]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #35856 - phimuemue:master, r=brson
authorbors <bors@rust-lang.org>
Sat, 3 Sep 2016 04:02:41 +0000 (21:02 -0700)
committerGitHub <noreply@github.com>
Sat, 3 Sep 2016 04:02:41 +0000 (21:02 -0700)
Introduce max_by/min_by on iterators

See https://github.com/rust-lang/rfcs/issues/1722 for reference.

It seems that there is `min`, `max` (simple computation of min/max), `min_by_key`, `max_by_key` (min/max by comparing mapped values) but no `min_by` and `max_by` (min/max according to comparison function). However, e.g. on vectors or slices there is `sort`, `sort_by_key` and `sort_by`.

962 files changed:
.travis.yml
CONTRIBUTING.md
README.md
RELEASES.md
configure
man/rustc.1
man/rustdoc.1
mk/cfg/mips-unknown-linux-uclibc.mk [new file with mode: 0644]
mk/cfg/mips64-unknown-linux-gnuabi64.mk [new file with mode: 0644]
mk/cfg/mips64el-unknown-linux-gnuabi64.mk [new file with mode: 0644]
mk/cfg/mipsel-unknown-linux-uclibc.mk [new file with mode: 0644]
mk/cfg/s390x-unknown-linux-gnu.mk [new file with mode: 0644]
mk/crates.mk
mk/docs.mk
mk/main.mk
mk/tests.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/mk/Makefile.in
src/bootstrap/native.rs
src/bootstrap/sanity.rs
src/bootstrap/step.rs
src/doc/book/borrow-and-asref.md
src/doc/book/closures.md
src/doc/book/compiler-plugins.md
src/doc/book/error-handling.md
src/doc/book/ffi.md
src/doc/book/macros.md
src/doc/book/traits.md
src/doc/reference.md
src/doc/style/README.md [deleted file]
src/doc/style/SUMMARY.md [deleted file]
src/doc/style/errors/README.md [deleted file]
src/doc/style/errors/ergonomics.md [deleted file]
src/doc/style/errors/handling.md [deleted file]
src/doc/style/errors/propagation.md [deleted file]
src/doc/style/errors/signaling.md [deleted file]
src/doc/style/features/README.md [deleted file]
src/doc/style/features/crates.md [deleted file]
src/doc/style/features/functions-and-methods/README.md [deleted file]
src/doc/style/features/functions-and-methods/convenience.md [deleted file]
src/doc/style/features/functions-and-methods/input.md [deleted file]
src/doc/style/features/functions-and-methods/output.md [deleted file]
src/doc/style/features/let.md [deleted file]
src/doc/style/features/loops.md [deleted file]
src/doc/style/features/match.md [deleted file]
src/doc/style/features/modules.md [deleted file]
src/doc/style/features/traits/README.md [deleted file]
src/doc/style/features/traits/common.md [deleted file]
src/doc/style/features/traits/extensions.md [deleted file]
src/doc/style/features/traits/generics.md [deleted file]
src/doc/style/features/traits/objects.md [deleted file]
src/doc/style/features/traits/overloading.md [deleted file]
src/doc/style/features/traits/reuse.md [deleted file]
src/doc/style/features/types/README.md [deleted file]
src/doc/style/features/types/conversions.md [deleted file]
src/doc/style/features/types/newtype.md [deleted file]
src/doc/style/ownership/README.md [deleted file]
src/doc/style/ownership/builders.md [deleted file]
src/doc/style/ownership/cell-smart.md [deleted file]
src/doc/style/ownership/constructors.md [deleted file]
src/doc/style/ownership/destructors.md [deleted file]
src/doc/style/ownership/raii.md [deleted file]
src/doc/style/platform.md [deleted file]
src/doc/style/safety/README.md [deleted file]
src/doc/style/safety/lib-guarantees.md [deleted file]
src/doc/style/safety/unsafe.md [deleted file]
src/doc/style/style/README.md [deleted file]
src/doc/style/style/braces.md [deleted file]
src/doc/style/style/comments.md [deleted file]
src/doc/style/style/features.md [deleted file]
src/doc/style/style/imports.md [deleted file]
src/doc/style/style/naming/README.md [deleted file]
src/doc/style/style/naming/containers.md [deleted file]
src/doc/style/style/naming/conversions.md [deleted file]
src/doc/style/style/naming/iterators.md [deleted file]
src/doc/style/style/naming/ownership.md [deleted file]
src/doc/style/style/optional.md [deleted file]
src/doc/style/style/organization.md [deleted file]
src/doc/style/style/whitespace.md [deleted file]
src/doc/style/testing/README.md [deleted file]
src/doc/style/testing/unit.md [deleted file]
src/doc/style/todo.md [deleted file]
src/etc/CONFIGS.md
src/etc/debugger_pretty_printers_common.py
src/etc/gdb_rust_pretty_printing.py
src/etc/lldb_rust_formatters.py
src/liballoc/arc.rs
src/liballoc/boxed.rs
src/liballoc/lib.rs
src/liballoc/raw_vec.rs
src/liballoc/rc.rs
src/liballoc_jemalloc/lib.rs
src/liballoc_system/lib.rs
src/libcollections/binary_heap.rs
src/libcollections/borrow.rs
src/libcollections/btree/map.rs
src/libcollections/btree/set.rs
src/libcollections/enum_set.rs
src/libcollections/fmt.rs
src/libcollections/lib.rs
src/libcollections/linked_list.rs
src/libcollections/range.rs
src/libcollections/str.rs
src/libcollections/string.rs
src/libcollections/vec.rs
src/libcollections/vec_deque.rs
src/libcollectionstest/btree/set.rs
src/libcollectionstest/lib.rs
src/libcore/any.rs
src/libcore/array.rs
src/libcore/borrow.rs
src/libcore/cell.rs
src/libcore/char.rs
src/libcore/char_private.rs
src/libcore/clone.rs
src/libcore/cmp.rs
src/libcore/convert.rs
src/libcore/default.rs
src/libcore/fmt/builders.rs
src/libcore/fmt/mod.rs
src/libcore/fmt/num.rs
src/libcore/hash/mod.rs
src/libcore/hash/sip.rs
src/libcore/intrinsics.rs
src/libcore/iter/iterator.rs
src/libcore/iter/mod.rs
src/libcore/iter/range.rs
src/libcore/iter/sources.rs
src/libcore/iter/traits.rs
src/libcore/iter_private.rs
src/libcore/lib.rs
src/libcore/macros.rs
src/libcore/marker.rs
src/libcore/mem.rs
src/libcore/nonzero.rs
src/libcore/num/bignum.rs
src/libcore/num/dec2flt/algorithm.rs
src/libcore/num/dec2flt/mod.rs
src/libcore/num/dec2flt/num.rs
src/libcore/num/dec2flt/parse.rs
src/libcore/num/dec2flt/rawfp.rs
src/libcore/num/flt2dec/decoder.rs
src/libcore/num/flt2dec/mod.rs
src/libcore/num/flt2dec/strategy/dragon.rs
src/libcore/num/flt2dec/strategy/grisu.rs
src/libcore/num/mod.rs
src/libcore/ops.rs
src/libcore/option.rs
src/libcore/ptr.rs
src/libcore/result.rs
src/libcore/slice.rs
src/libcore/str/mod.rs
src/libcore/str/pattern.rs
src/libcore/sync/atomic.rs
src/libcore/tuple.rs
src/libcoretest/cell.rs
src/libcoretest/char.rs
src/libcoretest/lib.rs
src/libcoretest/ptr.rs
src/liblibc
src/libpanic_unwind/gcc.rs
src/libpanic_unwind/seh64_gnu.rs
src/librbml/lib.rs
src/librbml/opaque.rs
src/librustc/dep_graph/dep_node.rs
src/librustc/diagnostics.rs
src/librustc/hir/check_attr.rs
src/librustc/hir/fold.rs
src/librustc/hir/intravisit.rs
src/librustc/hir/lowering.rs
src/librustc/hir/map/blocks.rs
src/librustc/hir/map/collector.rs
src/librustc/hir/map/def_collector.rs
src/librustc/hir/map/mod.rs
src/librustc/hir/mod.rs
src/librustc/hir/print.rs
src/librustc/hir/svh.rs
src/librustc/infer/bivariate.rs
src/librustc/infer/combine.rs
src/librustc/infer/equate.rs
src/librustc/infer/error_reporting.rs
src/librustc/infer/freshen.rs
src/librustc/infer/glb.rs
src/librustc/infer/higher_ranked/mod.rs
src/librustc/infer/lub.rs
src/librustc/infer/mod.rs
src/librustc/infer/region_inference/graphviz.rs
src/librustc/infer/region_inference/mod.rs
src/librustc/infer/resolve.rs
src/librustc/infer/sub.rs
src/librustc/lib.rs
src/librustc/lint/builtin.rs
src/librustc/lint/context.rs
src/librustc/lint/mod.rs
src/librustc/middle/cstore.rs
src/librustc/middle/dead.rs
src/librustc/middle/effect.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/free_region.rs
src/librustc/middle/lang_items.rs
src/librustc/middle/liveness.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/privacy.rs
src/librustc/middle/reachable.rs
src/librustc/middle/recursion_limit.rs
src/librustc/middle/region.rs
src/librustc/middle/resolve_lifetime.rs
src/librustc/middle/stability.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/traits/error_reporting.rs
src/librustc/traits/fulfill.rs
src/librustc/traits/object_safety.rs
src/librustc/traits/select.rs
src/librustc/traits/specialize/mod.rs
src/librustc/traits/util.rs
src/librustc/ty/_match.rs
src/librustc/ty/context.rs
src/librustc/ty/error.rs
src/librustc/ty/flags.rs
src/librustc/ty/fold.rs
src/librustc/ty/item_path.rs
src/librustc/ty/layout.rs
src/librustc/ty/maps.rs
src/librustc/ty/mod.rs
src/librustc/ty/outlives.rs
src/librustc/ty/relate.rs
src/librustc/ty/structural_impls.rs
src/librustc/ty/sty.rs
src/librustc/ty/subst.rs
src/librustc/ty/util.rs
src/librustc/ty/walk.rs
src/librustc/ty/wf.rs
src/librustc/util/fs.rs
src/librustc/util/ppaux.rs
src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs
src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs [new file with mode: 0644]
src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs [new file with mode: 0644]
src/librustc_back/target/mips_unknown_linux_uclibc.rs [new file with mode: 0644]
src/librustc_back/target/mipsel_unknown_linux_uclibc.rs [new file with mode: 0644]
src/librustc_back/target/mod.rs
src/librustc_back/target/s390x_unknown_linux_gnu.rs [new file with mode: 0644]
src/librustc_borrowck/borrowck/check_loans.rs
src/librustc_borrowck/borrowck/fragments.rs
src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
src/librustc_borrowck/borrowck/gather_loans/mod.rs
src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
src/librustc_borrowck/borrowck/mir/dataflow/impls.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_borrowck/borrowck/mod.rs
src/librustc_const_eval/check_match.rs
src/librustc_data_structures/flock.rs [new file with mode: 0644]
src/librustc_data_structures/lib.rs
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_driver/pretty.rs
src/librustc_driver/test.rs
src/librustc_errors/emitter.rs
src/librustc_errors/lib.rs
src/librustc_errors/lock.rs [new file with mode: 0644]
src/librustc_incremental/assert_dep_graph.rs
src/librustc_incremental/calculate_svh/def_path_hash.rs [new file with mode: 0644]
src/librustc_incremental/calculate_svh/mod.rs
src/librustc_incremental/calculate_svh/svh_visitor.rs
src/librustc_incremental/lib.rs
src/librustc_incremental/persist/dirty_clean.rs
src/librustc_incremental/persist/fs.rs [new file with mode: 0644]
src/librustc_incremental/persist/hash.rs
src/librustc_incremental/persist/load.rs
src/librustc_incremental/persist/mod.rs
src/librustc_incremental/persist/preds.rs
src/librustc_incremental/persist/save.rs
src/librustc_incremental/persist/util.rs [deleted file]
src/librustc_incremental/persist/work_product.rs
src/librustc_lint/bad_style.rs
src/librustc_lint/builtin.rs
src/librustc_lint/lib.rs
src/librustc_lint/types.rs
src/librustc_lint/unused.rs
src/librustc_llvm/build.rs
src/librustc_llvm/ffi.rs
src/librustc_llvm/lib.rs
src/librustc_metadata/astencode.rs
src/librustc_metadata/common.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/csearch.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/diagnostics.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/index_builder.rs [new file with mode: 0644]
src/librustc_metadata/lib.rs
src/librustc_metadata/loader.rs
src/librustc_metadata/macro_import.rs
src/librustc_metadata/tydecode.rs
src/librustc_metadata/tyencode.rs
src/librustc_mir/build/cfg.rs
src/librustc_mir/build/matches/mod.rs
src/librustc_mir/build/matches/test.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/build/scope.rs
src/librustc_mir/diagnostics.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/cx/mod.rs
src/librustc_mir/hair/cx/pattern.rs
src/librustc_mir/hair/mod.rs
src/librustc_mir/pretty.rs
src/librustc_mir/transform/no_landing_pads.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/diagnostics.rs
src/librustc_passes/rvalues.rs
src/librustc_passes/static_recursion.rs
src/librustc_plugin/lib.rs
src/librustc_plugin/load.rs
src/librustc_plugin/registry.rs
src/librustc_privacy/lib.rs
src/librustc_resolve/assign_ids.rs
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/check_unused.rs
src/librustc_resolve/diagnostics.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/resolve_imports.rs
src/librustc_save_analysis/dump_visitor.rs
src/librustc_trans/_match.rs [deleted file]
src/librustc_trans/abi.rs
src/librustc_trans/adt.rs
src/librustc_trans/asm.rs
src/librustc_trans/assert_module_sources.rs
src/librustc_trans/back/link.rs
src/librustc_trans/back/linker.rs
src/librustc_trans/back/symbol_names.rs
src/librustc_trans/back/write.rs
src/librustc_trans/base.rs
src/librustc_trans/cabi_mips64.rs [new file with mode: 0644]
src/librustc_trans/cabi_powerpc.rs
src/librustc_trans/callee.rs
src/librustc_trans/cleanup.rs
src/librustc_trans/closure.rs
src/librustc_trans/collector.rs
src/librustc_trans/common.rs
src/librustc_trans/consts.rs
src/librustc_trans/context.rs
src/librustc_trans/controlflow.rs [deleted file]
src/librustc_trans/datum.rs [deleted file]
src/librustc_trans/debuginfo/create_scope_map.rs
src/librustc_trans/debuginfo/metadata.rs
src/librustc_trans/debuginfo/mod.rs
src/librustc_trans/debuginfo/source_loc.rs
src/librustc_trans/debuginfo/type_names.rs
src/librustc_trans/debuginfo/utils.rs
src/librustc_trans/diagnostics.rs
src/librustc_trans/expr.rs [deleted file]
src/librustc_trans/glue.rs
src/librustc_trans/inline.rs [deleted file]
src/librustc_trans/intrinsic.rs
src/librustc_trans/lib.rs
src/librustc_trans/meth.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/rvalue.rs
src/librustc_trans/monomorphize.rs
src/librustc_trans/partitioning.rs
src/librustc_trans/symbol_names_test.rs
src/librustc_trans/trans_item.rs
src/librustc_trans/tvec.rs
src/librustc_trans/type_of.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/autoderef.rs
src/librustc_typeck/check/callee.rs
src/librustc_typeck/check/cast.rs
src/librustc_typeck/check/closure.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/compare_method.rs
src/librustc_typeck/check/dropck.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/check/method/probe.rs
src/librustc_typeck/check/method/suggest.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/regionck.rs
src/librustc_typeck/check/upvar.rs
src/librustc_typeck/check/wfcheck.rs
src/librustc_typeck/check/writeback.rs
src/librustc_typeck/check_unused.rs
src/librustc_typeck/coherence/mod.rs
src/librustc_typeck/coherence/orphan.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/constrained_type_params.rs
src/librustc_typeck/diagnostics.rs
src/librustc_typeck/lib.rs
src/librustc_typeck/rscope.rs
src/librustc_typeck/variance/constraints.rs
src/librustc_typeck/variance/solve.rs
src/librustc_typeck/variance/terms.rs
src/librustc_unicode/char.rs
src/librustc_unicode/lib.rs
src/librustc_unicode/u_str.rs
src/librustdoc/Cargo.toml
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/core.rs
src/librustdoc/flock.rs [deleted file]
src/librustdoc/html/format.rs
src/librustdoc/html/item_type.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/main.js
src/librustdoc/lib.rs
src/librustdoc/test.rs
src/librustdoc/visit_ast.rs
src/libserialize/collection_impls.rs
src/libserialize/json.rs
src/libserialize/serialize.rs
src/libstd/ascii.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/error.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/cursor.rs
src/libstd/io/error.rs
src/libstd/io/impls.rs
src/libstd/io/lazy.rs
src/libstd/io/mod.rs
src/libstd/io/stdio.rs
src/libstd/io/util.rs
src/libstd/lib.rs
src/libstd/memchr.rs
src/libstd/net/addr.rs
src/libstd/net/ip.rs
src/libstd/net/mod.rs
src/libstd/net/parser.rs
src/libstd/net/tcp.rs
src/libstd/net/test.rs
src/libstd/net/udp.rs
src/libstd/num/mod.rs
src/libstd/os/linux/raw.rs
src/libstd/panic.rs
src/libstd/panicking.rs
src/libstd/path.rs
src/libstd/primitive_docs.rs
src/libstd/process.rs
src/libstd/rt.rs
src/libstd/sync/barrier.rs
src/libstd/sync/condvar.rs
src/libstd/sync/mpsc/blocking.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/mpsc/sync.rs
src/libstd/sync/mutex.rs
src/libstd/sync/once.rs
src/libstd/sync/rwlock.rs
src/libstd/sys/common/args.rs
src/libstd/sys/common/at_exit_imp.rs
src/libstd/sys/common/backtrace.rs
src/libstd/sys/common/condvar.rs
src/libstd/sys/common/io.rs
src/libstd/sys/common/mod.rs
src/libstd/sys/common/mutex.rs
src/libstd/sys/common/net.rs
src/libstd/sys/common/remutex.rs
src/libstd/sys/common/thread.rs
src/libstd/sys/common/thread_info.rs
src/libstd/sys/common/thread_local.rs
src/libstd/sys/common/wtf8.rs
src/libstd/sys/unix/condvar.rs
src/libstd/sys/unix/ext/ffi.rs
src/libstd/sys/unix/ext/net.rs
src/libstd/sys/unix/ext/process.rs
src/libstd/sys/unix/fd.rs
src/libstd/sys/unix/fs.rs
src/libstd/sys/unix/net.rs
src/libstd/sys/unix/os.rs
src/libstd/sys/unix/os_str.rs
src/libstd/sys/unix/pipe.rs
src/libstd/sys/unix/process.rs
src/libstd/sys/unix/rand.rs
src/libstd/sys/unix/rwlock.rs
src/libstd/sys/unix/stdio.rs
src/libstd/sys/unix/thread.rs
src/libstd/sys/windows/compat.rs
src/libstd/sys/windows/condvar.rs
src/libstd/sys/windows/dynamic_lib.rs
src/libstd/sys/windows/ext/process.rs
src/libstd/sys/windows/fs.rs
src/libstd/sys/windows/handle.rs
src/libstd/sys/windows/mod.rs
src/libstd/sys/windows/mutex.rs
src/libstd/sys/windows/net.rs
src/libstd/sys/windows/os.rs
src/libstd/sys/windows/os_str.rs
src/libstd/sys/windows/pipe.rs
src/libstd/sys/windows/process.rs
src/libstd/sys/windows/stdio.rs
src/libstd/sys/windows/thread.rs
src/libstd/sys/windows/thread_local.rs
src/libstd/thread/local.rs
src/libstd/thread/mod.rs
src/libsyntax/abi.rs
src/libsyntax/ast.rs
src/libsyntax/attr.rs
src/libsyntax/config.rs
src/libsyntax/diagnostic_list.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/build.rs
src/libsyntax/ext/expand.rs
src/libsyntax/feature_gate.rs
src/libsyntax/fold.rs
src/libsyntax/lib.rs
src/libsyntax/parse/attr.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/libsyntax/ptr.rs
src/libsyntax/test.rs
src/libsyntax/visit.rs
src/libsyntax_ext/deriving/bounds.rs
src/libsyntax_ext/deriving/clone.rs
src/libsyntax_ext/deriving/cmp/eq.rs
src/libsyntax_ext/deriving/cmp/ord.rs
src/libsyntax_ext/deriving/cmp/partial_eq.rs
src/libsyntax_ext/deriving/cmp/partial_ord.rs
src/libsyntax_ext/deriving/debug.rs
src/libsyntax_ext/deriving/decodable.rs
src/libsyntax_ext/deriving/default.rs
src/libsyntax_ext/deriving/encodable.rs
src/libsyntax_ext/deriving/generic/mod.rs
src/libsyntax_ext/deriving/generic/ty.rs
src/libsyntax_ext/deriving/hash.rs
src/libsyntax_ext/deriving/mod.rs
src/libsyntax_pos/lib.rs
src/libtest/lib.rs
src/libunwind/libunwind.rs
src/llvm
src/rust-installer
src/rustc/Cargo.lock
src/rustc/std_shim/Cargo.lock
src/rustllvm/PassWrapper.cpp
src/rustllvm/RustWrapper.cpp
src/rustllvm/llvm-auto-clean-trigger
src/stage0.txt
src/test/codegen/abi-sysv64.rs [new file with mode: 0644]
src/test/codegen/adjustments.rs
src/test/codegen/coercions.rs
src/test/codegen/consts.rs
src/test/codegen/drop.rs
src/test/codegen/loads.rs
src/test/codegen/mir_zst_stores.rs
src/test/codegen/naked-functions.rs
src/test/codegen/refs.rs
src/test/codegen/stores.rs
src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs
src/test/compile-fail-fulldeps/lint-plugin-forbid-attrs.rs
src/test/compile-fail/E0009.rs
src/test/compile-fail/E0017.rs
src/test/compile-fail/E0033.rs
src/test/compile-fail/E0034.rs
src/test/compile-fail/E0040.rs
src/test/compile-fail/E0053.rs
src/test/compile-fail/E0076.rs
src/test/compile-fail/E0084.rs
src/test/compile-fail/E0087.rs
src/test/compile-fail/E0089.rs
src/test/compile-fail/E0093.rs
src/test/compile-fail/E0132.rs
src/test/compile-fail/E0133.rs
src/test/compile-fail/E0164.rs
src/test/compile-fail/E0165.rs
src/test/compile-fail/E0184.rs
src/test/compile-fail/E0194.rs
src/test/compile-fail/E0195.rs
src/test/compile-fail/E0221.rs
src/test/compile-fail/E0232.rs
src/test/compile-fail/E0259.rs
src/test/compile-fail/E0260.rs
src/test/compile-fail/E0277.rs
src/test/compile-fail/E0389.rs
src/test/compile-fail/E0393.rs
src/test/compile-fail/E0395.rs
src/test/compile-fail/E0396.rs
src/test/compile-fail/E0403.rs
src/test/compile-fail/E0407.rs
src/test/compile-fail/E0423.rs [new file with mode: 0644]
src/test/compile-fail/E0424.rs [new file with mode: 0644]
src/test/compile-fail/E0425.rs [new file with mode: 0644]
src/test/compile-fail/E0426.rs [new file with mode: 0644]
src/test/compile-fail/E0428.rs [new file with mode: 0644]
src/test/compile-fail/E0429.rs [new file with mode: 0644]
src/test/compile-fail/E0430.rs [new file with mode: 0644]
src/test/compile-fail/E0431.rs [new file with mode: 0644]
src/test/compile-fail/E0432.rs [new file with mode: 0644]
src/test/compile-fail/E0433.rs [new file with mode: 0644]
src/test/compile-fail/E0434.rs [new file with mode: 0644]
src/test/compile-fail/E0435.rs [new file with mode: 0644]
src/test/compile-fail/E0437.rs [new file with mode: 0644]
src/test/compile-fail/E0438.rs [new file with mode: 0644]
src/test/compile-fail/E0439.rs [new file with mode: 0644]
src/test/compile-fail/E0440.rs [new file with mode: 0644]
src/test/compile-fail/E0441.rs [new file with mode: 0644]
src/test/compile-fail/E0442.rs [new file with mode: 0644]
src/test/compile-fail/E0443.rs [new file with mode: 0644]
src/test/compile-fail/E0444.rs [new file with mode: 0644]
src/test/compile-fail/E0445.rs [new file with mode: 0644]
src/test/compile-fail/E0446.rs [new file with mode: 0644]
src/test/compile-fail/E0449.rs [new file with mode: 0644]
src/test/compile-fail/E0450.rs [new file with mode: 0644]
src/test/compile-fail/E0451.rs [new file with mode: 0644]
src/test/compile-fail/E0452.rs [new file with mode: 0644]
src/test/compile-fail/E0453.rs [new file with mode: 0644]
src/test/compile-fail/E0454.rs [new file with mode: 0644]
src/test/compile-fail/E0458.rs [new file with mode: 0644]
src/test/compile-fail/E0459.rs [new file with mode: 0644]
src/test/compile-fail/E0463.rs [new file with mode: 0644]
src/test/compile-fail/E0478.rs [new file with mode: 0644]
src/test/compile-fail/E0492.rs [new file with mode: 0644]
src/test/compile-fail/E0493.rs [new file with mode: 0644]
src/test/compile-fail/E0494.rs [new file with mode: 0644]
src/test/compile-fail/E0496.rs [new file with mode: 0644]
src/test/compile-fail/E0499.rs [new file with mode: 0644]
src/test/compile-fail/E0501.rs [new file with mode: 0644]
src/test/compile-fail/E0502.rs [new file with mode: 0644]
src/test/compile-fail/E0503.rs [new file with mode: 0644]
src/test/compile-fail/E0504.rs [new file with mode: 0644]
src/test/compile-fail/E0505.rs [new file with mode: 0644]
src/test/compile-fail/E0506.rs [new file with mode: 0644]
src/test/compile-fail/E0507.rs [new file with mode: 0644]
src/test/compile-fail/E0508.rs [new file with mode: 0644]
src/test/compile-fail/E0509.rs [new file with mode: 0644]
src/test/compile-fail/E0511.rs [new file with mode: 0644]
src/test/compile-fail/E0512.rs [new file with mode: 0644]
src/test/compile-fail/E0516.rs [new file with mode: 0644]
src/test/compile-fail/E0517.rs [new file with mode: 0644]
src/test/compile-fail/E0518.rs [new file with mode: 0644]
src/test/compile-fail/E0520.rs [new file with mode: 0644]
src/test/compile-fail/E0522.rs [new file with mode: 0644]
src/test/compile-fail/E0527.rs [new file with mode: 0644]
src/test/compile-fail/E0528.rs [new file with mode: 0644]
src/test/compile-fail/E0529.rs [new file with mode: 0644]
src/test/compile-fail/E0530.rs [new file with mode: 0644]
src/test/compile-fail/E0534.rs [new file with mode: 0644]
src/test/compile-fail/E0535.rs [new file with mode: 0644]
src/test/compile-fail/E0536.rs [new file with mode: 0644]
src/test/compile-fail/E0537.rs [new file with mode: 0644]
src/test/compile-fail/E0558.rs [new file with mode: 0644]
src/test/compile-fail/E0559.rs [new file with mode: 0644]
src/test/compile-fail/E0565-1.rs [new file with mode: 0644]
src/test/compile-fail/E0565.rs [new file with mode: 0644]
src/test/compile-fail/E560.rs [new file with mode: 0644]
src/test/compile-fail/associated-const-impl-wrong-type.rs
src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs
src/test/compile-fail/attr-literals.rs [new file with mode: 0644]
src/test/compile-fail/bad-format-args.rs [deleted file]
src/test/compile-fail/bad-module.rs
src/test/compile-fail/bad-sized.rs
src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs
src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs
src/test/compile-fail/borrowck/borrowck-let-suggestion.rs [deleted file]
src/test/compile-fail/cast-rfc0401.rs
src/test/compile-fail/coerce-mut.rs
src/test/compile-fail/conflicting-repr-hints.rs [new file with mode: 0644]
src/test/compile-fail/const-deref-ptr.rs
src/test/compile-fail/const-fn-mismatch.rs
src/test/compile-fail/const-fn-not-in-trait.rs
src/test/compile-fail/const-unsized.rs
src/test/compile-fail/diverging-fn-tail-35849.rs [new file with mode: 0644]
src/test/compile-fail/enable-orbit-for-incr-comp.rs [deleted file]
src/test/compile-fail/enum-and-module-in-same-scope.rs
src/test/compile-fail/feature-gate-abi-sysv64.rs [new file with mode: 0644]
src/test/compile-fail/fn-variance-1.rs
src/test/compile-fail/gated-attr-literals.rs [new file with mode: 0644]
src/test/compile-fail/impl-trait/auto-trait-leak.rs
src/test/compile-fail/impl-trait/loan-extend.rs
src/test/compile-fail/impl-wrong-item-for-trait.rs
src/test/compile-fail/import-from-missing.rs
src/test/compile-fail/import.rs
src/test/compile-fail/import2.rs
src/test/compile-fail/imports/duplicate.rs [new file with mode: 0644]
src/test/compile-fail/imports/reexports.rs [new file with mode: 0644]
src/test/compile-fail/issue-11004.rs [new file with mode: 0644]
src/test/compile-fail/issue-11925.rs [deleted file]
src/test/compile-fail/issue-12612.rs
src/test/compile-fail/issue-13404.rs
src/test/compile-fail/issue-16048.rs
src/test/compile-fail/issue-1697.rs
src/test/compile-fail/issue-18252.rs
src/test/compile-fail/issue-19452.rs
src/test/compile-fail/issue-20433.rs [new file with mode: 0644]
src/test/compile-fail/issue-21546.rs
src/test/compile-fail/issue-21950.rs
src/test/compile-fail/issue-22370.rs
src/test/compile-fail/issue-22560.rs
src/test/compile-fail/issue-23302.rs
src/test/compile-fail/issue-2356.rs
src/test/compile-fail/issue-24204.rs [new file with mode: 0644]
src/test/compile-fail/issue-25793.rs
src/test/compile-fail/issue-25826.rs
src/test/compile-fail/issue-28308.rs [deleted file]
src/test/compile-fail/issue-28324.rs [new file with mode: 0644]
src/test/compile-fail/issue-28625.rs [new file with mode: 0644]
src/test/compile-fail/issue-28776.rs
src/test/compile-fail/issue-2937.rs
src/test/compile-fail/issue-30007.rs
src/test/compile-fail/issue-30560.rs
src/test/compile-fail/issue-32833.rs
src/test/compile-fail/issue-32950.rs
src/test/compile-fail/issue-32963.rs
src/test/compile-fail/issue-35869.rs [new file with mode: 0644]
src/test/compile-fail/issue-5035.rs
src/test/compile-fail/issue-8208.rs
src/test/compile-fail/lint-forbid-attr.rs
src/test/compile-fail/lint-no-drop-on-repr-extern.rs [deleted file]
src/test/compile-fail/macro-backtrace-invalid-internals.rs [deleted file]
src/test/compile-fail/macro-backtrace-nested.rs [deleted file]
src/test/compile-fail/macro-backtrace-println.rs [deleted file]
src/test/compile-fail/macro-context.rs
src/test/compile-fail/macro-error.rs
src/test/compile-fail/missing-block-hint.rs [new file with mode: 0644]
src/test/compile-fail/mut-pattern-mismatched.rs
src/test/compile-fail/on-unimplemented/multiple-impls.rs
src/test/compile-fail/on-unimplemented/on-impl.rs
src/test/compile-fail/on-unimplemented/on-trait.rs
src/test/compile-fail/on-unimplemented/slice-index.rs
src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs
src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs
src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs
src/test/compile-fail/privacy2.rs
src/test/compile-fail/privacy3.rs
src/test/compile-fail/ptr-coercion.rs
src/test/compile-fail/question-mark-type-infer.rs [new file with mode: 0644]
src/test/compile-fail/region-borrow-params-issue-29793-small.rs
src/test/compile-fail/regions-escape-loop-via-vec.rs
src/test/compile-fail/regions-in-consts.rs [deleted file]
src/test/compile-fail/resolve_self_super_hint.rs
src/test/compile-fail/rfc1592-deprecated.rs [deleted file]
src/test/compile-fail/rfc1623.rs [new file with mode: 0644]
src/test/compile-fail/rfc1623.rs.bk [new file with mode: 0644]
src/test/compile-fail/send-is-not-static-ensures-scoping.rs
src/test/compile-fail/slice-mut.rs
src/test/compile-fail/super-at-top-level.rs
src/test/compile-fail/syntax-extension-minor.rs
src/test/compile-fail/task-rng-isnt-sendable.rs
src/test/compile-fail/trait-duplicate-methods.rs
src/test/compile-fail/trait-safety-fn-body.rs
src/test/compile-fail/trait-suggest-where-clause.rs
src/test/compile-fail/type-macros-fail.rs [deleted file]
src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs
src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs
src/test/compile-fail/unresolved-import.rs
src/test/compile-fail/unsafe-const-fn.rs
src/test/compile-fail/unsafe_no_drop_flag-gate.rs [deleted file]
src/test/compile-fail/unsized6.rs
src/test/compile-fail/use-from-trait-xc.rs
src/test/compile-fail/use-from-trait.rs
src/test/compile-fail/use-keyword.rs
src/test/compile-fail/use-mod-2.rs
src/test/compile-fail/variance-associated-types.rs
src/test/compile-fail/variance-object-types.rs
src/test/compile-fail/variance-region-bounds.rs
src/test/compile-fail/variance-regions-direct.rs
src/test/compile-fail/variance-regions-indirect.rs
src/test/compile-fail/variance-trait-bounds.rs
src/test/compile-fail/variance-trait-object-bound.rs
src/test/compile-fail/variance-types-bounds.rs
src/test/compile-fail/variance-types.rs
src/test/debuginfo/auxiliary/macro-stepping.rs [new file with mode: 0644]
src/test/debuginfo/lexical-scope-with-macro.rs
src/test/debuginfo/macro-stepping.rs [new file with mode: 0644]
src/test/incremental/crate_hash_reorder.rs [new file with mode: 0644]
src/test/incremental/issue-35593.rs [new file with mode: 0644]
src/test/incremental/string_constant.rs
src/test/parse-fail/doc-after-struct-field.rs [new file with mode: 0644]
src/test/parse-fail/doc-before-extern-rbrace.rs
src/test/parse-fail/doc-before-fn-rbrace.rs [new file with mode: 0644]
src/test/parse-fail/doc-before-identifier.rs [new file with mode: 0644]
src/test/parse-fail/doc-before-mod-rbrace.rs [new file with mode: 0644]
src/test/parse-fail/doc-before-rbrace.rs
src/test/parse-fail/doc-before-semi.rs
src/test/parse-fail/doc-before-struct-rbrace-1.rs [new file with mode: 0644]
src/test/parse-fail/doc-before-struct-rbrace-2.rs [new file with mode: 0644]
src/test/parse-fail/non-str-meta.rs [deleted file]
src/test/parse-fail/suffixed-literal-meta.rs [new file with mode: 0644]
src/test/pretty/attr-literals.rs [new file with mode: 0644]
src/test/run-fail-fulldeps/qquote.rs
src/test/run-fail/call-fn-never-arg.rs
src/test/run-fail/issue-30380.rs
src/test/run-fail/mir_drop_panics.rs
src/test/run-fail/mir_dynamic_drops_1.rs
src/test/run-fail/mir_dynamic_drops_2.rs
src/test/run-fail/mir_dynamic_drops_3.rs
src/test/run-fail/mir_indexing_oob_1.rs
src/test/run-fail/mir_indexing_oob_2.rs
src/test/run-fail/mir_indexing_oob_3.rs
src/test/run-fail/mir_trans_calls_converging_drops.rs
src/test/run-fail/mir_trans_calls_converging_drops_2.rs
src/test/run-fail/mir_trans_calls_diverging.rs
src/test/run-fail/mir_trans_calls_diverging_drops.rs
src/test/run-fail/mir_trans_no_landing_pads.rs
src/test/run-fail/mir_trans_no_landing_pads_diverging.rs
src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs
src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs
src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs
src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
src/test/run-pass-fulldeps/auxiliary/plugin_args.rs
src/test/run-pass-fulldeps/deprecated-derive.rs
src/test/run-pass-fulldeps/empty-struct-braces-derive.rs
src/test/run-pass-fulldeps/lint-group-plugin.rs
src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs
src/test/run-pass-fulldeps/lint-plugin.rs
src/test/run-pass-fulldeps/macro-crate-multi-decorator-literals.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/mir-pass.rs
src/test/run-pass-valgrind/cast-enum-with-dtor.rs
src/test/run-pass/abi-sysv64-arg-passing.rs [new file with mode: 0644]
src/test/run-pass/abi-sysv64-register-usage.rs [new file with mode: 0644]
src/test/run-pass/atomic-access-bool.rs [new file with mode: 0644]
src/test/run-pass/attr-before-view-item.rs
src/test/run-pass/attr-before-view-item2.rs
src/test/run-pass/attr-no-drop-flag-size.rs [deleted file]
src/test/run-pass/auxiliary/issue-10028.rs
src/test/run-pass/deriving-meta-empty-trait-list.rs
src/test/run-pass/diverging-fn-tail-35849.rs [new file with mode: 0644]
src/test/run-pass/drop-flag-sanity-check.rs [deleted file]
src/test/run-pass/drop-flag-skip-sanity-check.rs [deleted file]
src/test/run-pass/dynamic-drop.rs
src/test/run-pass/enum-size-variance.rs
src/test/run-pass/exhaustive-bool-match-sanity.rs
src/test/run-pass/fds-are-cloexec.rs
src/test/run-pass/imports.rs [new file with mode: 0644]
src/test/run-pass/intrinsic-move-val.rs
src/test/run-pass/issue-10734.rs
src/test/run-pass/issue-12033.rs [new file with mode: 0644]
src/test/run-pass/issue-14875.rs [new file with mode: 0644]
src/test/run-pass/issue-16648.rs
src/test/run-pass/issue-19100.rs
src/test/run-pass/issue-25757.rs
src/test/run-pass/issue-2611-3.rs
src/test/run-pass/issue-26251.rs [new file with mode: 0644]
src/test/run-pass/issue-27320.rs
src/test/run-pass/issue-2895.rs
src/test/run-pass/issue-28950.rs
src/test/run-pass/issue-32805.rs
src/test/run-pass/issue-33387.rs
src/test/run-pass/issue-33687.rs [new file with mode: 0644]
src/test/run-pass/issue-34053.rs [new file with mode: 0644]
src/test/run-pass/issue-35423.rs [new file with mode: 0644]
src/test/run-pass/issue-35815.rs [new file with mode: 0644]
src/test/run-pass/issue-36023.rs [new file with mode: 0644]
src/test/run-pass/issue-36139-normalize-closure-sig.rs [new file with mode: 0644]
src/test/run-pass/issue-7784.rs
src/test/run-pass/liveness-assign-imm-local-after-ret.rs
src/test/run-pass/match-vec-alternatives.rs
src/test/run-pass/mir_adt_construction.rs
src/test/run-pass/mir_ascription_coercion.rs
src/test/run-pass/mir_augmented_assignments.rs
src/test/run-pass/mir_autoderef.rs
src/test/run-pass/mir_boxing.rs
src/test/run-pass/mir_build_match_comparisons.rs
src/test/run-pass/mir_call_with_associated_type.rs
src/test/run-pass/mir_cast_fn_ret.rs
src/test/run-pass/mir_coercion_casts.rs
src/test/run-pass/mir_coercions.rs
src/test/run-pass/mir_constval_adts.rs
src/test/run-pass/mir_cross_crate.rs [deleted file]
src/test/run-pass/mir_early_return_scope.rs [new file with mode: 0644]
src/test/run-pass/mir_fat_ptr.rs
src/test/run-pass/mir_fat_ptr_drop.rs
src/test/run-pass/mir_heavy_promoted.rs [new file with mode: 0644]
src/test/run-pass/mir_match_arm_guard.rs
src/test/run-pass/mir_misc_casts.rs
src/test/run-pass/mir_overflow_off.rs
src/test/run-pass/mir_raw_fat_ptr.rs
src/test/run-pass/mir_refs_correct.rs
src/test/run-pass/mir_small_agg_arg.rs
src/test/run-pass/mir_struct_with_assoc_ty.rs
src/test/run-pass/mir_temp_promotions.rs
src/test/run-pass/mir_trans_array.rs
src/test/run-pass/mir_trans_array_2.rs
src/test/run-pass/mir_trans_call_converging.rs
src/test/run-pass/mir_trans_calls.rs
src/test/run-pass/mir_trans_calls_variadic.rs
src/test/run-pass/mir_trans_critical_edge.rs
src/test/run-pass/mir_trans_spike1.rs
src/test/run-pass/mir_trans_switch.rs
src/test/run-pass/mir_trans_switchint.rs
src/test/run-pass/mir_void_return.rs
src/test/run-pass/mir_void_return_2.rs
src/test/run-pass/no-drop-flag-size.rs [new file with mode: 0644]
src/test/run-pass/rfc1592-deprecated.rs [deleted file]
src/test/run-pass/rfc1623.rs [new file with mode: 0644]
src/test/run-pass/rfc1623.rs.bk [new file with mode: 0644]
src/test/run-pass/signal-exit-status.rs
src/test/run-pass/simd-intrinsic-generic-cast.rs
src/test/run-pass/try-operator-custom.rs [new file with mode: 0644]
src/test/run-pass/type-macros-hlist.rs
src/test/run-pass/type-macros-simple.rs
src/test/run-pass/unreachable-code-1.rs
src/test/run-pass/vec-matching-fold.rs
src/test/run-pass/vec-matching-legal-tail-element-borrow.rs
src/test/run-pass/vec-matching.rs
src/test/run-pass/vec-tail-matching.rs
src/test/run-pass/zero-size-type-destructors.rs
src/test/run-pass/zero_sized_subslice_match.rs
src/test/rustdoc/issue-26606.rs
src/test/rustdoc/macros.rs
src/test/ui/codemap_tests/bad-format-args.rs [new file with mode: 0644]
src/test/ui/codemap_tests/bad-format-args.stderr [new file with mode: 0644]
src/test/ui/codemap_tests/issue-28308.rs [new file with mode: 0644]
src/test/ui/codemap_tests/issue-28308.stderr [new file with mode: 0644]
src/test/ui/codemap_tests/repair_span_std_macros.rs [new file with mode: 0644]
src/test/ui/codemap_tests/repair_span_std_macros.stderr [new file with mode: 0644]
src/test/ui/codemap_tests/unicode.stderr
src/test/ui/cross-crate-macro-backtrace/auxiliary/extern_macro_crate.rs [new file with mode: 0644]
src/test/ui/cross-crate-macro-backtrace/main.rs [new file with mode: 0644]
src/test/ui/cross-crate-macro-backtrace/main.stderr [new file with mode: 0644]
src/test/ui/lifetimes/borrowck-let-suggestion.rs [new file with mode: 0644]
src/test/ui/lifetimes/borrowck-let-suggestion.stderr [new file with mode: 0644]
src/test/ui/macros/bad_hello.rs [new file with mode: 0644]
src/test/ui/macros/bad_hello.stderr [new file with mode: 0644]
src/test/ui/macros/macro-backtrace-invalid-internals.rs [new file with mode: 0644]
src/test/ui/macros/macro-backtrace-invalid-internals.stderr [new file with mode: 0644]
src/test/ui/macros/macro-backtrace-nested.rs [new file with mode: 0644]
src/test/ui/macros/macro-backtrace-nested.stderr [new file with mode: 0644]
src/test/ui/macros/macro-backtrace-println.rs [new file with mode: 0644]
src/test/ui/macros/macro-backtrace-println.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/const-fn-in-trait.rs [new file with mode: 0644]
src/test/ui/mismatched_types/const-fn-in-trait.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/issue-26480.stderr
src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs [new file with mode: 0644]
src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr [new file with mode: 0644]
src/test/ui/span/issue-11925.rs [new file with mode: 0644]
src/test/ui/span/issue-11925.stderr [new file with mode: 0644]
src/tools/compiletest/Cargo.lock
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/linkchecker/Cargo.lock
src/tools/rustbook/build.rs
src/tools/tidy/src/bins.rs

index 0abd858d8228baaf5daa76454e4fa76185154f39..c5d8a94f39b052df9b2a497047f55549c5c8a833 100644 (file)
@@ -15,9 +15,9 @@ before_install:
 script:
   - docker run -v `pwd`:/build rust
     sh -c "
-      ./configure --llvm-root=/usr/lib/llvm-3.7 &&
+      ./configure --enable-rustbuild --llvm-root=/usr/lib/llvm-3.7 &&
       make tidy &&
-      make check-notidy -j4
+      make check -j4
     "
 
 # Real testing happens on http://buildbot.rust-lang.org/
index 60935770781817a63c3ea9b6a19260ee33118b54..4e6cd6c9782a95872376db0ff294cd4f1d88523c 100644 (file)
@@ -230,7 +230,7 @@ To find documentation-related issues, sort by the [A-docs label][adocs].
 In many cases, you don't need a full `make doc`. You can use `rustdoc` directly
 to check small fixes. For example, `rustdoc src/doc/reference.md` will render
 reference to `doc/reference.html`. The CSS might be messed up, but you can
-verify that HTML is right.
+verify that the HTML is right.
 
 ## Issue Triage
 
index 283efdd2411564f962cdaf210c43eec37384a55a..dbe48a50cfa707a9cca532ed9659a72aff9326f3 100644 (file)
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ Read ["Installing Rust"] from [The Book].
    * `g++` 4.7 or later or `clang++` 3.x
    * `python` 2.7 (but not 3.x)
    * GNU `make` 3.81 or later
-   * `cmake` 2.8.8 or later
+   * `cmake` 3.4.3 or later
    * `curl`
    * `git`
 
index c798c56cd6d03f810d74976a66d2ab53b116c11c..8817d7f88a73801e64c16b5f127f6404ebfc9a1f 100644 (file)
@@ -1,3 +1,180 @@
+Version 1.11.0 (2016-08-18)
+===========================
+
+Language
+--------
+
+* [`cfg_attr` works on `path` attributes]
+  (https://github.com/rust-lang/rust/pull/34546)
+* [Support nested `cfg_attr` attributes]
+  (https://github.com/rust-lang/rust/pull/34216)
+* [Allow statement-generating braced macro invocations at the end of blocks]
+  (https://github.com/rust-lang/rust/pull/34436)
+* [Macros can be expanded inside of trait definitions]
+  (https://github.com/rust-lang/rust/pull/34213)
+* [`#[macro_use]` works properly when it is itself expanded from a macro]
+  (https://github.com/rust-lang/rust/pull/34032)
+
+Stabilized APIs
+---------------
+
+* [`BinaryHeap::append`]
+  (https://doc.rust-lang.org/std/collections/binary_heap/struct.BinaryHeap.html#method.append)
+* [`BTreeMap::append`]
+  (https://doc.rust-lang.org/std/collections/btree_map/struct.BTreeMap.html#method.append)
+* [`BTreeMap::split_off`]
+  (https://doc.rust-lang.org/std/collections/btree_map/struct.BTreeMap.html#method.split_off)
+* [`BTreeSet::append`]
+  (https://doc.rust-lang.org/std/collections/btree_set/struct.BTreeSet.html#method.append)
+* [`BTreeSet::split_off`]
+  (https://doc.rust-lang.org/std/collections/btree_set/struct.BTreeSet.html#method.split_off)
+* [`f32::to_degrees`]
+  (https://doc.rust-lang.org/std/primitive.f32.html#method.to_degrees)
+  (in libcore - previously stabilized in libstd)
+* [`f32::to_radians`]
+  (https://doc.rust-lang.org/std/primitive.f32.html#method.to_radians)
+  (in libcore - previously stabilized in libstd)
+* [`f64::to_degrees`]
+  (https://doc.rust-lang.org/std/primitive.f64.html#method.to_degrees)
+  (in libcore - previously stabilized in libstd)
+* [`f64::to_radians`]
+  (https://doc.rust-lang.org/std/primitive.f64.html#method.to_radians)
+  (in libcore - previously stabilized in libstd)
+* [`Iterator::sum`]
+  (https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum)
+* [`Iterator::product`]
+  (https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum)
+* [`Cell::get_mut`]
+  (https://doc.rust-lang.org/std/cell/struct.Cell.html#method.get_mut)
+* [`RefCell::get_mut`]
+  (https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.get_mut)
+
+Libraries
+---------
+
+* [The `thread_local!` macro supports multiple definitions in a single
+   invocation, and can apply attributes]
+  (https://github.com/rust-lang/rust/pull/34077)
+* [`Cow` implements `Default`]
+  (https://github.com/rust-lang/rust/pull/34305)
+* [`Wrapping` implements binary, octal, lower-hex and upper-hex
+  `Display` formatting]
+  (https://github.com/rust-lang/rust/pull/34190)
+* [The range types implement `Hash`]
+  (https://github.com/rust-lang/rust/pull/34180)
+* [`lookup_host` ignores unknown address types]
+  (https://github.com/rust-lang/rust/pull/34067)
+* [`assert_eq!` accepts a custom error message, like `assert!` does]
+  (https://github.com/rust-lang/rust/pull/33976)
+* [The main thread is now called "main" instead of "&lt;main&gt;"]
+  (https://github.com/rust-lang/rust/pull/33803)
+
+Cargo
+-----
+
+* [Disallow specifying features of transitive deps]
+  (https://github.com/rust-lang/cargo/pull/2821)
+* [Add color support for Windows consoles]
+  (https://github.com/rust-lang/cargo/pull/2804)
+* [Fix `harness = false` on `[lib]` sections]
+  (https://github.com/rust-lang/cargo/pull/2795)
+* [Don't panic when `links` contains a '.']
+  (https://github.com/rust-lang/cargo/pull/2787)
+* [Build scripts can emit warnings]
+  (https://github.com/rust-lang/cargo/pull/2630),
+  and `-vv` prints warnings for all crates.
+* [Ignore file locks on OS X NFS mounts]
+  (https://github.com/rust-lang/cargo/pull/2720)
+* [Don't warn about `package.metadata` keys]
+  (https://github.com/rust-lang/cargo/pull/2668).
+  This provides room for expansion by arbitrary tools.
+* [Add support for cdylib crate types]
+  (https://github.com/rust-lang/cargo/pull/2741)
+* [Prevent publishing crates when files are dirty]
+  (https://github.com/rust-lang/cargo/pull/2781)
+* [Don't fetch all crates on clean]
+  (https://github.com/rust-lang/cargo/pull/2704)
+* [Propagate --color option to rustc]
+  (https://github.com/rust-lang/cargo/pull/2779)
+* [Fix `cargo doc --open` on Windows]
+  (https://github.com/rust-lang/cargo/pull/2780)
+* [Improve autocompletion]
+  (https://github.com/rust-lang/cargo/pull/2772)
+* [Configure colors of stderr as well as stdout]
+  (https://github.com/rust-lang/cargo/pull/2739)
+
+Performance
+-----------
+
+* [Caching projections speeds up type check dramatically for some
+  workloads]
+  (https://github.com/rust-lang/rust/pull/33816)
+* [The default `HashMap` hasher is SipHash 1-3 instead of SipHash 2-4]
+  (https://github.com/rust-lang/rust/pull/33940)
+  This hasher is faster, but is believed to provide sufficient
+  protection from collision attacks.
+* [Comparison of `Ipv4Addr` is 10x faster]
+  (https://github.com/rust-lang/rust/pull/33891)
+
+Rustdoc
+-------
+
+* [Fix empty implementation section on some module pages]
+  (https://github.com/rust-lang/rust/pull/34536)
+* [Fix inlined renamed reexports in import lists]
+  (https://github.com/rust-lang/rust/pull/34479)
+* [Fix search result layout for enum variants and struct fields]
+  (https://github.com/rust-lang/rust/pull/34477)
+* [Fix issues with source links to external crates]
+  (https://github.com/rust-lang/rust/pull/34387)
+* [Fix redirect pages for renamed reexports]
+  (https://github.com/rust-lang/rust/pull/34245)
+
+Tooling
+-------
+
+* [rustc is better at finding the MSVC toolchain]
+  (https://github.com/rust-lang/rust/pull/34492)
+* [When emitting debug info, rustc emits frame pointers for closures,
+  shims and glue, as it does for all other functions]
+  (https://github.com/rust-lang/rust/pull/33909)
+* [rust-lldb warns about unsupported versions of LLDB]
+  (https://github.com/rust-lang/rust/pull/34646)
+* Many more errors have been given error codes and extended
+  explanations
+* API documentation continues to be improved, with many new examples
+
+Misc
+----
+
+* [rustc no longer hangs when dependencies recursively re-export
+  submodules]
+  (https://github.com/rust-lang/rust/pull/34542)
+* [rustc requires LLVM 3.7+]
+  (https://github.com/rust-lang/rust/pull/34104)
+* [The 'How Safe and Unsafe Interact' chapter of The Rustonomicon was
+  rewritten]
+  (https://github.com/rust-lang/rust/pull/33895)
+* [rustc support 16-bit pointer sizes]
+  (https://github.com/rust-lang/rust/pull/33460).
+  No targets use this yet, but it works toward AVR support.
+
+Compatibility Notes
+-------------------
+
+* [`const`s and `static`s may not have unsized types]
+  (https://github.com/rust-lang/rust/pull/34443)
+* [The new follow-set rules that place restrictions on `macro_rules!`
+  in order to ensure syntax forward-compatibility have been enabled]
+  (https://github.com/rust-lang/rust/pull/33982)
+  This was an [ammendment to RFC 550]
+  (https://github.com/rust-lang/rfcs/pull/1384),
+  and has been a warning since 1.10.
+* [`cfg` attribute process has been refactored to fix various bugs]
+  (https://github.com/rust-lang/rust/pull/33706).
+  This causes breakage in some corner cases.
+
+
 Version 1.10.0 (2016-07-07)
 ===========================
 
index 18dc99dd6c34c0a46106f403596b34084e8843b7..bcc1faea3b5d86f9c64d4380126de858cebd62c1 100755 (executable)
--- a/configure
+++ b/configure
@@ -360,6 +360,13 @@ abs_path() {
     (unset CDPATH && cd "$_path" > /dev/null && pwd)
 }
 
+HELP=0
+for arg; do
+    case "$arg" in
+        --help) HELP=1;;
+    esac
+done
+
 msg "looking for configure programs"
 need_cmd cmp
 need_cmd mkdir
@@ -566,11 +573,8 @@ esac
 
 
 OPTIONS=""
-HELP=0
-if [ "$1" = "--help" ]
+if [ "$HELP" -eq 1 ]
 then
-    HELP=1
-    shift
     echo
     echo "Usage: $CFG_SELF [options]"
     echo
@@ -733,8 +737,6 @@ if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTION
 if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi
 if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi
 
-if [ -n "$CFG_DISABLE_ORBIT" ]; then putvar CFG_DISABLE_ORBIT; fi
-
 step_msg "looking for build programs"
 
 probe_need CFG_CURL curl
@@ -1749,7 +1751,7 @@ do
         CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON"
     fi
 
-    CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC'"
+    CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ'"
     CMAKE_ARGS="$CMAKE_ARGS -G '$CFG_CMAKE_GENERATOR'"
     CMAKE_ARGS="$CMAKE_ARGS $CFG_LLVM_SRC_DIR"
 
index 0eaf89a560fb84a1defe2357d3bbeff71c1845a0..1656255956191f4d730519feedf75d82a2d02805 100644 (file)
@@ -1,4 +1,4 @@
-.TH RUSTC "1" "August 2016" "rustc 1.12.0" "User Commands"
+.TH RUSTC "1" "September 2016" "rustc 1.13.0" "User Commands"
 .SH NAME
 rustc \- The Rust compiler
 .SH SYNOPSIS
index 3fb5757f4ff24be21f2cac4ea3312fef2d257b23..4d885bd14363fc7eb233ae846cefe6fbcba2c957 100644 (file)
@@ -1,4 +1,4 @@
-.TH RUSTDOC "1" "August 2016" "rustdoc 1.12.0" "User Commands"
+.TH RUSTDOC "1" "September 2016" "rustdoc 1.13.0" "User Commands"
 .SH NAME
 rustdoc \- generate documentation from Rust source code
 .SH SYNOPSIS
diff --git a/mk/cfg/mips-unknown-linux-uclibc.mk b/mk/cfg/mips-unknown-linux-uclibc.mk
new file mode 100644 (file)
index 0000000..34aee77
--- /dev/null
@@ -0,0 +1 @@
+# rustbuild-only target
diff --git a/mk/cfg/mips64-unknown-linux-gnuabi64.mk b/mk/cfg/mips64-unknown-linux-gnuabi64.mk
new file mode 100644 (file)
index 0000000..34aee77
--- /dev/null
@@ -0,0 +1 @@
+# rustbuild-only target
diff --git a/mk/cfg/mips64el-unknown-linux-gnuabi64.mk b/mk/cfg/mips64el-unknown-linux-gnuabi64.mk
new file mode 100644 (file)
index 0000000..34aee77
--- /dev/null
@@ -0,0 +1 @@
+# rustbuild-only target
diff --git a/mk/cfg/mipsel-unknown-linux-uclibc.mk b/mk/cfg/mipsel-unknown-linux-uclibc.mk
new file mode 100644 (file)
index 0000000..34aee77
--- /dev/null
@@ -0,0 +1 @@
+# rustbuild-only target
diff --git a/mk/cfg/s390x-unknown-linux-gnu.mk b/mk/cfg/s390x-unknown-linux-gnu.mk
new file mode 100644 (file)
index 0000000..34aee77
--- /dev/null
@@ -0,0 +1 @@
+# rustbuild-only target
index 5ff6d7a89dbe0a4bdb2e91f8aa1684c08ac8305b..a915d07384f3cd712dc012af7e5684e1ddb61c92 100644 (file)
@@ -112,7 +112,7 @@ DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml \
              rustc_const_math syntax_pos rustc_errors
 DEPS_rustc_back := std syntax flate log libc
 DEPS_rustc_borrowck := rustc log graphviz syntax syntax_pos rustc_errors rustc_mir
-DEPS_rustc_data_structures := std log serialize
+DEPS_rustc_data_structures := std log serialize libc
 DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
                      rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
                      rustc_trans rustc_privacy rustc_lint rustc_plugin \
@@ -137,9 +137,8 @@ DEPS_rustc_save_analysis := rustc log syntax syntax_pos serialize
 DEPS_rustc_typeck := rustc syntax syntax_pos rustc_platform_intrinsics rustc_const_math \
                      rustc_const_eval rustc_errors
 
-DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
-                test rustc_lint rustc_const_eval syntax_pos
-
+DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts test \
+                rustc_lint rustc_const_eval syntax_pos rustc_data_structures
 
 TOOL_DEPS_compiletest := test getopts log serialize
 TOOL_DEPS_rustdoc := rustdoc
index f202c75360bf8f8c99c9f7cc35eb2cc32654546d..6c0be654e1f5d74a8e39b6f18f26896742fda9d1 100644 (file)
@@ -66,7 +66,7 @@ ERR_IDX_GEN_MD = $(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(ERR_IDX_GEN_EXE)
 
 D := $(S)src/doc
 
-DOC_TARGETS := book nomicon style error-index
+DOC_TARGETS := book nomicon error-index
 COMPILER_DOC_TARGETS :=
 DOC_L10N_TARGETS :=
 
@@ -209,13 +209,6 @@ doc/nomicon/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/nomicon/*.md) |
        $(Q)rm -rf doc/nomicon
        $(Q)$(RUSTBOOK) build $(S)src/doc/nomicon doc/nomicon
 
-style: doc/style/index.html
-
-doc/style/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/style/*.md) | doc/
-       @$(call E, rustbook: $@)
-       $(Q)rm -rf doc/style
-       $(Q)$(RUSTBOOK) build $(S)src/doc/style doc/style
-
 error-index: doc/error-index.html
 
 # Metadata used to generate the index is created as a side effect of
index 1725143325c61207ad54d1becf2a11521d2f8243..6130b581387515af42c59a2ca4f8d31302b1c016 100644 (file)
@@ -162,12 +162,6 @@ ifdef CFG_ENABLE_DEBUGINFO
   CFG_RUSTC_FLAGS += -g
 endif
 
-ifdef CFG_DISABLE_ORBIT
-  $(info cfg: HOLD HOLD HOLD (CFG_DISABLE_ORBIT))
-  RUSTFLAGS_STAGE1 += -Z orbit=off
-  RUSTFLAGS_STAGE2 += -Z orbit=off
-endif
-
 ifdef SAVE_TEMPS
   CFG_RUSTC_FLAGS += -C save-temps
 endif
@@ -306,7 +300,7 @@ endif
 # LLVM macros
 ######################################################################
 
-LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl
+LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz
 LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \
                 interpreter instrumentation
 
@@ -354,6 +348,7 @@ LLVM_AS_$(1)=$$(CFG_LLVM_INST_DIR_$(1))/bin/llvm-as$$(X_$(1))
 LLC_$(1)=$$(CFG_LLVM_INST_DIR_$(1))/bin/llc$$(X_$(1))
 
 LLVM_ALL_COMPONENTS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --components)
+LLVM_VERSION_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --version)
 
 endef
 
index 201e4cae51d6d9a4e293d2eedfa276f477991cd3..c135aa9b8fb956cd9b186af8736ff1d83597ac72 100644 (file)
@@ -649,6 +649,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) = \
        --lldb-python $$(CFG_LLDB_PYTHON) \
         --gdb-version="$(CFG_GDB_VERSION)" \
         --lldb-version="$(CFG_LLDB_VERSION)" \
+        --llvm-version="$$(LLVM_VERSION_$(3))" \
         --android-cross-path=$(CFG_ARM_LINUX_ANDROIDEABI_NDK) \
         --adb-path=$(CFG_ADB) \
         --adb-test-dir=$(CFG_ADB_TEST_DIR) \
index d52577eb228e2b27454445b026696101b21da885..36b94e4ebea32d4136abc26919eb7f89f4fe0d8d 100644 (file)
@@ -157,3 +157,24 @@ name = "winapi-build"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[metadata]
+"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 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 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 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 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-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
index c64cbb9a74e09573f698d6c295342d9376c40f3e..175e32125f27204bdc0db3b79628b08b1a9de19b 100644 (file)
@@ -38,13 +38,19 @@ fn main() {
     // is passed (a bit janky...)
     let target = args.windows(2).find(|w| &*w[0] == "--target")
                                 .and_then(|w| w[1].to_str());
+    let version = args.iter().find(|w| &**w == "-vV");
 
     // Build scripts always use the snapshot compiler which is guaranteed to be
     // able to produce an executable, whereas intermediate compilers may not
     // have the standard library built yet and may not be able to produce an
     // executable. Otherwise we just use the standard compiler we're
     // bootstrapping with.
-    let (rustc, libdir) = if target.is_none() {
+    //
+    // Also note that cargo will detect the version of the compiler to trigger
+    // a rebuild when the compiler changes. If this happens, we want to make
+    // sure to use the actual compiler instead of the snapshot compiler becase
+    // that's the one that's actually changing.
+    let (rustc, libdir) = if target.is_none() && version.is_none() {
         ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR")
     } else {
         ("RUSTC_REAL", "RUSTC_LIBDIR")
index 3d8b1438125e6fda3aa20aea8bdfb6ca1a70f79b..2b9d717cbd48dbaa3365257cb80916b32a10c393 100644 (file)
@@ -148,6 +148,9 @@ pub fn compiletest(build: &Build,
     if let Some(ref dir) = build.lldb_python_dir {
         cmd.arg("--lldb-python-dir").arg(dir);
     }
+    let llvm_config = build.llvm_config(target);
+    let llvm_version = output(Command::new(&llvm_config).arg("--version"));
+    cmd.arg("--llvm-version").arg(llvm_version);
 
     cmd.args(&build.flags.args);
 
@@ -158,7 +161,6 @@ pub fn compiletest(build: &Build,
     // Only pass correct values for these flags for the `run-make` suite as it
     // requires that a C++ compiler was configured which isn't always the case.
     if suite == "run-make" {
-        let llvm_config = build.llvm_config(target);
         let llvm_components = output(Command::new(&llvm_config).arg("--components"));
         let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags"));
         cmd.arg("--cc").arg(build.cc(target))
index 155848901cdb49c8919d1d77f9d0756f18328b4d..302ac68460c69cbf3c181befa10576b0c3349cc1 100644 (file)
@@ -203,6 +203,10 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
         cargo.env("LLVM_RUSTLLVM", "1");
     }
     cargo.env("LLVM_CONFIG", build.llvm_config(target));
+    let target_config = build.config.target_config.get(target);
+    if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
+        cargo.env("CFG_LLVM_ROOT", s);
+    }
     if build.config.llvm_static_stdcpp {
         cargo.env("LLVM_STATIC_STDCPP",
                   compiler_file(build.cxx(target), "libstdc++.a"));
index aafbf68d1b7b60b712fac8ba7a6b091b2266c98d..682a6f74126a8278555573a5743a057711cdc9eb 100644 (file)
@@ -78,6 +78,7 @@ pub struct Config {
     pub channel: String,
     pub musl_root: Option<PathBuf>,
     pub prefix: Option<String>,
+    pub codegen_tests: bool,
 }
 
 /// Per-target configuration stored in the global configuration structure.
@@ -169,6 +170,7 @@ pub fn parse(build: &str, file: Option<PathBuf>) -> Config {
         config.rust_codegen_units = 1;
         config.build = build.to_string();
         config.channel = "dev".to_string();
+        config.codegen_tests = true;
 
         let toml = file.map(|file| {
             let mut f = t!(File::open(&file));
@@ -322,6 +324,7 @@ macro_rules! check {
                 ("DEBUGINFO_TESTS", self.rust_debuginfo_tests),
                 ("LOCAL_REBUILD", self.local_rebuild),
                 ("NINJA", self.ninja),
+                ("CODEGEN_TESTS", self.codegen_tests),
             }
 
             match key {
index 0af6082aee4f7f16962ee360f8ddc387e82d36b0..dbf29cda49212aabdea508447caec450dd8de063 100644 (file)
@@ -32,7 +32,7 @@
 use std::collections::HashMap;
 use std::env;
 use std::fs::{self, File};
-use std::path::{PathBuf, Path};
+use std::path::{Component, PathBuf, Path};
 use std::process::Command;
 
 use build_helper::{run_silent, output};
@@ -308,10 +308,6 @@ pub fn build(&mut self) {
                     doc::rustbook(self, stage, target.target, "nomicon",
                                   &doc_out);
                 }
-                DocStyle { stage } => {
-                    doc::rustbook(self, stage, target.target, "style",
-                                  &doc_out);
-                }
                 DocStandalone { stage } => {
                     doc::standalone(self, stage, target.target, &doc_out);
                 }
@@ -394,8 +390,10 @@ pub fn build(&mut self) {
                                        "mir-opt", "mir-opt");
                 }
                 CheckCodegen { compiler } => {
-                    check::compiletest(self, &compiler, target.target,
-                                       "codegen", "codegen");
+                    if self.config.codegen_tests {
+                        check::compiletest(self, &compiler, target.target,
+                                           "codegen", "codegen");
+                    }
                 }
                 CheckCodegenUnits { compiler } => {
                     check::compiletest(self, &compiler, target.target,
@@ -479,12 +477,32 @@ pub fn build(&mut self) {
     /// This will detect if any submodules are out of date an run the necessary
     /// commands to sync them all with upstream.
     fn update_submodules(&self) {
+        struct Submodule<'a> {
+            path: &'a Path,
+            state: State,
+        }
+
+        enum State {
+            // The submodule may have staged/unstaged changes
+            MaybeDirty,
+            // Or could be initialized but never updated
+            NotInitialized,
+            // The submodule, itself, has extra commits but those changes haven't been commited to
+            // the (outer) git repository
+            OutOfSync,
+        }
+
         if !self.config.submodules {
             return
         }
         if fs::metadata(self.src.join(".git")).is_err() {
             return
         }
+        let git = || {
+            let mut cmd = Command::new("git");
+            cmd.current_dir(&self.src);
+            return cmd
+        };
         let git_submodule = || {
             let mut cmd = Command::new("git");
             cmd.current_dir(&self.src).arg("submodule");
@@ -496,19 +514,67 @@ fn update_submodules(&self) {
         //        of detecting whether we need to run all the submodule commands
         //        below.
         let out = output(git_submodule().arg("status"));
-        if !out.lines().any(|l| l.starts_with("+") || l.starts_with("-")) {
-            return
+        let mut submodules = vec![];
+        for line in out.lines() {
+            // NOTE `git submodule status` output looks like this:
+            //
+            // -5066b7dcab7e700844b0e2ba71b8af9dc627a59b src/liblibc
+            // +b37ef24aa82d2be3a3cc0fe89bf82292f4ca181c src/compiler-rt (remotes/origin/..)
+            //  e058ca661692a8d01f8cf9d35939dfe3105ce968 src/jemalloc (3.6.0-533-ge058ca6)
+            //
+            // The first character can be '-', '+' or ' ' and denotes the `State` of the submodule
+            // Right next to this character is the SHA-1 of the submodule HEAD
+            // And after that comes the path to the submodule
+            let path = Path::new(line[1..].split(' ').skip(1).next().unwrap());
+            let state = if line.starts_with('-') {
+                State::NotInitialized
+            } else if line.starts_with('+') {
+                State::OutOfSync
+            } else if line.starts_with(' ') {
+                State::MaybeDirty
+            } else {
+                panic!("unexpected git submodule state: {:?}", line.chars().next());
+            };
+
+            submodules.push(Submodule { path: path, state: state })
         }
 
         self.run(git_submodule().arg("sync"));
-        self.run(git_submodule().arg("init"));
-        self.run(git_submodule().arg("update"));
-        self.run(git_submodule().arg("update").arg("--recursive"));
-        self.run(git_submodule().arg("status").arg("--recursive"));
-        self.run(git_submodule().arg("foreach").arg("--recursive")
-                                .arg("git").arg("clean").arg("-fdx"));
-        self.run(git_submodule().arg("foreach").arg("--recursive")
-                                .arg("git").arg("checkout").arg("."));
+
+        for submodule in submodules {
+            // If using llvm-root then don't touch the llvm submodule.
+            if submodule.path.components().any(|c| c == Component::Normal("llvm".as_ref())) &&
+                self.config.target_config.get(&self.config.build)
+                    .and_then(|c| c.llvm_config.as_ref()).is_some()
+            {
+                continue
+            }
+
+            if submodule.path.components().any(|c| c == Component::Normal("jemalloc".as_ref())) &&
+                !self.config.use_jemalloc
+            {
+                continue
+            }
+
+            match submodule.state {
+                State::MaybeDirty => {
+                    // drop staged changes
+                    self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"]));
+                    // drops unstaged changes
+                    self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"]));
+                },
+                State::NotInitialized => {
+                    self.run(git_submodule().arg("init").arg(submodule.path));
+                    self.run(git_submodule().arg("update").arg(submodule.path));
+                },
+                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"]));
+                },
+            }
+        }
     }
 
     /// Clear out `dir` if `input` is newer.
@@ -543,6 +609,10 @@ fn cargo(&self,
              .arg("-j").arg(self.jobs().to_string())
              .arg("--target").arg(target);
 
+        // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
+        // Force cargo to output binaries with disambiguating hashes in the name
+        cargo.env("__CARGO_DEFAULT_LIB_METADATA", "1");
+
         let stage;
         if compiler.stage == 0 && self.local_rebuild {
             // Assume the local-rebuild rustc already has stage1 features.
index c657785d78b6e31f094536b736f7275289c0039a..cc44d45c2cc75864ca7653f010567e0e7e66e1b9 100644 (file)
@@ -22,6 +22,10 @@ BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py $(BOOTSTRAP_
 all:
        $(Q)$(BOOTSTRAP)
 
+# Don’t use $(Q) here, always show how to invoke the bootstrap script directly
+help:
+       $(BOOTSTRAP) --help
+
 clean:
        $(Q)$(BOOTSTRAP) --clean
 
index a78cef4f409b43e1001b209459eb4604e0ff3a5c..a4518d6ed7619159c204480905c49175f0460ffc 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")
+       .define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ")
        .define("LLVM_INCLUDE_EXAMPLES", "OFF")
        .define("LLVM_INCLUDE_TESTS", "OFF")
        .define("LLVM_INCLUDE_DOCS", "OFF")
index d6ac3ef6c9c5024d8c1be674518fa221bfdf41bc..c0d303c0ea9aeb19fe70e7319bdb78178d52920e 100644 (file)
@@ -89,7 +89,7 @@ pub fn check(build: &mut Build) {
 
     // Externally configured LLVM requires FileCheck to exist
     let filecheck = build.llvm_filecheck(&build.config.build);
-    if !filecheck.starts_with(&build.out) && !filecheck.exists() {
+    if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
         panic!("filecheck executable {:?} does not exist", filecheck);
     }
 
index 8d3cb36166b70ffb5e0ab2b5850734aa222f96d1..12929664886c4964f2096f0f530ec1946b3cd924 100644 (file)
@@ -92,7 +92,6 @@ macro_rules! targets {
             (doc, Doc { stage: u32 }),
             (doc_book, DocBook { stage: u32 }),
             (doc_nomicon, DocNomicon { stage: u32 }),
-            (doc_style, DocStyle { stage: u32 }),
             (doc_standalone, DocStandalone { stage: u32 }),
             (doc_std, DocStd { stage: u32 }),
             (doc_test, DocTest { stage: u32 }),
@@ -366,8 +365,7 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
                 vec![self.libtest(compiler)]
             }
             Source::DocBook { stage } |
-            Source::DocNomicon { stage } |
-            Source::DocStyle { stage } => {
+            Source::DocNomicon { stage } => {
                 vec![self.target(&build.config.build).tool_rustbook(stage)]
             }
             Source::DocErrorIndex { stage } => {
@@ -382,8 +380,7 @@ pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> {
             Source::Doc { stage } => {
                 let mut deps = vec![
                     self.doc_book(stage), self.doc_nomicon(stage),
-                    self.doc_style(stage), self.doc_standalone(stage),
-                    self.doc_std(stage),
+                    self.doc_standalone(stage), self.doc_std(stage),
                     self.doc_error_index(stage),
                 ];
 
index 1cfeb2620bd08d6fc16b5ae1a7779af4f4366822..c30b2e68665f177f6c62c148d45dc852801ce049 100644 (file)
@@ -8,7 +8,7 @@ different. Here’s a quick refresher on what these two traits mean.
 
 # Borrow
 
-The `Borrow` trait is used when you’re writing a datastructure, and you want to
+The `Borrow` trait is used when you’re writing a data structure, and you want to
 use either an owned or borrowed type as synonymous for some purpose.
 
 For example, [`HashMap`][hashmap] has a [`get` method][get] which uses `Borrow`:
@@ -86,7 +86,7 @@ We can see how they’re kind of the same: they both deal with owned and borrowe
 versions of some type. However, they’re a bit different.
 
 Choose `Borrow` when you want to abstract over different kinds of borrowing, or
-when you’re building a datastructure that treats owned and borrowed values in
+when you’re building a data structure that treats owned and borrowed values in
 equivalent ways, such as hashing and comparison.
 
 Choose `AsRef` when you want to convert something to a reference directly, and
index d332cac7d8d16c76bed6b7bad805c1c389239feb..3ed85c1a90b692e75105e50b0ae25c41f34614bf 100644 (file)
@@ -340,7 +340,7 @@ fn call_with_ref<'a, F>(some_closure:F) -> i32
     where F: Fn(&'a i32) -> i32 {
 ```
 
-However this presents a problem with in our case. When you specify the explicit
+However this presents a problem in our case. When you specify the explicit
 lifetime on a function it binds that lifetime to the *entire* scope of the function
 instead of just the invocation scope of our closure. This means that the borrow checker
 will see a mutable reference in the same lifetime as our immutable reference and fail
index 8426d5a626549b8ea22b33f3598a78090491e63f..a9a81843ab199c471e3d2c2b56b7408c1d6b5b55 100644 (file)
@@ -46,10 +46,10 @@ extern crate rustc;
 extern crate rustc_plugin;
 
 use syntax::parse::token;
-use syntax::ast::TokenTree;
+use syntax::tokenstream::TokenTree;
 use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
 use syntax::ext::build::AstBuilder;  // trait for expr_usize
-use syntax_pos::Span;
+use syntax::ext::quote::rt::Span;
 use rustc_plugin::Registry;
 
 fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
@@ -69,7 +69,7 @@ fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
     }
 
     let text = match args[0] {
-        TokenTree::Token(_, token::Ident(s, _)) => s.to_string(),
+        TokenTree::Token(_, token::Ident(s)) => s.to_string(),
         _ => {
             cx.span_err(sp, "argument should be a single identifier");
             return DummyResult::any(sp);
index 6e13b464e4c25767643c637dc406be387671c8ff..a62e1b7dfa9c505bfba37e503ad66acee15153b9 100644 (file)
@@ -59,7 +59,7 @@ handling is reducing the amount of explicit case analysis the programmer has to
 do while keeping code composable.
 
 Keeping code composable is important, because without that requirement, we
-could [`panic`](../std/macro.panic!.html) whenever we
+could [`panic`](../std/macro.panic.html) whenever we
 come across something unexpected. (`panic` causes the current task to unwind,
 and in most cases, the entire program aborts.) Here's an example:
 
@@ -944,7 +944,7 @@ macro_rules! try {
 }
 ```
 
-(The [real definition](../std/macro.try!.html) is a bit more
+(The [real definition](../std/macro.try.html) is a bit more
 sophisticated. We will address that later.)
 
 Using the `try!` macro makes it very easy to simplify our last example. Since
@@ -1271,7 +1271,7 @@ macro_rules! try {
 ```
 
 This is not its real definition. Its real definition is
-[in the standard library](../std/macro.try!.html):
+[in the standard library](../std/macro.try.html):
 
 <span id="code-try-def"></span>
 
@@ -2178,7 +2178,7 @@ heuristics!
   [`From`](../std/convert/trait.From.html)
   and
   [`Error`](../std/error/trait.Error.html)
-  impls to make the [`try!`](../std/macro.try!.html)
+  impls to make the [`try!`](../std/macro.try.html)
   macro more ergonomic.
 * If you're writing a library and your code can produce errors, define your own
   error type and implement the
index ca104ff29ace3377c7ccb9efb5d53b7c350963a8..1dea15311ce82aacf15cf2835318202778bc0ac6 100644 (file)
@@ -539,6 +539,7 @@ This is currently hidden behind the `abi_vectorcall` gate and is subject to chan
 * `system`
 * `C`
 * `win64`
+* `sysv64`
 
 Most of the abis in this list are self-explanatory, but the `system` abi may
 seem a little odd. This constraint selects whatever the appropriate ABI is for
index 9f40829f4233f1e4d76f37f5f39fcc4850eaeb28..78fe07ec1be165acc58a0e5d3fd0afb999d6b6b1 100644 (file)
@@ -662,7 +662,7 @@ Here are some common macros you’ll see in Rust code.
 This macro causes the current thread to panic. You can give it a message
 to panic with:
 
-```rust,no_run
+```rust,should_panic
 panic!("oh no!");
 ```
 
@@ -688,7 +688,7 @@ These two macros are used in tests. `assert!` takes a boolean. `assert_eq!`
 takes two values and checks them for equality. `true` passes, `false` `panic!`s.
 Like this:
 
-```rust,no_run
+```rust,should_panic
 // A-ok!
 
 assert!(true);
index e685cb129b939669a235ec14ddb2091c9d06f086..9cbb514e2806576e7c9d3f9cbddc5e66f2a307de 100644 (file)
@@ -47,6 +47,34 @@ As you can see, the `trait` block looks very similar to the `impl` block,
 but we don’t define a body, only a type signature. When we `impl` a trait,
 we use `impl Trait for Item`, rather than only `impl Item`.
 
+`Self` may be used in a type annotation to refer to an instance of the type
+implementing this trait passed as a parameter. `Self`, `&Self` or `&mut Self`
+may be used depending on the level of ownership required.
+
+```rust
+struct Circle {
+    x: f64,
+    y: f64,
+    radius: f64,
+}
+
+trait HasArea {
+    fn area(&self) -> f64;
+
+    fn is_larger(&self, &Self) -> bool;
+}
+
+impl HasArea for Circle {
+    fn area(&self) -> f64 {
+        std::f64::consts::PI * (self.radius * self.radius)
+    }
+
+    fn is_larger(&self, other: &Self) -> bool {
+        self.area() > other.area()
+    }
+}
+```
+
 ## Trait bounds on generic functions
 
 Traits are useful because they allow a type to make certain promises about its
index f0ab1488d4015962f432ba4971aeb0b9bc2a2f79..cc5d9c3685aba004f1e61cd17e5a1dd49974d7e8 100644 (file)
@@ -1677,6 +1677,7 @@ There are also some platform-specific ABI strings:
 * `extern "cdecl"` -- The default for x86\_32 C code.
 * `extern "stdcall"` -- The default for the Win32 API on x86\_32.
 * `extern "win64"` -- The default for C code on x86\_64 Windows.
+* `extern "sysv64"` -- The default for C code on non-Windows x86\_64.
 * `extern "aapcs"` -- The default for ARM.
 * `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's
   `__fastcall` and GCC and clang's `__attribute__((fastcall))`
@@ -2070,6 +2071,9 @@ macro scope.
    trait of the same name. `{Self}` will be replaced with the type that is supposed
    to implement the trait but doesn't. To use this, the `on_unimplemented` feature gate
    must be enabled.
+- `must_use` - on structs and enums, will warn if a value of this type isn't used or
+   assigned to a variable. You may also include an optional message by using
+   `#[must_use = "message"]` which will be given alongside the warning.
 
 ### Conditional compilation
 
@@ -2283,7 +2287,7 @@ the `PartialEq` or `Clone` constraints for the appropriate `impl`:
 #[derive(PartialEq, Clone)]
 struct Foo<T> {
     a: i32,
-    b: T
+    b: T,
 }
 ```
 
@@ -2485,6 +2489,9 @@ The currently implemented features of the reference compiler are:
 
 * - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns.
 
+* - `abi_sysv64` - Allows the usage of the system V AMD64 calling convention
+                             (e.g. `extern "sysv64" func fn_();`)
+
 If a feature is promoted to a language feature, then all existing programs will
 start to receive compilation warnings about `#![feature]` directives which enabled
 the new feature (because the directive is no longer necessary). However, if a
@@ -3896,7 +3903,7 @@ Coercion is allowed between the following types:
   use std::ops::Deref;
 
   struct CharContainer {
-      value: char
+      value: char,
   }
 
   impl Deref for CharContainer {
diff --git a/src/doc/style/README.md b/src/doc/style/README.md
deleted file mode 100644 (file)
index 8d837d1..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-% Style Guidelines
-
-This document collects the emerging principles, conventions, abstractions, and
-best practices for writing Rust code.
-
-Since Rust is evolving at a rapid pace, these guidelines are
-preliminary. The hope is that writing them down explicitly will help
-drive discussion, consensus and adoption.
-
-Whenever feasible, guidelines provide specific examples from Rust's standard
-libraries.
-
-### Guideline statuses
-
-Every guideline has a status:
-
-* **[FIXME]**: Marks places where there is more work to be done. In
-  some cases, that just means going through the RFC process.
-
-* **[FIXME #NNNNN]**: Like **[FIXME]**, but links to the issue tracker.
-
-* **[RFC #NNNN]**: Marks accepted guidelines, linking to the rust-lang
-  RFC establishing them.
-
-### Guideline stabilization
-
-One purpose of these guidelines is to reach decisions on a number of
-cross-cutting API and stylistic choices. Discussion and development of
-the guidelines will happen primarily on https://internals.rust-lang.org/,
-using the Guidelines category. Discussion can also occur on the
-[guidelines issue tracker](https://github.com/rust-lang/rust-guidelines).
-
-Guidelines that are under development or discussion will be marked with the
-status **[FIXME]**, with a link to the issue tracker when appropriate.
-
-Once a concrete guideline is ready to be proposed, it should be filed
-as an [FIXME: needs RFC](https://github.com/rust-lang/rfcs). If the RFC is
-accepted, the official guidelines will be updated to match, and will
-include the tag **[RFC #NNNN]** linking to the RFC document.
-
-### What's in this document
-
-This document is broken into four parts:
-
-* **[Style](style/README.md)** provides a set of rules governing naming conventions,
-  whitespace, and other stylistic issues.
-
-* **[Guidelines by Rust feature](features/README.md)** places the focus on each of
-  Rust's features, starting from expressions and working the way out toward
-  crates, dispensing guidelines relevant to each.
-
-* **Topical guidelines and patterns**. The rest of the document proceeds by
-  cross-cutting topic, starting with
-  [Ownership and resources](ownership/README.md).
-
-* **APIs for a changing Rust**
-  discusses the forward-compatibility hazards, especially those that interact
-  with the pre-1.0 library stabilization process.
-
-> **[FIXME]** Add cross-references throughout this document to the tutorial,
-> reference manual, and other guides.
-
-> **[FIXME]** What are some _non_-goals, _non_-principles, or _anti_-patterns that
-> we should document?
diff --git a/src/doc/style/SUMMARY.md b/src/doc/style/SUMMARY.md
deleted file mode 100644 (file)
index 508ede6..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-# Summary
-
-* [Style](style/README.md)
-    * [Whitespace](style/whitespace.md)
-    * [Comments](style/comments.md)
-    * [Braces, semicolons, commas](style/braces.md)
-    * [Naming](style/naming/README.md)
-        * [Ownership variants](style/naming/ownership.md)
-        * [Containers/wrappers](style/naming/containers.md)
-        * [Conversions](style/naming/conversions.md)
-        * [Iterators](style/naming/iterators.md)
-    * [Imports](style/imports.md)
-    * [Organization](style/organization.md)
-* [Guidelines by Rust feature](features/README.md)
-    * [Let binding](features/let.md)
-    * [Pattern matching](features/match.md)
-    * [Loops](features/loops.md)
-    * [Functions and methods](features/functions-and-methods/README.md)
-        * [Input](features/functions-and-methods/input.md)
-        * [Output](features/functions-and-methods/output.md)
-        * [For convenience](features/functions-and-methods/convenience.md)
-    * [Types](features/types/README.md)
-        * [Conversions](features/types/conversions.md)
-        * [The newtype pattern](features/types/newtype.md)
-    * [Traits](features/traits/README.md)
-        * [For generics](features/traits/generics.md)
-        * [For objects](features/traits/objects.md)
-        * [For overloading](features/traits/overloading.md)
-        * [For extensions](features/traits/extensions.md)
-        * [For reuse](features/traits/reuse.md)
-        * [Common traits](features/traits/common.md)
-    * [Modules](features/modules.md)
-    * [Crates](features/crates.md)
-* [Ownership and resources](ownership/README.md)
-    * [Constructors](ownership/constructors.md)
-    * [Builders](ownership/builders.md)
-    * [Destructors](ownership/destructors.md)
-    * [RAII](ownership/raii.md)
-    * [Cells and smart pointers](ownership/cell-smart.md)
-* [Errors](errors/README.md)
-    * [Signaling](errors/signaling.md)
-    * [Handling](errors/handling.md)
-    * [Propagation](errors/propagation.md)
-    * [Ergonomics](errors/ergonomics.md)
-* [Safety and guarantees](safety/README.md)
-    * [Using unsafe](safety/unsafe.md)
-    * [Library guarantees](safety/lib-guarantees.md)
-* [Testing](testing/README.md)
-    * [Unit testing](testing/unit.md)
-* [FFI, platform-specific code](platform.md)
diff --git a/src/doc/style/errors/README.md b/src/doc/style/errors/README.md
deleted file mode 100644 (file)
index 444da26..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-% Errors
-
-> **[FIXME]** Add some general text here.
diff --git a/src/doc/style/errors/ergonomics.md b/src/doc/style/errors/ergonomics.md
deleted file mode 100644 (file)
index 269f2a2..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-% Ergonomic error handling
-
-Error propagation with raw `Result`s can require tedious matching and
-repackaging. This tedium is largely alleviated by the `try!` macro,
-and can be completely removed (in some cases) by the "`Result`-`impl`"
-pattern.
-
-### The `try!` macro
-
-Prefer
-
-```rust,ignore
-use std::io::{File, Open, Write, IoError};
-
-struct Info {
-    name: String,
-    age: i32,
-    rating: i32
-}
-
-fn write_info(info: &Info) -> Result<(), IoError> {
-    let mut file = File::open_mode(&Path::new("my_best_friends.txt"),
-                                   Open, Write);
-    // Early return on error
-    try!(file.write_line(&format!("name: {}", info.name)));
-    try!(file.write_line(&format!("age: {}", info.age)));
-    try!(file.write_line(&format!("rating: {}", info.rating)));
-    return Ok(());
-}
-```
-
-over
-
-```rust,ignore
-use std::io::{File, Open, Write, IoError};
-
-struct Info {
-    name: String,
-    age: i32,
-    rating: i32
-}
-
-fn write_info(info: &Info) -> Result<(), IoError> {
-    let mut file = File::open_mode(&Path::new("my_best_friends.txt"),
-                                   Open, Write);
-    // Early return on error
-    match file.write_line(&format!("name: {}", info.name)) {
-        Ok(_) => (),
-        Err(e) => return Err(e)
-    }
-    match file.write_line(&format!("age: {}", info.age)) {
-        Ok(_) => (),
-        Err(e) => return Err(e)
-    }
-    return file.write_line(&format!("rating: {}", info.rating));
-}
-```
-
-See
-[the `result` module documentation](https://doc.rust-lang.org/stable/std/result/index.html#the-try-macro)
-for more details.
-
-### The `Result`-`impl` pattern [FIXME]
-
-> **[FIXME]** Document the way that the `io` module uses trait impls
-> on `std::io::Result` to painlessly propagate errors.
diff --git a/src/doc/style/errors/handling.md b/src/doc/style/errors/handling.md
deleted file mode 100644 (file)
index 9b8a00d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-% Handling errors
-
-### Use thread isolation to cope with failure. [FIXME]
-
-> **[FIXME]** Explain how to isolate threads and detect thread failure for recovery.
-
-### Consuming `Result` [FIXME]
diff --git a/src/doc/style/errors/propagation.md b/src/doc/style/errors/propagation.md
deleted file mode 100644 (file)
index 0a347cd..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-% Propagation
-
-> **[FIXME]** We need guidelines on how to layer error information up a stack of
-> abstractions.
-
-### Error interoperation [FIXME]
-
-> **[FIXME]** Document the `FromError` infrastructure.
diff --git a/src/doc/style/errors/signaling.md b/src/doc/style/errors/signaling.md
deleted file mode 100644 (file)
index 4038ec1..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-% Signaling errors [RFC #236]
-
-> The guidelines below were approved by [RFC #236](https://github.com/rust-lang/rfcs/pull/236).
-
-Errors fall into one of three categories:
-
-* Catastrophic errors, e.g. out-of-memory.
-* Contract violations, e.g. wrong input encoding, index out of bounds.
-* Obstructions, e.g. file not found, parse error.
-
-The basic principle of the convention is that:
-
-* Catastrophic errors and programming errors (bugs) can and should only be
-recovered at a *coarse grain*, i.e. a thread boundary.
-* Obstructions preventing an operation should be reported at a maximally *fine
-grain* -- to the immediate invoker of the operation.
-
-## Catastrophic errors
-
-An error is _catastrophic_ if there is no meaningful way for the current thread to
-continue after the error occurs.
-
-Catastrophic errors are _extremely_ rare, especially outside of `libstd`.
-
-**Canonical examples**: out of memory, stack overflow.
-
-### For catastrophic errors, panic
-
-For errors like stack overflow, Rust currently aborts the process, but
-could in principle panic, which (in the best case) would allow
-reporting and recovery from a supervisory thread.
-
-## Contract violations
-
-An API may define a contract that goes beyond the type checking enforced by the
-compiler. For example, slices support an indexing operation, with the contract
-that the supplied index must be in bounds.
-
-Contracts can be complex and involve more than a single function invocation. For
-example, the `RefCell` type requires that `borrow_mut` not be called until all
-existing borrows have been relinquished.
-
-### For contract violations, panic
-
-A contract violation is always a bug, and for bugs we follow the Erlang
-philosophy of "let it crash": we assume that software *will* have bugs, and we
-design coarse-grained thread boundaries to report, and perhaps recover, from these
-bugs.
-
-### Contract design
-
-One subtle aspect of these guidelines is that the contract for a function is
-chosen by an API designer -- and so the designer also determines what counts as
-a violation.
-
-This RFC does not attempt to give hard-and-fast rules for designing
-contracts. However, here are some rough guidelines:
-
-* Prefer expressing contracts through static types whenever possible.
-
-* It *must* be possible to write code that uses the API without violating the
-  contract.
-
-* Contracts are most justified when violations are *inarguably* bugs -- but this
-  is surprisingly rare.
-
-* Consider whether the API client could benefit from the contract-checking
-  logic.  The checks may be expensive. Or there may be useful programming
-  patterns where the client does not want to check inputs before hand, but would
-  rather attempt the operation and then find out whether the inputs were invalid.
-
-* When a contract violation is the *only* kind of error a function may encounter
-  -- i.e., there are no obstructions to its success other than "bad" inputs --
-  using `Result` or `Option` instead is especially warranted. Clients can then use
-  `unwrap` to assert that they have passed valid input, or re-use the error
-  checking done by the API for their own purposes.
-
-* When in doubt, use loose contracts and instead return a `Result` or `Option`.
-
-## Obstructions
-
-An operation is *obstructed* if it cannot be completed for some reason, even
-though the operation's contract has been satisfied. Obstructed operations may
-have (documented!) side effects -- they are not required to roll back after
-encountering an obstruction.  However, they should leave the data structures in
-a "coherent" state (satisfying their invariants, continuing to guarantee safety,
-etc.).
-
-Obstructions may involve external conditions (e.g., I/O), or they may involve
-aspects of the input that are not covered by the contract.
-
-**Canonical examples**: file not found, parse error.
-
-### For obstructions, use `Result`
-
-The
-[`Result<T,E>` type](https://doc.rust-lang.org/stable/std/result/index.html)
-represents either a success (yielding `T`) or failure (yielding `E`). By
-returning a `Result`, a function allows its clients to discover and react to
-obstructions in a fine-grained way.
-
-#### What about `Option`?
-
-The `Option` type should not be used for "obstructed" operations; it
-should only be used when a `None` return value could be considered a
-"successful" execution of the operation.
-
-This is of course a somewhat subjective question, but a good litmus
-test is: would a reasonable client ever ignore the result? The
-`Result` type provides a lint that ensures the result is actually
-inspected, while `Option` does not, and this difference of behavior
-can help when deciding between the two types.
-
-Another litmus test: can the operation be understood as asking a
-question (possibly with sideeffects)? Operations like `pop` on a
-vector can be viewed as asking for the contents of the first element,
-with the side effect of removing it if it exists -- with an `Option`
-return value.
-
-## Do not provide both `Result` and `panic!` variants.
-
-An API should not provide both `Result`-producing and `panic`king versions of an
-operation. It should provide just the `Result` version, allowing clients to use
-`try!` or `unwrap` instead as needed. This is part of the general pattern of
-cutting down on redundant variants by instead using method chaining.
diff --git a/src/doc/style/features/README.md b/src/doc/style/features/README.md
deleted file mode 100644 (file)
index 0965750..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-% Guidelines by language feature
-
-Rust provides a unique combination of language features, some new and some
-old. This section gives guidance on when and how to use Rust's features, and
-brings attention to some of the tradeoffs between different features.
-
-Notably missing from this section is an in-depth discussion of Rust's pointer
-types (both built-in and in the library). The topic of pointers is discussed at
-length in a [separate section on ownership](../ownership/README.md).
diff --git a/src/doc/style/features/crates.md b/src/doc/style/features/crates.md
deleted file mode 100644 (file)
index 4748b05..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-% Crates
-
-> **[FIXME]** What general guidelines should we provide for crate design?
-
-> Possible topics: facades; per-crate preludes (to be imported as globs);
-> "lib.rs"
diff --git a/src/doc/style/features/functions-and-methods/README.md b/src/doc/style/features/functions-and-methods/README.md
deleted file mode 100644 (file)
index a3559ca..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-% Functions and methods
-
-### Prefer methods to functions if there is a clear receiver. **[FIXME: needs RFC]**
-
-Prefer
-
-```rust,ignore
-impl Foo {
-    pub fn frob(&self, w: widget) { ... }
-}
-```
-
-over
-
-```rust,ignore
-pub fn frob(foo: &Foo, w: widget) { ... }
-```
-
-for any operation that is clearly associated with a particular
-type.
-
-Methods have numerous advantages over functions:
-
-* They do not need to be imported or qualified to be used: all you
-  need is a value of the appropriate type.
-* Their invocation performs autoborrowing (including mutable borrows).
-* They make it easy to answer the question "what can I do with a value
-  of type `T`" (especially when using rustdoc).
-* They provide `self` notation, which is more concise and often more
-  clearly conveys ownership distinctions.
-
-> **[FIXME]** Revisit these guidelines with
-> [UFCS](https://github.com/nick29581/rfcs/blob/ufcs/0000-ufcs.md) and
-> conventions developing around it.
-
-
-
-### Guidelines for inherent methods. **[FIXME]**
-
-> **[FIXME]** We need guidelines for when to provide inherent methods on a type,
-> versus methods through a trait or functions.
-
-> **NOTE**: Rules for method resolution around inherent methods are in flux,
-> which may impact the guidelines.
diff --git a/src/doc/style/features/functions-and-methods/convenience.md b/src/doc/style/features/functions-and-methods/convenience.md
deleted file mode 100644 (file)
index 69fd377..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-% Convenience methods
-
-### Provide small, coherent sets of convenience methods. **[FIXME: needs RFC]**
-
-_Convenience methods_ wrap up existing functionality in a more convenient
-way. The work done by a convenience method varies widely:
-
-* _Re-providing functions as methods_. For example, the `std::path::Path` type
-  provides methods like `stat` on `Path`s that simply invoke the corresponding
-  function in `std::io::fs`.
-* _Skipping through conversions_. For example, the `str` type provides a
-  `.len()` convenience method which is also expressible as `.as_bytes().len()`.
-  Sometimes the conversion is more complex: the `str` module also provides
-  `from_chars`, which encapsulates a simple use of iterators.
-* _Encapsulating common arguments_. For example, vectors of `&str`s
-  provide a `connect` as well as a special case, `concat`, that is expressible
-  using `connect` with a fixed separator of `""`.
-* _Providing more efficient special cases_. The `connect` and `concat` example
-  also applies here: singling out `concat` as a special case allows for a more
-  efficient implementation.
-
-  Note, however, that the `connect` method actually detects the special case
-  internally and invokes `concat`. Usually, it is not necessary to add a public
-  convenience method just for efficiency gains; there should also be a
-  _conceptual_ reason to add it, e.g. because it is such a common special case.
-
-It is tempting to add convenience methods in a one-off, haphazard way as
-common use patterns emerge. Avoid this temptation, and instead _design_ small,
-coherent sets of convenience methods that are easy to remember:
-
-* _Small_: Avoid combinatorial explosions of convenience methods. For example,
-  instead of adding `_str` variants of methods that provide a `str` output,
-  instead ensure that the normal output type of methods is easily convertible to
-  `str`.
-* _Coherent_: Look for small groups of convenience methods that make sense to
-  include together. For example, the `Path` API mentioned above includes a small
-  selection of the most common filesystem operations that take a `Path`
-  argument.  If one convenience method strongly suggests the existence of others,
-  consider adding the whole group.
-* _Memorable_: It is not worth saving a few characters of typing if you have to
-  look up the name of a convenience method every time you use it. Add
-  convenience methods with names that are obvious and easy to remember, and add
-  them for the most common or painful use cases.
diff --git a/src/doc/style/features/functions-and-methods/input.md b/src/doc/style/features/functions-and-methods/input.md
deleted file mode 100644 (file)
index 5b63a45..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-% Input to functions and methods
-
-### Let the client decide when to copy and where to place data. [FIXME: needs RFC]
-
-#### Copying:
-
-Prefer
-
-```rust,ignore
-fn foo(b: Bar) {
-   // use b as owned, directly
-}
-```
-
-over
-
-```rust,ignore
-fn foo(b: &Bar) {
-    let b = b.clone();
-    // use b as owned after cloning
-}
-```
-
-If a function requires ownership of a value of unknown type `T`, but does not
-otherwise need to make copies, the function should take ownership of the
-argument (pass by value `T`) rather than using `.clone()`. That way, the caller
-can decide whether to relinquish ownership or to `clone`.
-
-Similarly, the `Copy` trait bound should only be demanded it when absolutely
-needed, not as a way of signaling that copies should be cheap to make.
-
-#### Placement:
-
-Prefer
-
-```rust,ignore
-fn foo(b: Bar) -> Bar { ... }
-```
-
-over
-
-```rust,ignore
-fn foo(b: Box<Bar>) -> Box<Bar> { ... }
-```
-
-for concrete types `Bar` (as opposed to trait objects). This way, the caller can
-decide whether to place data on the stack or heap. No overhead is imposed by
-letting the caller determine the placement.
-
-### Minimize assumptions about parameters. [FIXME: needs RFC]
-
-The fewer assumptions a function makes about its inputs, the more widely usable
-it becomes.
-
-#### Minimizing assumptions through generics:
-
-Prefer
-
-```rust,ignore
-fn foo<T: Iterator<i32>>(c: T) { ... }
-```
-
-over any of
-
-```rust,ignore
-fn foo(c: &[i32]) { ... }
-fn foo(c: &Vec<i32>) { ... }
-fn foo(c: &SomeOtherCollection<i32>) { ... }
-```
-
-if the function only needs to iterate over the data.
-
-More generally, consider using generics to pinpoint the assumptions a function
-needs to make about its arguments.
-
-On the other hand, generics can make it more difficult to read and understand a
-function's signature. Aim for "natural" parameter types that a neither overly
-concrete nor overly abstract. See the discussion on
-[traits](../traits/README.md) for more guidance.
-
-
-#### Minimizing ownership assumptions:
-
-Prefer either of
-
-```rust,ignore
-fn foo(b: &Bar) { ... }
-fn foo(b: &mut Bar) { ... }
-```
-
-over
-
-```rust,ignore
-fn foo(b: Bar) { ... }
-```
-
-That is, prefer borrowing arguments rather than transferring ownership, unless
-ownership is actually needed.
-
-### Prefer compound return types to out-parameters. [FIXME: needs RFC]
-
-Prefer
-
-```rust,ignore
-fn foo() -> (Bar, Bar)
-```
-
-over
-
-```rust,ignore
-fn foo(output: &mut Bar) -> Bar
-```
-
-for returning multiple `Bar` values.
-
-Compound return types like tuples and structs are efficiently compiled
-and do not require heap allocation. If a function needs to return
-multiple values, it should do so via one of these types.
-
-The primary exception: sometimes a function is meant to modify data
-that the caller already owns, for example to re-use a buffer:
-
-```rust,ignore
-fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize>
-```
-
-(From the [Read trait](https://doc.rust-lang.org/stable/std/io/trait.Read.html#tymethod.read).)
-
-### Consider validating arguments, statically or dynamically. [FIXME: needs RFC]
-
-_Note: this material is closely related to
-  [library-level guarantees](../../safety/lib-guarantees.md)._
-
-Rust APIs do _not_ generally follow the
-[robustness principle](https://en.wikipedia.org/wiki/Robustness_principle): "be
-conservative in what you send; be liberal in what you accept".
-
-Instead, Rust code should _enforce_ the validity of input whenever practical.
-
-Enforcement can be achieved through the following mechanisms (listed
-in order of preference).
-
-#### Static enforcement:
-
-Choose an argument type that rules out bad inputs.
-
-For example, prefer
-
-```rust,ignore
-enum FooMode {
-    Mode1,
-    Mode2,
-    Mode3,
-}
-fn foo(mode: FooMode) { ... }
-```
-
-over
-
-```rust,ignore
-fn foo(mode2: bool, mode3: bool) {
-    assert!(!mode2 || !mode3);
-    ...
-}
-```
-
-Static enforcement usually comes at little run-time cost: it pushes the
-costs to the boundaries. It also catches bugs early, during compilation,
-rather than through run-time failures.
-
-On the other hand, some properties are difficult or impossible to
-express using types.
-
-#### Dynamic enforcement:
-
-Validate the input as it is processed (or ahead of time, if necessary).  Dynamic
-checking is often easier to implement than static checking, but has several
-downsides:
-
-1. Runtime overhead (unless checking can be done as part of processing the input).
-2. Delayed detection of bugs.
-3. Introduces failure cases, either via `panic!` or `Result`/`Option` types (see
-   the [error handling guidelines](../../errors/README.md)), which must then be
-   dealt with by client code.
-
-#### Dynamic enforcement with `debug_assert!`:
-
-Same as dynamic enforcement, but with the possibility of easily turning off
-expensive checks for production builds.
-
-#### Dynamic enforcement with opt-out:
-
-Same as dynamic enforcement, but adds sibling functions that opt out of the
-checking.
-
-The convention is to mark these opt-out functions with a suffix like
-`_unchecked` or by placing them in a `raw` submodule.
-
-The unchecked functions can be used judiciously in cases where (1) performance
-dictates avoiding checks and (2) the client is otherwise confident that the
-inputs are valid.
-
-> **[FIXME]** Should opt-out functions be marked `unsafe`?
diff --git a/src/doc/style/features/functions-and-methods/output.md b/src/doc/style/features/functions-and-methods/output.md
deleted file mode 100644 (file)
index e26eee5..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-% Output from functions and methods
-
-### Don't overpromise. [FIXME]
-
-> **[FIXME]** Add discussion of overly-specific return types,
-> e.g. returning a compound iterator type rather than hiding it behind
-> a use of newtype.
-
-### Let clients choose what to throw away. [FIXME: needs RFC]
-
-#### Return useful intermediate results:
-
-Many functions that answer a question also compute interesting related data.  If
-this data is potentially of interest to the client, consider exposing it in the
-API.
-
-Prefer
-
-```rust,ignore
-struct SearchResult {
-    found: bool,          // item in container?
-    expected_index: usize // what would the item's index be?
-}
-
-fn binary_search(&self, k: Key) -> SearchResult
-```
-or
-
-```rust,ignore
-fn binary_search(&self, k: Key) -> (bool, usize)
-```
-
-over
-
-```rust,ignore
-fn binary_search(&self, k: Key) -> bool
-```
-
-#### Yield back ownership:
-
-Prefer
-
-```rust,ignore
-fn from_utf8_owned(vv: Vec<u8>) -> Result<String, Vec<u8>>
-```
-
-over
-
-```rust,ignore
-fn from_utf8_owned(vv: Vec<u8>) -> Option<String>
-```
-
-The `from_utf8_owned` function gains ownership of a vector.  In the successful
-case, the function consumes its input, returning an owned string without
-allocating or copying. In the unsuccessful case, however, the function returns
-back ownership of the original slice.
diff --git a/src/doc/style/features/let.md b/src/doc/style/features/let.md
deleted file mode 100644 (file)
index ba9787b..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-% Let binding
-
-### Always separately bind RAII guards. [FIXME: needs RFC]
-
-Prefer
-
-```rust,ignore
-fn use_mutex(m: sync::mutex::Mutex<i32>) {
-    let guard = m.lock();
-    do_work(guard);
-    drop(guard); // unlock the lock
-    // do other work
-}
-```
-
-over
-
-```rust,ignore
-fn use_mutex(m: sync::mutex::Mutex<i32>) {
-    do_work(m.lock());
-    // do other work
-}
-```
-
-As explained in the [RAII guide](../ownership/raii.md), RAII guards are values
-that represent ownership of some resource and whose destructor releases the
-resource. Because the lifetime of guards are significant, they should always be
-explicitly `let`-bound to make the lifetime clear. Consider using an explicit
-`drop` to release the resource early.
-
-### Prefer conditional expressions to deferred initialization. [FIXME: needs RFC]
-
-Prefer
-
-```rust,ignore
-let foo = match bar {
-    Baz => 0,
-    Quux => 1
-};
-```
-
-over
-
-```rust,ignore
-let foo;
-match bar {
-    Baz => {
-        foo = 0;
-    }
-    Quux => {
-        foo = 1;
-    }
-}
-```
-
-unless the conditions for initialization are too complex to fit into a simple
-conditional expression.
-
-### Use type annotations for clarification; prefer explicit generics when inference fails. [FIXME: needs RFC]
-
-Prefer
-
-```rust,ignore
-let v = s.iter().map(|x| x * 2)
-                .collect::<Vec<_>>();
-```
-
-over
-
-```rust,ignore
-let v: Vec<_> = s.iter().map(|x| x * 2)
-                        .collect();
-```
-
-When the type of a value might be unclear to the _reader_ of the code, consider
-explicitly annotating it in a `let`.
-
-On the other hand, when the type is unclear to the _compiler_, prefer to specify
-the type by explicit generics instantiation, which is usually more clear.
-
-### Shadowing [FIXME]
-
-> **[FIXME]** Repeatedly shadowing a binding is somewhat common in Rust code. We
-> need to articulate a guideline on when it is appropriate/useful and when not.
-
-### Prefer immutable bindings. [FIXME: needs RFC]
-
-Use `mut` bindings to signal the span during which a value is mutated:
-
-```rust,ignore
-let mut v = Vec::new();
-// push things onto v
-let v = v;
-// use v immutably henceforth
-```
-
-### Prefer to bind all `struct` or tuple fields. [FIXME: needs RFC]
-
-When consuming a `struct` or tuple via a `let`, bind all of the fields rather
-than using `..` to elide the ones you don't need. The benefit is that when
-fields are added, the compiler will pinpoint all of the places where that type
-of value was consumed, which will often need to be adjusted to take the new
-field properly into account.
diff --git a/src/doc/style/features/loops.md b/src/doc/style/features/loops.md
deleted file mode 100644 (file)
index b144825..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-% Loops
-
-### Prefer `for` to `while`. [FIXME: needs RFC]
-
-A `for` loop is preferable to a `while` loop, unless the loop counts in a
-non-uniform way (making it difficult to express using `for`).
-
-### Guidelines for `loop`. [FIXME]
-
-> **[FIXME]** When is `loop` recommended? Some possibilities:
-> * For optimistic retry algorithms
-> * For servers
-> * To avoid mutating local variables sometimes needed to fit `while`
diff --git a/src/doc/style/features/match.md b/src/doc/style/features/match.md
deleted file mode 100644 (file)
index 0d5a118..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-% Pattern matching
-
-### Dereference `match` targets when possible. [FIXME: needs RFC]
-
-Prefer
-
-~~~~ignore
-match *foo {
-    X(...) => ...
-    Y(...) => ...
-}
-~~~~
-
-over
-
-~~~~ignore
-match foo {
-    box X(...) => ...
-    box Y(...) => ...
-}
-~~~~
-
-<!-- ### Clearly indicate important scopes. **[FIXME: needs RFC]** -->
-
-<!-- If it is important that the destructor for a value be executed at a specific -->
-<!-- time, clearly bind that value using a standalone `let` -->
diff --git a/src/doc/style/features/modules.md b/src/doc/style/features/modules.md
deleted file mode 100644 (file)
index 995c5fd..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-% Modules
-
-> **[FIXME]** What general guidelines should we provide for module design?
-
-> We should discuss visibility, nesting, `mod.rs`, and any interesting patterns
-> around modules.
-
-### Headers [FIXME: needs RFC]
-
-Organize module headers as follows:
-  1. [Imports](../style/imports.md).
-  1. `mod` declarations.
-  1. `pub mod` declarations.
-
-### Avoid `path` directives. [FIXME: needs RFC]
-
-Avoid using `#[path="..."]` directives; make the file system and
-module hierarchy match, instead.
-
-### Use the module hierarchy to organize APIs into coherent sections. [FIXME]
-
-> **[FIXME]** Flesh this out with examples; explain what a "coherent
-> section" is with examples.
->
-> The module hierarchy defines both the public and internal API of your module.
-> Breaking related functionality into submodules makes it understandable to both
-> users and contributors to the module.
-
-### Place modules in their own file. [FIXME: needs RFC]
-
-> **[FIXME]**
-> - "<100 lines" is arbitrary, but it's a clearer recommendation
->   than "~1 page" or similar suggestions that vary by screen size, etc.
-
-For all except very short modules (<100 lines) and [tests](../testing/README.md),
-place the module `foo` in a separate file, as in:
-
-```rust,ignore
-pub mod foo;
-
-// in foo.rs or foo/mod.rs
-pub fn bar() { println!("..."); }
-/* ... */
-```
-
-rather than declaring it inline:
-
-```rust,ignore
-pub mod foo {
-    pub fn bar() { println!("..."); }
-    /* ... */
-}
-```
-
-#### Use subdirectories for modules with children. [FIXME: needs RFC]
-
-For modules that themselves have submodules, place the module in a separate
-directory (e.g., `bar/mod.rs` for a module `bar`) rather than the same directory.
-
-Note the structure of
-[`std::io`](https://doc.rust-lang.org/std/io/). Many of the submodules lack
-children, like
-[`io::fs`](https://doc.rust-lang.org/std/io/fs/)
-and
-[`io::stdio`](https://doc.rust-lang.org/std/io/stdio/).
-On the other hand,
-[`io::net`](https://doc.rust-lang.org/std/io/net/)
-contains submodules, so it lives in a separate directory:
-
-```text
-io/mod.rs
-   io/extensions.rs
-   io/fs.rs
-   io/net/mod.rs
-          io/net/addrinfo.rs
-          io/net/ip.rs
-          io/net/tcp.rs
-          io/net/udp.rs
-          io/net/unix.rs
-   io/pipe.rs
-   ...
-```
-
-While it is possible to define all of `io` within a single directory,
-mirroring the module hierarchy in the directory structure makes
-submodules of `io::net` easier to find.
-
-### Consider top-level definitions or reexports. [FIXME: needs RFC]
-
-For modules with submodules,
-define or [reexport](https://doc.rust-lang.org/std/io/#reexports) commonly used
-definitions at the top level:
-
-* Functionality relevant to the module itself or to many of its
-  children should be defined in `mod.rs`.
-* Functionality specific to a submodule should live in that
-  submodule. Reexport at the top level for the most important or
-  common definitions.
-
-For example,
-[`IoError`](https://doc.rust-lang.org/std/io/struct.IoError.html)
-is defined in `io/mod.rs`, since it pertains to the entirety of `io`,
-while
-[`TcpStream`](https://doc.rust-lang.org/std/io/net/tcp/struct.TcpStream.html)
-is defined in `io/net/tcp.rs` and reexported in the `io` module.
-
-### Use internal module hierarchies for organization. [FIXME: needs RFC]
-
-> **[FIXME]**
-> - Referencing internal modules from the standard library is subject to
->   becoming outdated.
-
-Internal module hierarchies (i.e., private submodules) may be used to
-hide implementation details that are not part of the module's API.
-
-For example, in [`std::io`](https://doc.rust-lang.org/std/io/), `mod mem`
-provides implementations for
-[`BufReader`](https://doc.rust-lang.org/std/io/struct.BufReader.html)
-and
-[`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html),
-but these are re-exported in `io/mod.rs` at the top level of the module:
-
-```rust,ignore
-// libstd/io/mod.rs
-
-pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter};
-/* ... */
-mod mem;
-```
-
-This hides the detail that there even exists a `mod mem` in `io`, and
-helps keep code organized while offering freedom to change the
-implementation.
diff --git a/src/doc/style/features/traits/README.md b/src/doc/style/features/traits/README.md
deleted file mode 100644 (file)
index 1893db2..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-% Traits
-
-Traits are probably Rust's most complex feature, supporting a wide range of use
-cases and design tradeoffs. Patterns of trait usage are still emerging.
-
-### Know whether a trait will be used as an object. [FIXME: needs RFC]
-
-Trait objects have some [significant limitations](objects.md): methods
-invoked through a trait object cannot use generics, and cannot use
-`Self` except in receiver position.
-
-When designing a trait, decide early on whether the trait will be used
-as an [object](objects.md) or as a [bound on generics](generics.md);
-the tradeoffs are discussed in each of the linked sections.
-
-If a trait is meant to be used as an object, its methods should take
-and return trait objects rather than use generics.
-
-
-### Default methods [FIXME]
-
-> **[FIXME]** Guidelines for default methods.
diff --git a/src/doc/style/features/traits/common.md b/src/doc/style/features/traits/common.md
deleted file mode 100644 (file)
index e8699c7..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-% Common traits
-
-### Eagerly implement common traits. [FIXME: needs RFC]
-
-Rust's trait system does not allow _orphans_: roughly, every `impl` must live
-either in the crate that defines the trait or the implementing
-type. Consequently, crates that define new types should eagerly implement all
-applicable, common traits.
-
-To see why, consider the following situation:
-
-* Crate `std` defines trait `Debug`.
-* Crate `url` defines type `Url`, without implementing `Debug`.
-* Crate `webapp` imports from both `std` and `url`,
-
-There is no way for `webapp` to add `Debug` to `url`, since it defines neither.
-(Note: the newtype pattern can provide an efficient, but inconvenient
-workaround; see [newtype for views](../types/newtype.md))
-
-The most important common traits to implement from `std` are:
-
-```text
-Clone, Debug, Hash, Eq
-```
-
-#### When safe, derive or otherwise implement `Send` and `Share`. [FIXME]
-
-> **[FIXME]**. This guideline is in flux while the "opt-in" nature of
-> built-in traits is being decided. See https://github.com/rust-lang/rfcs/pull/127
-
-### Prefer to derive, rather than implement. [FIXME: needs RFC]
-
-Deriving saves implementation effort, makes correctness trivial, and
-automatically adapts to upstream changes.
-
-### Do not overload operators in surprising ways. [FIXME: needs RFC]
-
-Operators with built in syntax (`*`, `|`, and so on) can be provided for a type
-by implementing the traits in `core::ops`. These operators come with strong
-expectations: implement `Mul` only for an operation that bears some resemblance
-to multiplication (and shares the expected properties, e.g. associativity), and
-so on for the other traits.
-
-### The `Drop` trait
-
-The `Drop` trait is treated specially by the compiler as a way of
-associating destructors with types. See
-[the section on destructors](../../ownership/destructors.md) for
-guidance.
-
-### The `Deref`/`DerefMut` traits
-
-#### Use `Deref`/`DerefMut` only for smart pointers. [FIXME: needs RFC]
-
-The `Deref` traits are used implicitly by the compiler in many circumstances,
-and interact with method resolution. The relevant rules are designed
-specifically to accommodate smart pointers, and so the traits should be used
-only for that purpose.
-
-#### Do not fail within a `Deref`/`DerefMut` implementation. [FIXME: needs RFC]
-
-Because the `Deref` traits are invoked implicitly by the compiler in sometimes
-subtle ways, failure during dereferencing can be extremely confusing. If a
-dereference might not succeed, target the `Deref` trait as a `Result` or
-`Option` type instead.
-
-#### Avoid inherent methods when implementing `Deref`/`DerefMut` [FIXME: needs RFC]
-
-The rules around method resolution and `Deref` are in flux, but inherent methods
-on a type implementing `Deref` are likely to shadow any methods of the referent
-with the same name.
diff --git a/src/doc/style/features/traits/extensions.md b/src/doc/style/features/traits/extensions.md
deleted file mode 100644 (file)
index fc3a03c..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-% Using traits to add extension methods
-
-> **[FIXME]** Elaborate.
-
-### Consider using default methods rather than extension traits **[FIXME]**
-
-> **[FIXME]** Elaborate.
diff --git a/src/doc/style/features/traits/generics.md b/src/doc/style/features/traits/generics.md
deleted file mode 100644 (file)
index f9dac12..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-% Using traits for bounds on generics
-
-The most widespread use of traits is for writing generic functions or types. For
-example, the following signature describes a function for consuming any iterator
-yielding items of type `A` to produce a collection of `A`:
-
-```rust,ignore
-fn from_iter<T: Iterator<A>>(iterator: T) -> SomeCollection<A>
-```
-
-Here, the `Iterator` trait specifies an interface that a type `T` must
-explicitly implement to be used by this generic function.
-
-**Pros**:
-
-* _Reusability_. Generic functions can be applied to an open-ended collection of
-  types, while giving a clear contract for the functionality those types must
-  provide.
-* _Static dispatch and optimization_. Each use of a generic function is
-  specialized ("monomorphized") to the particular types implementing the trait
-  bounds, which means that (1) invocations of trait methods are static, direct
-  calls to the implementation and (2) the compiler can inline and otherwise
-  optimize these calls.
-* _Inline layout_. If a `struct` and `enum` type is generic over some type
-  parameter `T`, values of type `T` will be laid out _inline_ in the
-  `struct`/`enum`, without any indirection.
-* _Inference_. Since the type parameters to generic functions can usually be
-  inferred, generic functions can help cut down on verbosity in code where
-  explicit conversions or other method calls would usually be necessary. See the
-  overloading/implicits use case below.
-* _Precise types_. Because generics give a _name_ to the specific type
-  implementing a trait, it is possible to be precise about places where that
-  exact type is required or produced. For example, a function
-
-  ```rust,ignore
-  fn binary<T: Trait>(x: T, y: T) -> T
-  ```
-
-  is guaranteed to consume and produce elements of exactly the same type `T`; it
-  cannot be invoked with parameters of different types that both implement
-  `Trait`.
-
-**Cons**:
-
-* _Code size_. Specializing generic functions means that the function body is
-  duplicated. The increase in code size must be weighed against the performance
-  benefits of static dispatch.
-* _Homogeneous types_. This is the other side of the "precise types" coin: if
-  `T` is a type parameter, it stands for a _single_ actual type. So for example
-  a `Vec<T>` contains elements of a single concrete type (and, indeed, the
-  vector representation is specialized to lay these out in line). Sometimes
-  heterogeneous collections are useful; see
-  trait objects below.
-* _Signature verbosity_. Heavy use of generics can bloat function signatures.
-  **[Ed. note]** This problem may be mitigated by some language improvements; stay tuned.
-
-### Favor widespread traits. **[FIXME: needs RFC]**
-
-Generic types are a form of abstraction, which entails a mental indirection: if
-a function takes an argument of type `T` bounded by `Trait`, clients must first
-think about the concrete types that implement `Trait` to understand how and when
-the function is callable.
-
-To keep the cost of abstraction low, favor widely-known traits. Whenever
-possible, implement and use traits provided as part of the standard library.  Do
-not introduce new traits for generics lightly; wait until there are a wide range
-of types that can implement the type.
diff --git a/src/doc/style/features/traits/objects.md b/src/doc/style/features/traits/objects.md
deleted file mode 100644 (file)
index 34712ed..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-% Using trait objects
-
-> **[FIXME]** What are uses of trait objects other than heterogeneous collections?
-
-Trait objects are useful primarily when _heterogeneous_ collections of objects
-need to be treated uniformly; it is the closest that Rust comes to
-object-oriented programming.
-
-```rust,ignore
-struct Frame  { ... }
-struct Button { ... }
-struct Label  { ... }
-
-trait Widget  { ... }
-
-impl Widget for Frame  { ... }
-impl Widget for Button { ... }
-impl Widget for Label  { ... }
-
-impl Frame {
-    fn new(contents: &[Box<Widget>]) -> Frame {
-        ...
-    }
-}
-
-fn make_gui() -> Box<Widget> {
-    let b: Box<Widget> = box Button::new(...);
-    let l: Box<Widget> = box Label::new(...);
-
-    box Frame::new([b, l]) as Box<Widget>
-}
-```
-
-By using trait objects, we can set up a GUI framework with a `Frame` widget that
-contains a heterogeneous collection of children widgets.
-
-**Pros**:
-
-* _Heterogeneity_. When you need it, you really need it.
-* _Code size_. Unlike generics, trait objects do not generate specialized
-  (monomorphized) versions of code, which can greatly reduce code size.
-
-**Cons**:
-
-* _No generic methods_. Trait objects cannot currently provide generic methods.
-* _Dynamic dispatch and fat pointers_. Trait objects inherently involve
-  indirection and vtable dispatch, which can carry a performance penalty.
-* _No Self_. Except for the method receiver argument, methods on trait objects
-  cannot use the `Self` type.
diff --git a/src/doc/style/features/traits/overloading.md b/src/doc/style/features/traits/overloading.md
deleted file mode 100644 (file)
index d7482c9..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-% Using traits for overloading
-
-> **[FIXME]** Elaborate.
-
-> **[FIXME]** We need to decide on guidelines for this use case. There are a few
-> patterns emerging in current Rust code, but it's not clear how widespread they
-> should be.
diff --git a/src/doc/style/features/traits/reuse.md b/src/doc/style/features/traits/reuse.md
deleted file mode 100644 (file)
index feedd39..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-% Using traits to share implementations
-
-> **[FIXME]** Elaborate.
-
-> **[FIXME]** We probably want to discourage this, at least when used in a way
-> that is publicly exposed.
-
-Traits that provide default implementations for function can provide code reuse
-across types. For example, a `print` method can be defined across multiple
-types as follows:
-
-``` Rust
-trait Printable {
-    // Default method implementation
-    fn print(&self) { println!("{:?}", *self) }
-}
-
-impl Printable for i32 {}
-
-impl Printable for String {
-    fn print(&self) { println!("{}", *self) }
-}
-
-impl Printable for bool {}
-
-impl Printable for f32 {}
-```
-
-This allows the implementation of `print` to be shared across types, yet
-overridden where needed, as seen in the `impl` for `String`.
diff --git a/src/doc/style/features/types/README.md b/src/doc/style/features/types/README.md
deleted file mode 100644 (file)
index d3b95d8..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-% Data types
-
-### Use custom types to imbue meaning; do not abuse `bool`, `Option` or other core types. **[FIXME: needs RFC]**
-
-Prefer
-
-```rust,ignore
-let w = Widget::new(Small, Round)
-```
-
-over
-
-```rust,ignore
-let w = Widget::new(true, false)
-```
-
-Core types like `bool`, `u8` and `Option` have many possible interpretations.
-
-Use custom types (whether `enum`s, `struct`, or tuples) to convey
-interpretation and invariants. In the above example,
-it is not immediately clear what `true` and `false` are conveying without
-looking up the argument names, but `Small` and `Round` are more suggestive.
-
-Using custom types makes it easier to expand the
-options later on, for example by adding an `ExtraLarge` variant.
-
-See [the newtype pattern](newtype.md) for a no-cost way to wrap
-existing types with a distinguished name.
-
-### Prefer private fields, except for passive data. **[FIXME: needs RFC]**
-
-Making a field public is a strong commitment: it pins down a representation
-choice, _and_ prevents the type from providing any validation or maintaining any
-invariants on the contents of the field, since clients can mutate it arbitrarily.
-
-Public fields are most appropriate for `struct` types in the C spirit: compound,
-passive data structures. Otherwise, consider providing getter/setter methods
-and hiding fields instead.
-
-> **[FIXME]** Cross-reference validation for function arguments.
-
-### Use custom `enum`s for alternatives, `bitflags` for C-style flags. **[FIXME: needs RFC]**
-
-Rust supports `enum` types with "custom discriminants":
-
-~~~~
-enum Color {
-  Red = 0xff0000,
-  Green = 0x00ff00,
-  Blue = 0x0000ff
-}
-~~~~
-
-Custom discriminants are useful when an `enum` type needs to be serialized to an
-integer value compatibly with some other system/language. They support
-"typesafe" APIs: by taking a `Color`, rather than an integer, a function is
-guaranteed to get well-formed inputs, even if it later views those inputs as
-integers.
-
-An `enum` allows an API to request exactly one choice from among many. Sometimes
-an API's input is instead the presence or absence of a set of flags. In C code,
-this is often done by having each flag correspond to a particular bit, allowing
-a single integer to represent, say, 32 or 64 flags. Rust's `std::bitflags`
-module provides a typesafe way for doing so.
-
-### Phantom types. [FIXME]
-
-> **[FIXME]** Add some material on phantom types (https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/)
diff --git a/src/doc/style/features/types/conversions.md b/src/doc/style/features/types/conversions.md
deleted file mode 100644 (file)
index f0f230f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-% Conversions between types
-
-### Associate conversions with the most specific type involved. **[FIXME: needs RFC]**
-
-When in doubt, prefer `to_`/`as_`/`into_` to `from_`, because they are
-more ergonomic to use (and can be chained with other methods).
-
-For many conversions between two types, one of the types is clearly more
-"specific": it provides some additional invariant or interpretation that is not
-present in the other type. For example, `str` is more specific than `&[u8]`,
-since it is a utf-8 encoded sequence of bytes.
-
-Conversions should live with the more specific of the involved types. Thus,
-`str` provides both the `as_bytes` method and the `from_utf8` constructor for
-converting to and from `&[u8]` values. Besides being intuitive, this convention
-avoids polluting concrete types like `&[u8]` with endless conversion methods.
-
-### Explicitly mark lossy conversions, or do not label them as conversions. **[FIXME: needs RFC]**
-
-If a function's name implies that it is a conversion (prefix `from_`, `as_`,
-`to_` or `into_`), but the function loses information, add a suffix `_lossy` or
-otherwise indicate the lossyness. Consider avoiding the conversion name prefix.
diff --git a/src/doc/style/features/types/newtype.md b/src/doc/style/features/types/newtype.md
deleted file mode 100644 (file)
index 9646e3e..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-% The newtype pattern
-
-A "newtype" is a tuple or `struct` with a single field. The terminology is borrowed from Haskell.
-
-Newtypes are a zero-cost abstraction: they introduce a new, distinct name for an
-existing type, with no runtime overhead when converting between the two types.
-
-### Use newtypes to provide static distinctions. [FIXME: needs RFC]
-
-Newtypes can statically distinguish between different interpretations of an
-underlying type.
-
-For example, a `f64` value might be used to represent a quantity in miles or in
-kilometers. Using newtypes, we can keep track of the intended interpretation:
-
-```rust,ignore
-struct Miles(pub f64);
-struct Kilometers(pub f64);
-
-impl Miles {
-    fn as_kilometers(&self) -> Kilometers { ... }
-}
-impl Kilometers {
-    fn as_miles(&self) -> Miles { ... }
-}
-```
-
-Once we have separated these two types, we can statically ensure that we do not
-confuse them. For example, the function
-
-```rust,ignore
-fn are_we_there_yet(distance_travelled: Miles) -> bool { ... }
-```
-
-cannot accidentally be called with a `Kilometers` value. The compiler will
-remind us to perform the conversion, thus averting certain
-[catastrophic bugs](http://en.wikipedia.org/wiki/Mars_Climate_Orbiter).
-
-### Use newtypes with private fields for hiding. [FIXME: needs RFC]
-
-A newtype can be used to hide representation details while making precise
-promises to the client.
-
-For example, consider a function `my_transform` that returns a compound iterator
-type `Enumerate<Skip<vec::MoveItems<T>>>`. We wish to hide this type from the
-client, so that the client's view of the return type is roughly `Iterator<(usize,
-T)>`. We can do so using the newtype pattern:
-
-```rust,ignore
-struct MyTransformResult<T>(Enumerate<Skip<vec::MoveItems<T>>>);
-impl<T> Iterator<(usize, T)> for MyTransformResult<T> { ... }
-
-fn my_transform<T, Iter: Iterator<T>>(iter: Iter) -> MyTransformResult<T> {
-    ...
-}
-```
-
-Aside from simplifying the signature, this use of newtypes allows us to make a
-expose and promise less to the client. The client does not know _how_ the result
-iterator is constructed or represented, which means the representation can
-change in the future without breaking client code.
-
-> **[FIXME]** Interaction with auto-deref.
-
-### Use newtypes to provide cost-free _views_ of another type. **[FIXME]**
-
-> **[FIXME]** Describe the pattern of using newtypes to provide a new set of
-> inherent or trait methods, providing a different perspective on the underlying
-> type.
diff --git a/src/doc/style/ownership/README.md b/src/doc/style/ownership/README.md
deleted file mode 100644 (file)
index 11bdb03..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-% Ownership and resource management
-
-> **[FIXME]** Add general remarks about ownership/resources here.
diff --git a/src/doc/style/ownership/builders.md b/src/doc/style/ownership/builders.md
deleted file mode 100644 (file)
index 3422591..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-% The builder pattern
-
-Some data structures are complicated to construct, due to their construction needing:
-
-* a large number of inputs
-* compound data (e.g. slices)
-* optional configuration data
-* choice between several flavors
-
-which can easily lead to a large number of distinct constructors with
-many arguments each.
-
-If `T` is such a data structure, consider introducing a `T` _builder_:
-
-1. Introduce a separate data type `TBuilder` for incrementally configuring a `T`
-   value. When possible, choose a better name: e.g. `Command` is the builder for
-   `Process`.
-2. The builder constructor should take as parameters only the data _required_ to
-   make a `T`.
-3. The builder should offer a suite of convenient methods for configuration,
-   including setting up compound inputs (like slices) incrementally.
-   These methods should return `self` to allow chaining.
-4. The builder should provide one or more "_terminal_" methods for actually building a `T`.
-
-The builder pattern is especially appropriate when building a `T` involves side
-effects, such as spawning a thread or launching a process.
-
-In Rust, there are two variants of the builder pattern, differing in the
-treatment of ownership, as described below.
-
-### Non-consuming builders (preferred):
-
-In some cases, constructing the final `T` does not require the builder itself to
-be consumed. The follow variant on
-[`std::process::Command`](https://doc.rust-lang.org/stable/std/process/struct.Command.html)
-is one example:
-
-```rust,ignore
-// NOTE: the actual Command API does not use owned Strings;
-// this is a simplified version.
-
-pub struct Command {
-    program: String,
-    args: Vec<String>,
-    cwd: Option<String>,
-    // etc
-}
-
-impl Command {
-    pub fn new(program: String) -> Command {
-        Command {
-            program: program,
-            args: Vec::new(),
-            cwd: None,
-        }
-    }
-
-    /// Add an argument to pass to the program.
-    pub fn arg<'a>(&'a mut self, arg: String) -> &'a mut Command {
-        self.args.push(arg);
-        self
-    }
-
-    /// Add multiple arguments to pass to the program.
-    pub fn args<'a>(&'a mut self, args: &[String])
-                    -> &'a mut Command {
-        self.args.push_all(args);
-        self
-    }
-
-    /// Set the working directory for the child process.
-    pub fn cwd<'a>(&'a mut self, dir: String) -> &'a mut Command {
-        self.cwd = Some(dir);
-        self
-    }
-
-    /// Executes the command as a child process, which is returned.
-    pub fn spawn(&self) -> std::io::Result<Process> {
-        ...
-    }
-}
-```
-
-Note that the `spawn` method, which actually uses the builder configuration to
-spawn a process, takes the builder by immutable reference. This is possible
-because spawning the process does not require ownership of the configuration
-data.
-
-Because the terminal `spawn` method only needs a reference, the configuration
-methods take and return a mutable borrow of `self`.
-
-#### The benefit
-
-By using borrows throughout, `Command` can be used conveniently for both
-one-liner and more complex constructions:
-
-```rust,ignore
-// One-liners
-Command::new("/bin/cat").arg("file.txt").spawn();
-
-// Complex configuration
-let mut cmd = Command::new("/bin/ls");
-cmd.arg(".");
-
-if size_sorted {
-    cmd.arg("-S");
-}
-
-cmd.spawn();
-```
-
-### Consuming builders:
-
-Sometimes builders must transfer ownership when constructing the final type
-`T`, meaning that the terminal methods must take `self` rather than `&self`:
-
-```rust,ignore
-// A simplified excerpt from std::thread::Builder
-
-impl ThreadBuilder {
-    /// Name the thread-to-be. Currently the name is used for identification
-    /// only in failure messages.
-    pub fn named(mut self, name: String) -> ThreadBuilder {
-        self.name = Some(name);
-        self
-    }
-
-    /// Redirect thread-local stdout.
-    pub fn stdout(mut self, stdout: Box<Writer + Send>) -> ThreadBuilder {
-        self.stdout = Some(stdout);
-        //   ^~~~~~ this is owned and cannot be cloned/re-used
-        self
-    }
-
-    /// Creates and executes a new child thread.
-    pub fn spawn(self, f: proc():Send) {
-        // consume self
-        ...
-    }
-}
-```
-
-Here, the `stdout` configuration involves passing ownership of a `Writer`,
-which must be transferred to the thread upon construction (in `spawn`).
-
-When the terminal methods of the builder require ownership, there is a basic tradeoff:
-
-* If the other builder methods take/return a mutable borrow, the complex
-  configuration case will work well, but one-liner configuration becomes
-  _impossible_.
-
-* If the other builder methods take/return an owned `self`, one-liners
-  continue to work well but complex configuration is less convenient.
-
-Under the rubric of making easy things easy and hard things possible, _all_
-builder methods for a consuming builder should take and returned an owned
-`self`. Then client code works as follows:
-
-```rust,ignore
-// One-liners
-ThreadBuilder::new().named("my_thread").spawn(proc() { ... });
-
-// Complex configuration
-let mut thread = ThreadBuilder::new();
-thread = thread.named("my_thread_2"); // must re-assign to retain ownership
-
-if reroute {
-    thread = thread.stdout(mywriter);
-}
-
-thread.spawn(proc() { ... });
-```
-
-One-liners work as before, because ownership is threaded through each of the
-builder methods until being consumed by `spawn`. Complex configuration,
-however, is more verbose: it requires re-assigning the builder at each step.
diff --git a/src/doc/style/ownership/cell-smart.md b/src/doc/style/ownership/cell-smart.md
deleted file mode 100644 (file)
index cd027cc..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-% Cells and smart pointers
-
-> **[FIXME]** Add guidelines about when to use Cell, RefCell, Rc and
-> Arc (and how to use them together).
diff --git a/src/doc/style/ownership/constructors.md b/src/doc/style/ownership/constructors.md
deleted file mode 100644 (file)
index 51fc74a..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-% Constructors
-
-### Define constructors as static, inherent methods. [FIXME: needs RFC]
-
-In Rust, "constructors" are just a convention:
-
-```rust,ignore
-impl<T> Vec<T> {
-    pub fn new() -> Vec<T> { ... }
-}
-```
-
-Constructors are static (no `self`) inherent methods for the type that they
-construct. Combined with the practice of
-[fully importing type names](../style/imports.md), this convention leads to
-informative but concise construction:
-
-```rust,ignore
-use vec::Vec;
-
-// construct a new vector
-let mut v = Vec::new();
-```
-
-This convention also applied to conversion constructors (prefix `from` rather
-than `new`).
-
-### Provide constructors for passive `struct`s with defaults. [FIXME: needs RFC]
-
-Given the `struct`
-
-```rust,ignore
-pub struct Config {
-    pub color: Color,
-    pub size:  Size,
-    pub shape: Shape,
-}
-```
-
-provide a constructor if there are sensible defaults:
-
-```rust,ignore
-impl Config {
-    pub fn new() -> Config {
-        Config {
-            color: Brown,
-            size: Medium,
-            shape: Square,
-        }
-    }
-}
-```
-
-which then allows clients to concisely override using `struct` update syntax:
-
-```rust,ignore
-Config { color: Red, .. Config::new() };
-```
-
-See the [guideline for field privacy](../features/types/README.md) for
-discussion on when to create such "passive" `struct`s with public
-fields.
diff --git a/src/doc/style/ownership/destructors.md b/src/doc/style/ownership/destructors.md
deleted file mode 100644 (file)
index 1cfcd78..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-% Destructors
-
-Unlike constructors, destructors in Rust have a special status: they are added
-by implementing `Drop` for a type, and they are automatically invoked as values
-go out of scope.
-
-> **[FIXME]** This section needs to be expanded.
-
-### Destructors should not fail. [FIXME: needs RFC]
-
-Destructors are executed on thread failure, and in that context a failing
-destructor causes the program to abort.
-
-Instead of failing in a destructor, provide a separate method for checking for
-clean teardown, e.g. a `close` method, that returns a `Result` to signal
-problems.
-
-### Destructors should not block. [FIXME: needs RFC]
-
-Similarly, destructors should not invoke blocking operations, which can make
-debugging much more difficult. Again, consider providing a separate method for
-preparing for an infallible, nonblocking teardown.
diff --git a/src/doc/style/ownership/raii.md b/src/doc/style/ownership/raii.md
deleted file mode 100644 (file)
index 244e809..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-% RAII
-
-Resource Acquisition is Initialization
-
-> **[FIXME]** Explain the RAII pattern and give best practices.
-
-### Whenever possible, tie resource access to guard scopes [FIXME]
-
-> **[FIXME]** Example: Mutex guards guarantee that access to the
-> protected resource only happens when the guard is in scope.
-
-`must_use`
diff --git a/src/doc/style/platform.md b/src/doc/style/platform.md
deleted file mode 100644 (file)
index d29d060..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-% FFI and platform-specific code **[FIXME]**
-
-> **[FIXME]** Not sure where this should live.
-
-When writing cross-platform code, group platform-specific code into a
-module called `platform`. Avoid `#[cfg]` directives outside this
-`platform` module.
diff --git a/src/doc/style/safety/README.md b/src/doc/style/safety/README.md
deleted file mode 100644 (file)
index 1ac6e70..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-% Safety and guarantees
-
-> **[FIXME]** Is there a better phrase than "strong guarantees" that encompasses
-> both e.g. memory safety and e.g. data structure invariants?
-
-A _guarantee_ is a property that holds no matter what client code does, unless
-the client explicitly opts out:
-
-* Rust guarantees memory safety and data-race freedom, with `unsafe`
-  blocks as an opt-out mechanism.
-
-* APIs in Rust often provide their own guarantees. For example, `std::str`
-guarantees that its underlying buffer is valid utf-8. The `std::path::Path` type
-guarantees no interior nulls. Both strings and paths provide `unsafe` mechanisms
-for opting out of these guarantees (and thereby avoiding runtime checks).
-
-Thinking about guarantees is an essential part of writing good Rust code.  The
-rest of this subsection outlines some cross-cutting principles around
-guarantees.
diff --git a/src/doc/style/safety/lib-guarantees.md b/src/doc/style/safety/lib-guarantees.md
deleted file mode 100644 (file)
index 8ee64f1..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-% Library-level guarantees
-
-Most libraries rely on internal invariants, e.g. about their data, resource
-ownership, or protocol states. In Rust, broken invariants cannot produce
-segfaults, but they can still lead to wrong answers.
-
-### Provide library-level guarantees whenever practical. **[FIXME: needs RFC]**
-
-Library-level invariants should be turned into guarantees whenever
-practical. They should hold no matter what the client does, modulo
-explicit opt-outs. Depending on the kind of invariant, this can be
-achieved through a combination of static and dynamic enforcement, as
-described below.
-
-#### Static enforcement:
-
-Guaranteeing invariants almost always requires _hiding_,
-i.e. preventing the client from directly accessing or modifying
-internal data.
-
-For example, the representation of the `str` type is hidden,
-which means that any value of type `str` must have been produced
-through an API under the control of the `str` module, and these
-APIs in turn ensure valid utf-8 encoding.
-
-Rust's type system makes it possible to provide guarantees even while
-revealing more of the representation than usual. For example, the
-`as_bytes()` method on `&str` gives a _read-only_ view into the
-underlying buffer, which cannot be used to violate the utf-8 property.
-
-#### Dynamic enforcement:
-
-Malformed inputs from the client are hazards to library-level
-guarantees, so library APIs should validate their input.
-
-For example, `std::str::from_utf8_owned` attempts to convert a `u8`
-slice into an owned string, but dynamically checks that the slice is
-valid utf-8 and returns `Err` if not.
-
-See
-[the discussion on input validation](../features/functions-and-methods/input.md)
-for more detail.
-
-
-### Prefer static enforcement of guarantees. **[FIXME: needs RFC]**
-
-Static enforcement provides two strong benefits over dynamic enforcement:
-
-* Bugs are caught at compile time.
-* There is no runtime cost.
-
-Sometimes purely static enforcement is impossible or impractical. In these
-cases, a library should check as much as possible statically, but defer to
-dynamic checks where needed.
-
-For example, the `std::string` module exports a `String` type with the guarantee
-that all instances are valid utf-8:
-
-* Any _consumer_ of a `String` is statically guaranteed utf-8 contents. For example,
-  the `append` method can push a `&str` onto the end of a `String` without
-  checking anything dynamically, since the existing `String` and `&str` are
-  statically guaranteed to be in utf-8.
-
-* Some _producers_ of a `String` must perform dynamic checks. For example, the
-  `from_utf8` function attempts to convert a `Vec<u8>` into a `String`, but
-  dynamically checks that the contents are utf-8.
-
-### Provide opt-outs with caution; make them explicit. **[FIXME: needs RFC]**
-
-Providing library-level guarantees sometimes entails inconvenience (for static
-checks) or overhead (for dynamic checks). So it is sometimes desirable to allow
-clients to sidestep this checking, while promising to use the API in a way that
-still provides the guarantee. Such escape hatches should only be introduced when
-there is a demonstrated need for them.
-
-It should be trivial for clients to audit their use of the library for
-escape hatches.
-
-See
-[the discussion on input validation](../features/functions-and-methods/input.md)
-for conventions on marking opt-out functions.
diff --git a/src/doc/style/safety/unsafe.md b/src/doc/style/safety/unsafe.md
deleted file mode 100644 (file)
index a8a50af..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-% Using `unsafe`
-
-### Unconditionally guarantee safety, or mark API as `unsafe`. **[FIXME: needs RFC]**
-
-Memory safety, type safety, and data race freedom are basic assumptions for all
-Rust code.
-
-APIs that use `unsafe` blocks internally thus have two choices:
-
-* They can guarantee safety _unconditionally_ (i.e., regardless of client
-  behavior or inputs) and be exported as safe code. Any safety violation is then
-  the library's fault, not the client's fault.
-
-* They can export potentially unsafe functions with the `unsafe` qualifier. In
-  this case, the documentation should make very clear the conditions under which
-  safety is guaranteed.
-
-The result is that a client program can never violate safety merely by having a
-bug; it must have explicitly opted out by using an `unsafe` block.
-
-Of the two options for using `unsafe`, creating such safe abstractions (the
-first option above) is strongly preferred.
diff --git a/src/doc/style/style/README.md b/src/doc/style/style/README.md
deleted file mode 100644 (file)
index 8744971..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-% Style
-
-This section gives a set of strict rules for styling Rust code.
-
-> **[FIXME]** General remarks about the style guidelines
diff --git a/src/doc/style/style/braces.md b/src/doc/style/style/braces.md
deleted file mode 100644 (file)
index 80323db..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-% Braces, semicolons, and commas [FIXME: needs RFC]
-
-### Opening braces always go on the same line.
-
-```rust,ignore
-fn foo() {
-    ...
-}
-
-fn frobnicate(a: Bar, b: Bar,
-              c: Bar, d: Bar)
-              -> Bar {
-    ...
-}
-
-trait Bar {
-    fn baz(&self);
-}
-
-impl Bar for Baz {
-    fn baz(&self) {
-        ...
-    }
-}
-
-frob(|x| {
-    x.transpose()
-})
-```
-
-### `match` arms get braces, except for single-line expressions.
-
-```rust,ignore
-match foo {
-    bar => baz,
-    quux => {
-        do_something();
-        do_something_else()
-    }
-}
-```
-
-### `return` statements get semicolons.
-
-```rust,ignore
-fn foo() {
-    do_something();
-
-    if condition() {
-        return;
-    }
-
-    do_something_else();
-}
-```
-
-### Trailing commas
-
-> **[FIXME]** We should have a guideline for when to include trailing
-> commas in `struct`s, `match`es, function calls, etc.
->
-> One possible rule: a trailing comma should be included whenever the
-> closing delimiter appears on a separate line:
-
-```rust,ignore
-Foo { bar: 0, baz: 1 }
-
-Foo {
-    bar: 0,
-    baz: 1,
-}
-
-match a_thing {
-    None => 0,
-    Some(x) => 1,
-}
-```
diff --git a/src/doc/style/style/comments.md b/src/doc/style/style/comments.md
deleted file mode 100644 (file)
index af02d87..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-% Comments [RFC #505]
-
-### Avoid block comments.
-
-Use line comments:
-
-```rust
-// Wait for the main thread to return, and set the process error code
-// appropriately.
-```
-
-Instead of:
-
-``` rust
-/*
- * Wait for the main thread to return, and set the process error code
- * appropriately.
- */
-```
-
-## Doc comments
-
-Doc comments are prefixed by three slashes (`///`) and indicate
-documentation that you would like to be included in Rustdoc's output.
-They support
-[Markdown syntax](https://en.wikipedia.org/wiki/Markdown)
-and are the main way of documenting your public APIs.
-
-The supported markdown syntax includes all of the extensions listed in the
-[GitHub Flavored Markdown]
-(https://help.github.com/articles/github-flavored-markdown) documentation,
-plus superscripts.
-
-### Summary line
-
-The first line in any doc comment should be a single-line short sentence
-providing a summary of the code. This line is used as a short summary
-description throughout Rustdoc's output, so it's a good idea to keep it
-short.
-
-### Sentence structure
-
-All doc comments, including the summary line, should begin with a
-capital letter and end with a period, question mark, or exclamation
-point. Prefer full sentences to fragments.
-
-The summary line should be written in
-[third person singular present indicative form]
-(http://en.wikipedia.org/wiki/English_verbs#Third_person_singular_present).
-Basically, this means write "Returns" instead of "Return".
-
-For example:
-
-```rust,ignore
-/// Sets up a default runtime configuration, given compiler-supplied arguments.
-///
-/// This function will block until the entire pool of M:N schedulers has
-/// exited. This function also requires a local thread to be available.
-///
-/// # Arguments
-///
-/// * `argc` & `argv` - The argument vector. On Unix this information is used
-///                     by `os::args`.
-/// * `main` - The initial procedure to run inside of the M:N scheduling pool.
-///            Once this procedure exits, the scheduling pool will begin to shut
-///            down. The entire pool (and this function) will only return once
-///            all child threads have finished executing.
-///
-/// # Return value
-///
-/// The return value is used as the process return code. 0 on success, 101 on
-/// error.
-```
-
-### Code snippets
-
-Only use inner doc comments `//!` to write crate and module-level documentation,
-nothing else. When using `mod` blocks, prefer `///` outside of the block:
-
-```rust
-/// This module contains tests
-mod test {
-    // ...
-}
-```
-
-over
-
-```rust
-mod test {
-    //! This module contains tests
-
-    // ...
-}
-```
-
-### Avoid inner doc comments.
-
-Use inner doc comments _only_ to document crates and file-level modules:
-
-```rust,ignore
-//! The core library.
-//!
-//! The core library is a something something...
-```
-
-### Explain context.
-
-Rust doesn't have special constructors, only functions that return new
-instances.  These aren't visible in the automatically generated documentation
-for a type, so you should specifically link to them:
-
-```rust,ignore
-/// An iterator that yields `None` forever after the underlying iterator
-/// yields `None` once.
-///
-/// These can be created through
-/// [`iter.fuse()`](trait.Iterator.html#method.fuse).
-pub struct Fuse<I> {
-    // ...
-}
-```
diff --git a/src/doc/style/style/features.md b/src/doc/style/style/features.md
deleted file mode 100644 (file)
index 13cc37f..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-## `return` [RFC #968]
-
-Terminate `return` statements with semicolons:
-
-``` rust,ignore
-fn foo(bar: i32) -> Option<i32> {
-    if some_condition() {
-        return None;
-    }
-
-    ...
-}
-```
diff --git a/src/doc/style/style/imports.md b/src/doc/style/style/imports.md
deleted file mode 100644 (file)
index c958875..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-% Imports [FIXME: needs RFC]
-
-The imports of a crate/module should consist of the following
-sections, in order, with a blank space between each:
-
-* `extern crate` directives
-* external `use` imports
-* local `use` imports
-* `pub use` imports
-
-For example:
-
-```rust,ignore
-// Crates.
-extern crate getopts;
-extern crate mylib;
-
-// Standard library imports.
-use getopts::{optopt, getopts};
-use std::os;
-
-// Import from a library that we wrote.
-use mylib::webserver;
-
-// Will be reexported when we import this module.
-pub use self::types::Webdata;
-```
-
-### Avoid `use *`, except in tests.
-
-Glob imports have several downsides:
-* They make it harder to tell where names are bound.
-* They are forwards-incompatible, since new upstream exports can clash
-  with existing names.
-
-When writing a [`test` submodule](../testing/README.md), importing `super::*` is appropriate
-as a convenience.
-
-### Prefer fully importing types/traits while module-qualifying functions.
-
-For example:
-
-```rust,ignore
-use option::Option;
-use mem;
-
-let i: isize = mem::transmute(Option(0));
-```
-
-> **[FIXME]** Add rationale.
diff --git a/src/doc/style/style/naming/README.md b/src/doc/style/style/naming/README.md
deleted file mode 100644 (file)
index 6d88a83..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-% Naming conventions
-
-### General conventions [RFC #430]
-
-> The guidelines below were approved by [RFC #430](https://github.com/rust-lang/rfcs/pull/430).
-
-In general, Rust tends to use `CamelCase` for "type-level" constructs
-(types and traits) and `snake_case` for "value-level" constructs. More
-precisely:
-
-| Item | Convention |
-| ---- | ---------- |
-| Crates | `snake_case` (but prefer single word) |
-| Modules | `snake_case` |
-| Types | `CamelCase` |
-| Traits | `CamelCase` |
-| Enum variants | `CamelCase` |
-| Functions | `snake_case` |
-| Methods | `snake_case` |
-| General constructors | `new` or `with_more_details` |
-| Conversion constructors | `from_some_other_type` |
-| Local variables | `snake_case` |
-| Static variables | `SCREAMING_SNAKE_CASE` |
-| Constant variables | `SCREAMING_SNAKE_CASE` |
-| Type parameters | concise `CamelCase`, usually single uppercase letter: `T` |
-| Lifetimes | short, lowercase: `'a` |
-
-<p>
-In `CamelCase`, acronyms count as one word: use `Uuid` rather than
-`UUID`.  In `snake_case`, acronyms are lower-cased: `is_xid_start`.
-
-In `snake_case` or `SCREAMING_SNAKE_CASE`, a "word" should never
-consist of a single letter unless it is the last "word". So, we have
-`btree_map` rather than `b_tree_map`, but `PI_2` rather than `PI2`.
-
-### Referring to types in function/method names [RFC 344]
-
-> The guidelines below were approved by [RFC #344](https://github.com/rust-lang/rfcs/pull/344).
-
-Function names often involve type names, the most common example being conversions
-like `as_slice`. If the type has a purely textual name (ignoring parameters), it
-is straightforward to convert between type conventions and function conventions:
-
-Type name | Text in methods
---------- | ---------------
-`String`  | `string`
-`Vec<T>`  | `vec`
-`YourType`| `your_type`
-
-Types that involve notation follow the convention below. There is some
-overlap on these rules; apply the most specific applicable rule:
-
-Type name | Text in methods
---------- | ---------------
-`&str`    | `str`
-`&[T]`    | `slice`
-`&mut [T]`| `mut_slice`
-`&[u8]`   | `bytes`
-`&T`      | `ref`
-`&mut T`  | `mut`
-`*const T`| `ptr`
-`*mut T`  | `mut_ptr`
-
-### Avoid redundant prefixes [RFC 356]
-
-> The guidelines below were approved by [RFC #356](https://github.com/rust-lang/rfcs/pull/356).
-
-Names of items within a module should not be prefixed with that module's name:
-
-Prefer
-
-```rust,ignore
-mod foo {
-    pub struct Error { ... }
-}
-```
-
-over
-
-```rust,ignore
-mod foo {
-    pub struct FooError { ... }
-}
-```
-
-This convention avoids stuttering (like `io::IoError`). Library clients can
-rename on import to avoid clashes.
-
-### Getter/setter methods [RFC 344]
-
-> The guidelines below were approved by [RFC #344](https://github.com/rust-lang/rfcs/pull/344).
-
-Some data structures do not wish to provide direct access to their fields, but
-instead offer "getter" and "setter" methods for manipulating the field state
-(often providing checking or other functionality).
-
-The convention for a field `foo: T` is:
-
-* A method `foo(&self) -> &T` for getting the current value of the field.
-* A method `set_foo(&self, val: T)` for setting the field. (The `val` argument
-  here may take `&T` or some other type, depending on the context.)
-
-Note that this convention is about getters/setters on ordinary data types, *not*
-on [builder objects](../../ownership/builders.html).
-
-### Escape hatches [FIXME]
-
-> **[FIXME]** Should we standardize a convention for functions that may break API
-> guarantees? e.g. `ToCStr::to_c_str_unchecked`
-
-### Predicates
-
-* Simple boolean predicates should be prefixed with `is_` or another
-  short question word, e.g., `is_empty`.
-* Common exceptions: `lt`, `gt`, and other established predicate names.
diff --git a/src/doc/style/style/naming/containers.md b/src/doc/style/style/naming/containers.md
deleted file mode 100644 (file)
index c352a5b..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-% Common container/wrapper methods [FIXME: needs RFC]
-
-Containers, wrappers, and cells all provide ways to access the data
-they enclose.  Accessor methods often have variants to access the data
-by value, by reference, and by mutable reference.
-
-In general, the `get` family of methods is used to access contained
-data without any risk of thread failure; they return `Option` as
-appropriate. This name is chosen rather than names like `find` or
-`lookup` because it is appropriate for a wider range of container types.
-
-#### Containers
-
-For a container with keys/indexes of type `K` and elements of type `V`:
-
-```rust,ignore
-// Look up element without failing
-fn get(&self, key: K) -> Option<&V>
-fn get_mut(&mut self, key: K) -> Option<&mut V>
-
-// Convenience for .get(key).map(|elt| elt.clone())
-fn get_clone(&self, key: K) -> Option<V>
-
-// Lookup element, failing if it is not found:
-impl Index<K, V> for Container { ... }
-impl IndexMut<K, V> for Container { ... }
-```
-
-#### Wrappers/Cells
-
-Prefer specific conversion functions like `as_bytes` or `into_vec` whenever
-possible. Otherwise, use:
-
-```rust,ignore
-// Extract contents without failing
-fn get(&self) -> &V
-fn get_mut(&mut self) -> &mut V
-fn unwrap(self) -> V
-```
-
-#### Wrappers/Cells around `Copy` data
-
-```rust,ignore
-// Extract contents without failing
-fn get(&self) -> V
-```
-
-#### `Option`-like types
-
-Finally, we have the cases of types like `Option` and `Result`, which
-play a special role for failure.
-
-For `Option<V>`:
-
-```rust,ignore
-// Extract contents or fail if not available
-fn assert(self) -> V
-fn expect(self, &str) -> V
-```
-
-For `Result<V, E>`:
-
-```rust,ignore
-// Extract the contents of Ok variant; fail if Err
-fn assert(self) -> V
-
-// Extract the contents of Err variant; fail if Ok
-fn assert_err(self) -> E
-```
diff --git a/src/doc/style/style/naming/conversions.md b/src/doc/style/style/naming/conversions.md
deleted file mode 100644 (file)
index 0287919..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-% Conversions [Rust issue #7087]
-
-> The guidelines below were approved by [rust issue #7087](https://github.com/rust-lang/rust/issues/7087).
-
-> **[FIXME]** Should we provide standard traits for conversions? Doing
-> so nicely will require
-> [trait reform](https://github.com/rust-lang/rfcs/pull/48) to land.
-
-Conversions should be provided as methods, with names prefixed as follows:
-
-| Prefix | Cost | Consumes convertee |
-| ------ | ---- | ------------------ |
-| `as_` | Free | No |
-| `to_` | Expensive | No |
-| `into_` | Variable | Yes |
-
-<p>
-For example:
-
-* `as_bytes()` gives a `&[u8]` view into a `&str`, which is a no-op.
-* `to_owned()` copies a `&str` to a new `String`.
-* `into_bytes()` consumes a `String` and yields the underlying
-  `Vec<u8>`, which is a no-op.
-
-Conversions prefixed `as_` and `into_` typically _decrease abstraction_, either
-exposing a view into the underlying representation (`as`) or deconstructing data
-into its underlying representation (`into`). Conversions prefixed `to_`, on the
-other hand, typically stay at the same level of abstraction but do some work to
-change one representation into another.
-
-> **[FIXME]** The distinctions between conversion methods does not work
-> so well for `from_` conversion constructors. Is that a problem?
diff --git a/src/doc/style/style/naming/iterators.md b/src/doc/style/style/naming/iterators.md
deleted file mode 100644 (file)
index 945cbe4..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-% Iterators
-
-#### Method names [RFC #199]
-
-> The guidelines below were approved by [RFC #199](https://github.com/rust-lang/rfcs/pull/199).
-
-For a container with elements of type `U`, iterator methods should be named:
-
-```rust,ignore
-fn iter(&self) -> T           // where T implements Iterator<&U>
-fn iter_mut(&mut self) -> T   // where T implements Iterator<&mut U>
-fn into_iter(self) -> T       // where T implements Iterator<U>
-```
-
-The default iterator variant yields shared references `&U`.
-
-#### Type names [RFC #344]
-
-> The guidelines below were approved by [RFC #344](https://github.com/rust-lang/rfcs/pull/344).
-
-The name of an iterator type should be the same as the method that
-produces the iterator.
-
-For example:
-
-* `iter` should yield an `Iter`
-* `iter_mut` should yield an `IterMut`
-* `into_iter` should yield an `IntoIter`
-* `keys` should yield `Keys`
-
-These type names make the most sense when prefixed with their owning module,
-e.g. `vec::IntoIter`.
diff --git a/src/doc/style/style/naming/ownership.md b/src/doc/style/style/naming/ownership.md
deleted file mode 100644 (file)
index 32cd8a1..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-% Ownership variants [RFC #199]
-
-> The guidelines below were approved by [RFC #199](https://github.com/rust-lang/rfcs/pull/199).
-
-Functions often come in multiple variants: immutably borrowed, mutably
-borrowed, and owned.
-
-The right default depends on the function in question. Variants should
-be marked through suffixes.
-
-#### Immutably borrowed by default
-
-If `foo` uses/produces an immutable borrow by default, use:
-
-* The `_mut` suffix (e.g. `foo_mut`) for the mutably borrowed variant.
-* The `_move` suffix (e.g. `foo_move`) for the owned variant.
-
-#### Owned by default
-
-If `foo` uses/produces owned data by default, use:
-
-* The `_ref` suffix (e.g. `foo_ref`) for the immutably borrowed variant.
-* The `_mut` suffix (e.g. `foo_mut`) for the mutably borrowed variant.
-
-#### Exceptions
-
-In the case of iterators, the moving variant can also be understood as
-an `into` conversion, `into_iter`, and `for x in v.into_iter()` reads
-arguably better than `for x in v.iter_move()`, so the convention is
-`into_iter`.
-
-For mutably borrowed variants, if the `mut` qualifier is part of a
-type name (e.g. `as_mut_slice`), it should appear as it would appear
-in the type.
diff --git a/src/doc/style/style/optional.md b/src/doc/style/style/optional.md
deleted file mode 100644 (file)
index d3c2178..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-*
-
-*
diff --git a/src/doc/style/style/organization.md b/src/doc/style/style/organization.md
deleted file mode 100644 (file)
index 8506540..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-% Organization [FIXME: needs RFC]
-
-> **[FIXME]** What else?
-
-### Reexport the most important types at the crate level.
-
-Crates `pub use` the most common types for convenience, so that clients do not
-have to remember or write the crate's module hierarchy to use these types.
-
-### Define types and operations together.
-
-Type definitions and the functions/methods that operate on them should be
-defined together in a single module, with the type appearing above the
-functions/methods.
diff --git a/src/doc/style/style/whitespace.md b/src/doc/style/style/whitespace.md
deleted file mode 100644 (file)
index c33c17c..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-% Whitespace [FIXME: needs RFC]
-
-* Lines must not exceed 99 characters.
-* Use 4 spaces for indentation, _not_ tabs.
-* No trailing whitespace at the end of lines or files.
-
-### Spaces
-
-* Use spaces around binary operators, including the equals sign in attributes:
-
-```rust,ignore
-#[deprecated = "Use `bar` instead."]
-fn foo(a: usize, b: usize) -> usize {
-    a + b
-}
-```
-
-* Use a space after colons and commas:
-
-```rust,ignore
-fn foo(a: Bar);
-
-MyStruct { foo: 3, bar: 4 }
-
-foo(bar, baz);
-```
-
-* Use a space after the opening and before the closing brace for
-  single line blocks or `struct` expressions:
-
-```rust,ignore
-spawn(proc() { do_something(); })
-
-Point { x: 0.1, y: 0.3 }
-```
-
-### Line wrapping
-
-* For multiline function signatures, each new line should align with the
-  first parameter. Multiple parameters per line are permitted:
-
-```rust,ignore
-fn frobnicate(a: Bar, b: Bar,
-              c: Bar, d: Bar)
-              -> Bar {
-    ...
-}
-
-fn foo<T: This,
-       U: That>(
-       a: Bar,
-       b: Bar)
-       -> Baz {
-    ...
-}
-```
-
-* Multiline function invocations generally follow the same rule as for
-  signatures. However, if the final argument begins a new block, the
-  contents of the block may begin on a new line, indented one level:
-
-```rust,ignore
-fn foo_bar(a: Bar, b: Bar,
-           c: |Bar|) -> Bar {
-    ...
-}
-
-// Same line is fine:
-foo_bar(x, y, |z| { z.transpose(y) });
-
-// Indented body on new line is also fine:
-foo_bar(x, y, |z| {
-    z.quux();
-    z.rotate(x)
-})
-```
-
-> **[FIXME]** Do we also want to allow the following?
->
-> ```rust,ignore
-> frobnicate(
->     arg1,
->     arg2,
->     arg3)
-> ```
->
-> This style could ease the conflict between line length and functions
-> with many parameters (or long method chains).
-
-### Matches
-
-> * **[Deprecated]** If you have multiple patterns in a single `match`
->   arm, write each pattern on a separate line:
->
->     ```rust,ignore
->     match foo {
->         bar(_)
->         | baz => quux,
->         x
->         | y
->         | z => {
->             quuux
->         }
->     }
->     ```
-
-### Alignment
-
-Idiomatic code should not use extra whitespace in the middle of a line
-to provide alignment.
-
-
-```rust,ignore
-// Good
-struct Foo {
-    short: f64,
-    really_long: f64,
-}
-
-// Bad
-struct Bar {
-    short:       f64,
-    really_long: f64,
-}
-
-// Good
-let a = 0;
-let radius = 7;
-
-// Bad
-let b        = 0;
-let diameter = 7;
-```
diff --git a/src/doc/style/testing/README.md b/src/doc/style/testing/README.md
deleted file mode 100644 (file)
index a21f694..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-% Testing
-
-> **[FIXME]** Add some general remarks about when and how to unit
-> test, versus other kinds of testing. What are our expectations for
-> Rust's core libraries?
diff --git a/src/doc/style/testing/unit.md b/src/doc/style/testing/unit.md
deleted file mode 100644 (file)
index dbbe9fc..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-% Unit testing
-
-Unit tests should live in a `tests` submodule at the bottom of the module they
-test. Mark the `tests` submodule with `#[cfg(test)]` so it is only compiled when
-testing.
-
-The `tests` module should contain:
-
-* Imports needed only for testing.
-* Functions marked with `#[test]` striving for full coverage of the parent module's
-  definitions.
-* Auxiliary functions needed for writing the tests.
-
-For example:
-
-``` rust
-// Excerpt from std::str
-
-#[cfg(test)]
-mod tests {
-    #[test]
-    fn test_eq() {
-        assert!((eq(&"".to_owned(), &"".to_owned())));
-        assert!((eq(&"foo".to_owned(), &"foo".to_owned())));
-        assert!((!eq(&"foo".to_owned(), &"bar".to_owned())));
-    }
-}
-```
-
-> **[FIXME]** add details about useful macros for testing, e.g. `assert!`
diff --git a/src/doc/style/todo.md b/src/doc/style/todo.md
deleted file mode 100644 (file)
index 28ef2a1..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-* [Containers and iteration]()
-* [The visitor pattern]()
-* [Concurrency]()
-* [Documentation]()
-* [Macros]()
index cde7094cec41e1cd795dab7bc7fc37a59d8aa897..542b7bf797b358d2f617f2d3da5991758568a8b3 100644 (file)
@@ -6,6 +6,7 @@ These are some links to repos with configs which ease the use of rust.
 
 * [rust.vim](https://github.com/rust-lang/rust.vim)
 * [emacs rust-mode](https://github.com/rust-lang/rust-mode)
+* [sublime-rust](https://github.com/rust-lang/sublime-rust)
 * [gedit-config](https://github.com/rust-lang/gedit-config)
 * [kate-config](https://github.com/rust-lang/kate-config)
 * [nano-config](https://github.com/rust-lang/nano-config)
index b2bb7859661ab63aae27658359731647887741f9..e713c7c8387fc51fcaf23b2d8538ea73f0fb166e 100644 (file)
@@ -324,3 +324,20 @@ def extract_length_and_ptr_from_slice(slice_val):
 
     assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
     return (length, data_ptr)
+
+UNQUALIFIED_TYPE_MARKERS = frozenset(["(", "[", "&", "*"])
+
+def extract_type_name(qualified_type_name):
+    '''Extracts the type name from a fully qualified path'''
+    if qualified_type_name[0] in UNQUALIFIED_TYPE_MARKERS:
+        return qualified_type_name
+
+    end_of_search = qualified_type_name.find("<")
+    if end_of_search < 0:
+        end_of_search = len(qualified_type_name)
+
+    index = qualified_type_name.rfind("::", 0, end_of_search)
+    if index < 0:
+        return qualified_type_name
+    else:
+        return qualified_type_name[index + 2:]
index 554ab66bc563d85328bd8c8303bcf035ac8fb380..9b163c835c65058a3fcac383e0e3f519ae6e7d1d 100755 (executable)
@@ -16,7 +16,7 @@ import debugger_pretty_printers_common as rustpp
 # We want a version of `range` which doesn't allocate an intermediate list,
 # specifically it should use a lazy iterator. In Python 2 this was `xrange`, but
 # if we're running with Python 3 then we need to use `range` instead.
-if sys.version_info.major >= 3:
+if sys.version_info[0] >= 3:
     xrange = range
 
 #===============================================================================
@@ -36,7 +36,7 @@ class GdbType(rustpp.Type):
         if tag is None:
             return tag
 
-        return tag.replace("&'static ", "&")
+        return rustpp.extract_type_name(tag).replace("&'static ", "&")
 
     def get_dwarf_type_kind(self):
         if self.ty.code == gdb.TYPE_CODE_STRUCT:
index c22a60abf3f7662be6aa814dc7a27ffb8c25105a..c0a4c3e9ece932e312999fb3e3cf58fb95069deb 100644 (file)
@@ -29,7 +29,7 @@ class LldbType(rustpp.Type):
         if qualified_name is None:
             return qualified_name
 
-        return extract_type_name(qualified_name).replace("&'static ", "&")
+        return rustpp.extract_type_name(qualified_name).replace("&'static ", "&")
 
     def get_dwarf_type_kind(self):
         type_class = self.ty.GetTypeClass()
@@ -204,7 +204,7 @@ def print_struct_val(val, internal_dict, omit_first_field, omit_type_name, is_tu
             # LLDB is not good at handling zero-sized values, so we have to help
             # it a little
             if field.GetType().GetByteSize() == 0:
-                return this + extract_type_name(field.GetType().GetName())
+                return this + rustpp.extract_type_name(field.GetType().GetName())
             else:
                 return this + "<invalid value>"
 
@@ -274,23 +274,6 @@ def print_std_string_val(val, internal_dict):
 # Helper Functions
 #=--------------------------------------------------------------------------------------------------
 
-UNQUALIFIED_TYPE_MARKERS = frozenset(["(", "[", "&", "*"])
-
-def extract_type_name(qualified_type_name):
-    '''Extracts the type name from a fully qualified path'''
-    if qualified_type_name[0] in UNQUALIFIED_TYPE_MARKERS:
-        return qualified_type_name
-
-    end_of_search = qualified_type_name.find("<")
-    if end_of_search < 0:
-        end_of_search = len(qualified_type_name)
-
-    index = qualified_type_name.rfind("::", 0, end_of_search)
-    if index < 0:
-        return qualified_type_name
-    else:
-        return qualified_type_name[index + 2:]
-
 def print_array_of_values(array_name, data_ptr_val, length, internal_dict):
     '''Prints a contigous memory range, interpreting it as values of the
        pointee-type of data_ptr_val.'''
index 64b780413f884f4a33045525a98d83717d6053e5..b54b71cabd1e9cdaa21ee7a4b752733c52e09ac4 100644 (file)
 /// does not use atomics, making it both thread-unsafe as well as significantly
 /// faster when updating the reference count.
 ///
+/// Note: the inherent methods defined on `Arc<T>` are all associated functions,
+/// which means that you have to call them as e.g.  `Arc::get_mut(&value)`
+/// instead of `value.get_mut()`.  This is so that there are no conflicts with
+/// methods on the inner type `T`, which are what you want to call in the
+/// majority of cases.
+///
 /// # Examples
 ///
 /// In this example, a large vector of data will be shared by several threads. First we
 /// }
 /// ```
 
-#[unsafe_no_drop_flag]
+#[cfg_attr(stage0, unsafe_no_drop_flag)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Arc<T: ?Sized> {
     ptr: Shared<ArcInner<T>>,
@@ -147,7 +153,7 @@ 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.
 
-#[unsafe_no_drop_flag]
+#[cfg_attr(stage0, unsafe_no_drop_flag)]
 #[stable(feature = "arc_weak", since = "1.4.0")]
 pub struct Weak<T: ?Sized> {
     ptr: Shared<ArcInner<T>>,
@@ -559,15 +565,6 @@ impl<T: ?Sized> Drop for Arc<T> {
     #[unsafe_destructor_blind_to_params]
     #[inline]
     fn drop(&mut self) {
-        // This structure has #[unsafe_no_drop_flag], so this drop glue may run
-        // more than once (but it is guaranteed to be zeroed after the first if
-        // it's run more than once)
-        let thin = *self.ptr as *const ();
-
-        if thin as usize == mem::POST_DROP_USIZE {
-            return;
-        }
-
         // Because `fetch_sub` is already atomic, we do not need to synchronize
         // with other threads unless we are going to delete the object. This
         // same logic applies to the below `fetch_sub` to the `weak` count.
@@ -755,12 +752,6 @@ impl<T: ?Sized> Drop for Weak<T> {
     /// ```
     fn drop(&mut self) {
         let ptr = *self.ptr;
-        let thin = ptr as *const ();
-
-        // see comments above for why this check is here
-        if thin as usize == mem::POST_DROP_USIZE {
-            return;
-        }
 
         // If we find out that we were the last weak pointer, then its time to
         // deallocate the data entirely. See the discussion in Arc::drop() about
index 7ba5ca30941f476f01f7957325b1cd361ab43e27..70c429cc3600a4f94809ee41470575e02b3f5a1c 100644 (file)
 use core::cmp::Ordering;
 use core::fmt;
 use core::hash::{self, Hash};
+use core::iter::FusedIterator;
 use core::marker::{self, Unsize};
 use core::mem;
 use core::ops::{CoerceUnsized, Deref, DerefMut};
 use core::ops::{BoxPlace, Boxed, InPlace, Place, Placer};
 use core::ptr::{self, Unique};
-use core::raw::TraitObject;
 use core::convert::From;
 
 /// A value that represents the heap. This is the default place that the `box`
@@ -271,6 +271,10 @@ pub unsafe fn from_raw(raw: *mut T) -> Self {
     /// proper way to do so is to convert the raw pointer back into a
     /// `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.
+    ///
     /// # Examples
     ///
     /// ```
@@ -427,12 +431,8 @@ impl Box<Any> {
     pub fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
         if self.is::<T>() {
             unsafe {
-                // Get the raw representation of the trait object
-                let raw = Box::into_raw(self);
-                let to: TraitObject = mem::transmute::<*mut Any, TraitObject>(raw);
-
-                // Extract the data pointer
-                Ok(Box::from_raw(to.data as *mut T))
+                let raw: *mut Any = Box::into_raw(self);
+                Ok(Box::from_raw(raw as *mut T))
             }
         } else {
             Err(self)
@@ -529,6 +529,9 @@ fn next_back(&mut self) -> Option<I::Item> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I: ExactSizeIterator + ?Sized> ExactSizeIterator for Box<I> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<I: FusedIterator + ?Sized> FusedIterator for Box<I> {}
+
 
 /// `FnBox` is a version of the `FnOnce` intended for use with boxed
 /// closure objects. The idea is that where one would normally store a
index 0293d5402c4c983f08f03cc5207b0a51b5f5de1d..c6453da3f4697d5f660634cf59a088a4197059ea 100644 (file)
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
 #![feature(unique)]
-#![feature(unsafe_no_drop_flag, filling_drop)]
+#![cfg_attr(stage0, feature(unsafe_no_drop_flag))]
 #![feature(unsize)]
 
-#![cfg_attr(not(test), feature(raw, fn_traits, placement_new_protocol))]
+#![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol))]
 #![cfg_attr(test, feature(test, box_heap))]
 
 // Allow testing this library
index cdb70ce57708ad705595a84ebe65f32289471de5..23542215fa890a7f4ddffb236a6cc714bc4a7ca2 100644 (file)
@@ -44,7 +44,7 @@
 /// `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.
-#[unsafe_no_drop_flag]
+#[cfg_attr(stage0, unsafe_no_drop_flag)]
 pub struct RawVec<T> {
     ptr: Unique<T>,
     cap: usize,
@@ -546,13 +546,6 @@ pub unsafe fn into_box(self) -> Box<[T]> {
         mem::forget(self);
         output
     }
-
-    /// This is a stupid name in the hopes that someone will find this in the
-    /// not too distant future and remove it with the rest of
-    /// #[unsafe_no_drop_flag]
-    pub fn unsafe_no_drop_flag_needs_drop(&self) -> bool {
-        self.cap != mem::POST_DROP_USIZE
-    }
 }
 
 impl<T> Drop for RawVec<T> {
@@ -560,7 +553,7 @@ impl<T> Drop for RawVec<T> {
     /// Frees the memory owned by the RawVec *without* trying to Drop its contents.
     fn drop(&mut self) {
         let elem_size = mem::size_of::<T>();
-        if elem_size != 0 && self.cap != 0 && self.unsafe_no_drop_flag_needs_drop() {
+        if elem_size != 0 && self.cap != 0 {
             let align = mem::align_of::<T>();
 
             let num_bytes = elem_size * self.cap;
index 2beb652aa017a6d2c16e959afe05d592a203224d..c24c7ca47ad053ff6ae38be2947d5c3e20556f44 100644 (file)
@@ -182,7 +182,13 @@ struct RcBox<T: ?Sized> {
 /// A reference-counted pointer type over an immutable value.
 ///
 /// See the [module level documentation](./index.html) for more details.
-#[unsafe_no_drop_flag]
+///
+/// Note: the inherent methods defined on `Rc<T>` are all associated functions,
+/// which means that you have to call them as e.g. `Rc::get_mut(&value)` instead
+/// of `value.get_mut()`.  This is so that there are no conflicts with methods
+/// on the inner type `T`, which are what you want to call in the majority of
+/// cases.
+#[cfg_attr(stage0, unsafe_no_drop_flag)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Rc<T: ?Sized> {
     ptr: Shared<RcBox<T>>,
@@ -263,6 +269,23 @@ pub fn try_unwrap(this: Self) -> Result<T, Self> {
     }
 
     /// Checks if `Rc::try_unwrap` would return `Ok`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(rc_would_unwrap)]
+    ///
+    /// use std::rc::Rc;
+    ///
+    /// let x = Rc::new(3);
+    /// assert!(Rc::would_unwrap(&x));
+    /// assert_eq!(Rc::try_unwrap(x), Ok(3));
+    ///
+    /// let x = Rc::new(4);
+    /// let _y = x.clone();
+    /// assert!(!Rc::would_unwrap(&x));
+    /// assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4)));
+    /// ```
     #[unstable(feature = "rc_would_unwrap",
                reason = "just added for niche usecase",
                issue = "28356")]
@@ -449,21 +472,18 @@ impl<T: ?Sized> Drop for Rc<T> {
     fn drop(&mut self) {
         unsafe {
             let ptr = *self.ptr;
-            let thin = ptr as *const ();
 
-            if thin as usize != mem::POST_DROP_USIZE {
-                self.dec_strong();
-                if self.strong() == 0 {
-                    // destroy the contained object
-                    ptr::drop_in_place(&mut (*ptr).value);
+            self.dec_strong();
+            if self.strong() == 0 {
+                // destroy the contained object
+                ptr::drop_in_place(&mut (*ptr).value);
 
-                    // remove the implicit "strong weak" pointer now that we've
-                    // destroyed the contents.
-                    self.dec_weak();
+                // remove the implicit "strong weak" pointer now that we've
+                // destroyed the contents.
+                self.dec_weak();
 
-                    if self.weak() == 0 {
-                        deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
-                    }
+                if self.weak() == 0 {
+                    deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
                 }
             }
         }
@@ -707,7 +727,7 @@ fn from(t: T) -> Self {
 /// dropped.
 ///
 /// See the [module level documentation](./index.html) for more.
-#[unsafe_no_drop_flag]
+#[cfg_attr(stage0, unsafe_no_drop_flag)]
 #[stable(feature = "rc_weak", since = "1.4.0")]
 pub struct Weak<T: ?Sized> {
     ptr: Shared<RcBox<T>>,
@@ -808,15 +828,12 @@ impl<T: ?Sized> Drop for Weak<T> {
     fn drop(&mut self) {
         unsafe {
             let ptr = *self.ptr;
-            let thin = ptr as *const ();
 
-            if thin as usize != mem::POST_DROP_USIZE {
-                self.dec_weak();
-                // the weak count starts at 1, and will only go to zero if all
-                // the strong pointers have disappeared.
-                if self.weak() == 0 {
-                    deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
-                }
+            self.dec_weak();
+            // the weak count starts at 1, and will only go to zero if all
+            // the strong pointers have disappeared.
+            if self.weak() == 0 {
+                deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
             }
         }
     }
index 347e97e6ffc0a8ddd84e25b3a0637bf499d0ab8a..aae0528e42cc9aa82cfcf756a47948c81d18907c 100644 (file)
@@ -77,7 +77,8 @@
 #[cfg(all(any(target_arch = "x86",
               target_arch = "x86_64",
               target_arch = "aarch64",
-              target_arch = "powerpc64")))]
+              target_arch = "powerpc64",
+              target_arch = "mips64")))]
 const MIN_ALIGN: usize = 16;
 
 // MALLOCX_ALIGN(a) macro
index 9eade937bfb4cffd60a4f3c207d312fccb8c54f5..2c0c6d068caaeb6205a7bb738ac1f059ef3a0361 100644 (file)
@@ -32,7 +32,8 @@
               target_arch = "asmjs")))]
 const MIN_ALIGN: usize = 8;
 #[cfg(all(any(target_arch = "x86_64",
-              target_arch = "aarch64")))]
+              target_arch = "aarch64",
+              target_arch = "mips64")))]
 const MIN_ALIGN: usize = 16;
 
 #[no_mangle]
index b9f5c6fcab9092a3d4565c5980a82f65888ff664..5ece27372e13034f2cc0400e3ce2f37e98903d20 100644 (file)
 #![allow(missing_docs)]
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use core::ops::{Drop, Deref, DerefMut};
-use core::iter::FromIterator;
+use core::ops::{Deref, DerefMut};
+use core::iter::{FromIterator, FusedIterator};
 use core::mem::swap;
 use core::mem::size_of;
 use core::ptr;
@@ -223,19 +223,19 @@ pub struct BinaryHeap<T> {
 /// on `BinaryHeap`. See its documentation for details.
 ///
 /// [`peek_mut()`]: struct.BinaryHeap.html#method.peek_mut
-#[unstable(feature = "binary_heap_peek_mut", issue = "34392")]
+#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
 pub struct PeekMut<'a, T: 'a + Ord> {
     heap: &'a mut BinaryHeap<T>
 }
 
-#[unstable(feature = "binary_heap_peek_mut", issue = "34392")]
+#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
 impl<'a, T: Ord> Drop for PeekMut<'a, T> {
     fn drop(&mut self) {
         self.heap.sift_down(0);
     }
 }
 
-#[unstable(feature = "binary_heap_peek_mut", issue = "34392")]
+#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
 impl<'a, T: Ord> Deref for PeekMut<'a, T> {
     type Target = T;
     fn deref(&self) -> &T {
@@ -243,7 +243,7 @@ fn deref(&self) -> &T {
     }
 }
 
-#[unstable(feature = "binary_heap_peek_mut", issue = "34392")]
+#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
 impl<'a, T: Ord> DerefMut for PeekMut<'a, T> {
     fn deref_mut(&mut self) -> &mut T {
         &mut self.heap.data[0]
@@ -366,7 +366,6 @@ pub fn peek(&self) -> Option<&T> {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(binary_heap_peek_mut)]
     /// use std::collections::BinaryHeap;
     /// let mut heap = BinaryHeap::new();
     /// assert!(heap.peek_mut().is_none());
@@ -380,7 +379,7 @@ pub fn peek(&self) -> Option<&T> {
     /// }
     /// assert_eq!(heap.peek(), Some(&2));
     /// ```
-    #[unstable(feature = "binary_heap_peek_mut", issue = "34392")]
+    #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
     pub fn peek_mut(&mut self) -> Option<PeekMut<T>> {
         if self.is_empty() {
             None
@@ -981,6 +980,9 @@ fn next_back(&mut self) -> Option<&'a T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Iter<'a, T> {}
+
 /// An iterator that moves out of a `BinaryHeap`.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Clone)]
@@ -1014,6 +1016,9 @@ fn next_back(&mut self) -> Option<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ExactSizeIterator for IntoIter<T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for IntoIter<T> {}
+
 /// An iterator that drains a `BinaryHeap`.
 #[stable(feature = "drain", since = "1.6.0")]
 pub struct Drain<'a, T: 'a> {
@@ -1046,6 +1051,9 @@ fn next_back(&mut self) -> Option<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T: 'a> FusedIterator for Drain<'a, T> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Ord> From<Vec<T>> for BinaryHeap<T> {
     fn from(vec: Vec<T>) -> BinaryHeap<T> {
index 37dbeb4eae17d6d61f7dad0929e8ae3c9830c72d..3ad1d08298581c81785cf6259754a24eab774033 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use core::clone::Clone;
-use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
-use core::convert::AsRef;
-use core::default::Default;
+use core::cmp::Ordering;
 use core::hash::{Hash, Hasher};
-use core::marker::Sized;
 use core::ops::Deref;
-use core::option::Option;
 
 use fmt;
 
index c3a7d4023754aac97d45a0539a9cf0e4a8cfe490..79840df1677eaf0c4c55ab0347f8891bd803d091 100644 (file)
@@ -11,7 +11,7 @@
 use core::cmp::Ordering;
 use core::fmt::Debug;
 use core::hash::{Hash, Hasher};
-use core::iter::{FromIterator, Peekable};
+use core::iter::{FromIterator, Peekable, FusedIterator};
 use core::marker::PhantomData;
 use core::ops::Index;
 use core::{fmt, intrinsics, mem, ptr};
@@ -1147,6 +1147,9 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Iter<'a, K, V> {}
+
 impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> {
     fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
         if self.length == 0 {
@@ -1216,6 +1219,9 @@ fn len(&self) -> usize {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {}
+
 impl<K, V> IntoIterator for BTreeMap<K, V> {
     type Item = (K, V);
     type IntoIter = IntoIter<K, V>;
@@ -1338,6 +1344,9 @@ fn len(&self) -> usize {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<K, V> FusedIterator for IntoIter<K, V> {}
+
 impl<'a, K, V> Iterator for Keys<'a, K, V> {
     type Item = &'a K;
 
@@ -1362,6 +1371,9 @@ fn len(&self) -> usize {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Keys<'a, K, V> {}
+
 impl<'a, K, V> Clone for Keys<'a, K, V> {
     fn clone(&self) -> Keys<'a, K, V> {
         Keys { inner: self.inner.clone() }
@@ -1392,6 +1404,9 @@ fn len(&self) -> usize {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Values<'a, K, V> {}
+
 impl<'a, K, V> Clone for Values<'a, K, V> {
     fn clone(&self) -> Values<'a, K, V> {
         Values { inner: self.inner.clone() }
@@ -1437,6 +1452,10 @@ fn len(&self) -> usize {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {}
+
+
 impl<'a, K, V> Range<'a, K, V> {
     unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
         let handle = self.front;
@@ -1511,6 +1530,9 @@ unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Range<'a, K, V> {}
+
 impl<'a, K, V> Clone for Range<'a, K, V> {
     fn clone(&self) -> Range<'a, K, V> {
         Range {
@@ -1574,6 +1596,9 @@ fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for RangeMut<'a, K, V> {}
+
 impl<'a, K, V> RangeMut<'a, K, V> {
     unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) {
         let handle = ptr::read(&self.back);
@@ -1981,8 +2006,6 @@ pub fn key(&self) -> &K {
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_entry_recover_keys)]
-    ///
     /// use std::collections::BTreeMap;
     /// use std::collections::btree_map::Entry;
     ///
@@ -1992,7 +2015,7 @@ pub fn key(&self) -> &K {
     ///     v.into_key();
     /// }
     /// ```
-    #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
+    #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")]
     pub fn into_key(self) -> K {
         self.key
     }
@@ -2074,13 +2097,18 @@ pub fn key(&self) -> &K {
         self.handle.reborrow().into_kv().0
     }
 
+    /// Deprecated, renamed to `remove_entry`
+    #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
+    #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")]
+    pub fn remove_pair(self) -> (K, V) {
+        self.remove_entry()
+    }
+
     /// Take ownership of the key and value from the map.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_entry_recover_keys)]
-    ///
     /// use std::collections::BTreeMap;
     /// use std::collections::btree_map::Entry;
     ///
@@ -2089,14 +2117,14 @@ pub fn key(&self) -> &K {
     ///
     /// if let Entry::Occupied(o) = map.entry("poneyland") {
     ///     // We delete the entry from the map.
-    ///     o.remove_pair();
+    ///     o.remove_entry();
     /// }
     ///
     /// // If now try to get the value, it will panic:
     /// // println!("{}", map["poneyland"]);
     /// ```
-    #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
-    pub fn remove_pair(self) -> (K, V) {
+    #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")]
+    pub fn remove_entry(self) -> (K, V) {
         self.remove_kv()
     }
 
index 0f885bc2950a6b3426778e7508445b286c76e47e..5d7b00f57c83b0b3c3ebb0d9ae2b7d43f4f7992a 100644 (file)
@@ -15,7 +15,7 @@
 use core::cmp::{min, max};
 use core::fmt::Debug;
 use core::fmt;
-use core::iter::{Peekable, FromIterator};
+use core::iter::{Peekable, FromIterator, FusedIterator};
 use core::ops::{BitOr, BitAnd, BitXor, Sub};
 
 use borrow::Borrow;
@@ -805,6 +805,8 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> {
     fn len(&self) -> usize { self.iter.len() }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Iter<'a, T> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Iterator for IntoIter<T> {
@@ -828,6 +830,8 @@ impl<T> ExactSizeIterator for IntoIter<T> {
     fn len(&self) -> usize { self.iter.len() }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for IntoIter<T> {}
 
 impl<'a, T> Clone for Range<'a, T> {
     fn clone(&self) -> Range<'a, T> {
@@ -847,6 +851,9 @@ fn next_back(&mut self) -> Option<&'a T> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Range<'a, T> {}
+
 /// Compare `x` and `y`, but return `short` if x is None and `long` if y is None
 fn cmp_opt<T: Ord>(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering) -> Ordering {
     match (x, y) {
@@ -890,6 +897,9 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T: Ord> FusedIterator for Difference<'a, T> {}
+
 impl<'a, T> Clone for SymmetricDifference<'a, T> {
     fn clone(&self) -> SymmetricDifference<'a, T> {
         SymmetricDifference {
@@ -920,6 +930,9 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T: Ord> FusedIterator for SymmetricDifference<'a, T> {}
+
 impl<'a, T> Clone for Intersection<'a, T> {
     fn clone(&self) -> Intersection<'a, T> {
         Intersection {
@@ -960,6 +973,9 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T: Ord> FusedIterator for Intersection<'a, T> {}
+
 impl<'a, T> Clone for Union<'a, T> {
     fn clone(&self) -> Union<'a, T> {
         Union {
@@ -991,3 +1007,6 @@ fn size_hint(&self) -> (usize, Option<usize>) {
         (max(a_len, b_len), Some(a_len + b_len))
     }
 }
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T: Ord> FusedIterator for Union<'a, T> {}
index 0c66c0564c3ea2ca879d6eaefee4442ca641f830..2456a04e40a3a18e48cde9947f70731ce2e9eae5 100644 (file)
@@ -20,7 +20,7 @@
 
 use core::marker;
 use core::fmt;
-use core::iter::FromIterator;
+use core::iter::{FromIterator, FusedIterator};
 use core::ops::{Sub, BitOr, BitAnd, BitXor};
 
 // FIXME(contentions): implement union family of methods? (general design may be
@@ -266,6 +266,9 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<E: CLike> FusedIterator for Iter<E> {}
+
 impl<E: CLike> FromIterator<E> for EnumSet<E> {
     fn from_iter<I: IntoIterator<Item = E>>(iter: I) -> EnumSet<E> {
         let mut ret = EnumSet::new();
index be0ef85d6b114aad2c2c975774bc209af7311fac..beb3e6b3d4e3132bf87a012bd59935d1c691f583 100644 (file)
 //! provides some helper methods.
 //!
 //! Additionally, the return value of this function is `fmt::Result` which is a
-//! typedef to `Result<(), std::io::Error>` (also known as `std::io::Result<()>`).
-//! Formatting implementations should ensure that they return errors from `write!`
-//! correctly (propagating errors upward).
+//! type alias of `Result<(), std::fmt::Error>`. Formatting implementations
+//! should ensure that they propagate errors from the `Formatter` (e.g., when
+//! calling `write!`) however, they should never return errors spuriously. That
+//! is, a formatting implementation must and may only return an error if the
+//! passed-in `Formatter` returns an error. This is because, contrary to what
+//! the function signature might suggest, string formatting is an infallible
+//! operation. This function only returns a result because writing to the
+//! underlying stream might fail and it must provide a way to propagate the fact
+//! that an error has occurred back up the stack.
 //!
 //! An example of implementing the formatting traits would look
 //! like:
 /// assert_eq!(s, "Hello, world!");
 /// ```
 ///
-/// [format!]: ../macro.format!.html
+/// [format!]: ../macro.format.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn format(args: Arguments) -> string::String {
     let mut output = string::String::new();
index 21387a1aa95543031fa403d3893c2a102f9afed1..c5a921693475a60e7ec1abfef9f78274ef742c11 100644 (file)
@@ -37,6 +37,7 @@
 #![feature(core_intrinsics)]
 #![feature(dropck_parametricity)]
 #![feature(fmt_internals)]
+#![feature(fused)]
 #![feature(heap_api)]
 #![feature(inclusive_range)]
 #![feature(lang_items)]
@@ -51,7 +52,7 @@
 #![feature(step_by)]
 #![feature(unicode)]
 #![feature(unique)]
-#![feature(unsafe_no_drop_flag)]
+#![cfg_attr(stage0, feature(unsafe_no_drop_flag))]
 #![cfg_attr(test, feature(rand, test))]
 
 #![no_std]
index 6842f02e0e19b1732d3ded4cc9a169f09c46b5c0..769c5162a456057a3d22a027b277f5345bbf8c2c 100644 (file)
@@ -19,7 +19,7 @@
 use core::cmp::Ordering;
 use core::fmt;
 use core::hash::{Hasher, Hash};
-use core::iter::FromIterator;
+use core::iter::{FromIterator, FusedIterator};
 use core::marker::PhantomData;
 use core::mem;
 use core::ops::{BoxPlace, InPlace, Place, Placer};
@@ -379,8 +379,6 @@ pub fn clear(&mut self) {
     /// # Examples
     ///
     /// ```
-    /// #![feature(linked_list_contains)]
-    ///
     /// use std::collections::LinkedList;
     ///
     /// let mut list: LinkedList<u32> = LinkedList::new();
@@ -392,8 +390,7 @@ pub fn clear(&mut self) {
     /// assert_eq!(list.contains(&0), true);
     /// assert_eq!(list.contains(&10), false);
     /// ```
-    #[unstable(feature = "linked_list_contains", reason = "recently added",
-               issue = "32630")]
+    #[stable(feature = "linked_list_contains", since = "1.12.0")]
     pub fn contains(&self, x: &T) -> bool
         where T: PartialEq<T>
     {
@@ -757,6 +754,9 @@ fn next_back(&mut self) -> Option<&'a T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Iter<'a, T> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> Iterator for IterMut<'a, T> {
     type Item = &'a mut T;
@@ -801,6 +801,9 @@ fn next_back(&mut self) -> Option<&'a mut T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for IterMut<'a, T> {}
+
 impl<'a, T> IterMut<'a, T> {
     /// Inserts the given element just after the element most recently returned by `.next()`.
     /// The inserted element does not appear in the iteration.
@@ -908,6 +911,9 @@ fn next_back(&mut self) -> Option<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ExactSizeIterator for IntoIter<T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for IntoIter<T> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> FromIterator<T> for LinkedList<T> {
     fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
@@ -1153,9 +1159,6 @@ unsafe impl<'a, T: Sync> Sync for IterMut<'a, T> {}
 
 #[cfg(test)]
 mod tests {
-    use std::clone::Clone;
-    use std::iter::{Iterator, IntoIterator, Extend};
-    use std::option::Option::{self, Some, None};
     use std::__rand::{thread_rng, Rng};
     use std::thread;
     use std::vec::Vec;
@@ -1313,7 +1316,6 @@ fn test_fuzz() {
 
     #[test]
     fn test_26021() {
-        use std::iter::ExactSizeIterator;
         // There was a bug in split_off that failed to null out the RHS's head's prev ptr.
         // This caused the RHS's dtor to walk up into the LHS at drop and delete all of
         // its nodes.
index 1badc72aed07c1a9d21eab781c59fd6ef5fed9f9..d331ead2c5ee685173d8ab82210a99c3f297fe03 100644 (file)
@@ -14,7 +14,6 @@
 
 //! Range syntax.
 
-use core::option::Option::{self, None, Some};
 use core::ops::{RangeFull, Range, RangeTo, RangeFrom};
 
 /// **RangeArgument** is implemented by Rust's built-in range types, produced
index 4c64019de097ef8a7c2a5295df19c60681f8c2ef..999c84ba7053801bef7ade6ba38db4670352b09d 100644 (file)
@@ -23,6 +23,7 @@
 use core::str::pattern::Pattern;
 use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
 use core::mem;
+use core::iter::FusedIterator;
 use rustc_unicode::str::{UnicodeStr, Utf16Encoder};
 
 use vec_deque::VecDeque;
@@ -136,6 +137,9 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for EncodeUtf16<'a> {}
+
 // Return the initial codepoint accumulator for the first byte.
 // The first byte is special, only want bottom 5 bits for width 2, 4 bits
 // for width 3, and 3 bits for width 4
index 788c838cd3fc8ddaf70ec34a6d862bdac2d2a591..3a304c629293062dfbb5d8eb313c12889c6ff72b 100644 (file)
@@ -57,7 +57,7 @@
 
 use core::fmt;
 use core::hash;
-use core::iter::FromIterator;
+use core::iter::{FromIterator, FusedIterator};
 use core::mem;
 use core::ops::{self, Add, AddAssign, Index, IndexMut};
 use core::ptr;
 /// [`OsString`]: ../../std/ffi/struct.OsString.html
 ///
 /// Indexing is intended to be a constant-time operation, but UTF-8 encoding
-/// does not allow us to do this. Furtheremore, it's not clear what sort of
+/// does not allow us to do this. Furthermore, it's not clear what sort of
 /// thing the index should return: a byte, a codepoint, or a grapheme cluster.
 /// The [`as_bytes()`] and [`chars()`] methods return iterators over the first
 /// two, respectively.
@@ -1995,3 +1995,6 @@ fn next_back(&mut self) -> Option<char> {
         self.iter.next_back()
     }
 }
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for Drain<'a> {}
index 522890a2e2682820f912022e424574ceaa3dc5c9..876314613f523fa675cf4dee5dbb801cea160bb9 100644 (file)
@@ -68,7 +68,7 @@
 use core::fmt;
 use core::hash::{self, Hash};
 use core::intrinsics::{arith_offset, assume};
-use core::iter::FromIterator;
+use core::iter::{FromIterator, FusedIterator};
 use core::mem;
 use core::ops::{Index, IndexMut};
 use core::ops;
 /// Vec does not currently guarantee the order in which elements are dropped
 /// (the order has changed in the past, and may change again).
 ///
-#[unsafe_no_drop_flag]
+#[cfg_attr(stage0, unsafe_no_drop_flag)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Vec<T> {
     buf: RawVec<T>,
@@ -1600,11 +1600,9 @@ fn cmp(&self, other: &Vec<T>) -> Ordering {
 impl<T> Drop for Vec<T> {
     #[unsafe_destructor_blind_to_params]
     fn drop(&mut self) {
-        if self.buf.unsafe_no_drop_flag_needs_drop() {
-            unsafe {
-                // use drop for [T]
-                ptr::drop_in_place(&mut self[..]);
-            }
+        unsafe {
+            // use drop for [T]
+            ptr::drop_in_place(&mut self[..]);
         }
         // RawVec handles deallocation
     }
@@ -1845,6 +1843,9 @@ fn next_back(&mut self) -> Option<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ExactSizeIterator for IntoIter<T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for IntoIter<T> {}
+
 #[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
 impl<T: Clone> Clone for IntoIter<T> {
     fn clone(&self) -> IntoIter<T> {
@@ -1932,3 +1933,6 @@ fn drop(&mut self) {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Drain<'a, T> {}
index 812a67a7e78edd9107145e3dddbadc4670ee7ab3..96624f121b2afbe5ffa81433606b4c3ba84046cc 100644 (file)
@@ -20,7 +20,7 @@
 
 use core::cmp::Ordering;
 use core::fmt;
-use core::iter::{repeat, FromIterator};
+use core::iter::{repeat, FromIterator, FusedIterator};
 use core::mem;
 use core::ops::{Index, IndexMut};
 use core::ptr;
@@ -939,8 +939,6 @@ pub fn clear(&mut self) {
     /// # Examples
     ///
     /// ```
-    /// #![feature(vec_deque_contains)]
-    ///
     /// use std::collections::VecDeque;
     ///
     /// let mut vector: VecDeque<u32> = VecDeque::new();
@@ -951,8 +949,7 @@ pub fn clear(&mut self) {
     /// assert_eq!(vector.contains(&1), true);
     /// assert_eq!(vector.contains(&10), false);
     /// ```
-    #[unstable(feature = "vec_deque_contains", reason = "recently added",
-               issue = "32630")]
+    #[stable(feature = "vec_deque_contains", since = "1.12.0")]
     pub fn contains(&self, x: &T) -> bool
         where T: PartialEq<T>
     {
@@ -1894,6 +1891,10 @@ fn next_back(&mut self) -> Option<&'a T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Iter<'a, T> {}
+
+
 /// `VecDeque` mutable iterator.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IterMut<'a, T: 'a> {
@@ -1946,6 +1947,9 @@ fn next_back(&mut self) -> Option<&'a mut T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for IterMut<'a, T> {}
+
 /// A by-value VecDeque iterator
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1980,6 +1984,9 @@ fn next_back(&mut self) -> Option<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ExactSizeIterator for IntoIter<T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for IntoIter<T> {}
+
 /// A draining VecDeque iterator
 #[stable(feature = "drain", since = "1.6.0")]
 pub struct Drain<'a, T: 'a> {
@@ -2069,6 +2076,9 @@ fn next_back(&mut self) -> Option<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T: 'a> FusedIterator for Drain<'a, T> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A: PartialEq> PartialEq for VecDeque<A> {
     fn eq(&self, other: &VecDeque<A>) -> bool {
@@ -2322,9 +2332,6 @@ fn from(other: VecDeque<T>) -> Self {
 
 #[cfg(test)]
 mod tests {
-    use core::iter::Iterator;
-    use core::option::Option::Some;
-
     use test;
 
     use super::VecDeque;
index f7b647d7772db4a57d91ec37d1cfc300703f23e6..a32e3f1a76aeacace834dc1158fd666e98ebde58 100644 (file)
@@ -39,30 +39,8 @@ fn test_hash() {
   assert!(::hash(&x) == ::hash(&y));
 }
 
-struct Counter<'a, 'b> {
-    i: &'a mut usize,
-    expected: &'b [i32],
-}
-
-impl<'a, 'b, 'c> FnMut<(&'c i32,)> for Counter<'a, 'b> {
-    extern "rust-call" fn call_mut(&mut self, (&x,): (&'c i32,)) -> bool {
-        assert_eq!(x, self.expected[*self.i]);
-        *self.i += 1;
-        true
-    }
-}
-
-impl<'a, 'b, 'c> FnOnce<(&'c i32,)> for Counter<'a, 'b> {
-    type Output = bool;
-
-    extern "rust-call" fn call_once(mut self, args: (&'c i32,)) -> bool {
-        self.call_mut(args)
-    }
-}
-
 fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F) where
-    // FIXME Replace Counter with `Box<FnMut(_) -> _>`
-    F: FnOnce(&BTreeSet<i32>, &BTreeSet<i32>, Counter) -> bool,
+    F: FnOnce(&BTreeSet<i32>, &BTreeSet<i32>, &mut FnMut(&i32) -> bool) -> bool,
 {
     let mut set_a = BTreeSet::new();
     let mut set_b = BTreeSet::new();
@@ -71,7 +49,11 @@ fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F) where
     for y in b { assert!(set_b.insert(*y)) }
 
     let mut i = 0;
-    f(&set_a, &set_b, Counter { i: &mut i, expected: expected });
+    f(&set_a, &set_b, &mut |&x| {
+        assert_eq!(x, expected[i]);
+        i += 1;
+        true
+    });
     assert_eq!(i, expected.len());
 }
 
index ab3231b2b9955e693540cd5f111a5961b934c632..32a07e3e7e6218637a9ff3a4bf2050cdbf13b3a4 100644 (file)
 #![deny(warnings)]
 
 #![feature(binary_heap_extras)]
-#![feature(binary_heap_peek_mut)]
 #![feature(box_syntax)]
 #![feature(btree_range)]
 #![feature(collections)]
 #![feature(collections_bound)]
 #![feature(const_fn)]
-#![feature(fn_traits)]
 #![feature(enumset)]
-#![feature(linked_list_contains)]
 #![feature(pattern)]
 #![feature(rand)]
 #![feature(step_by)]
@@ -27,7 +24,6 @@
 #![feature(test)]
 #![feature(unboxed_closures)]
 #![feature(unicode)]
-#![feature(vec_deque_contains)]
 #![feature(vec_into_iter_as_slice)]
 
 extern crate collections;
index a452be2565b655e14597eed0116d65386bc53210..a3018a46eea22063545331e6937609597a98654d 100644 (file)
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use fmt;
-use marker::Send;
-use mem::transmute;
-use option::Option::{self, Some, None};
-use raw::TraitObject;
 use intrinsics;
-use marker::{Reflect, Sized};
+use marker::Reflect;
 
 ///////////////////////////////////////////////////////////////////////////////
 // Any trait
@@ -201,11 +197,7 @@ pub fn is<T: Any>(&self) -> bool {
     pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
         if self.is::<T>() {
             unsafe {
-                // Get the raw representation of the trait object
-                let to: TraitObject = transmute(self);
-
-                // Extract the data pointer
-                Some(&*(to.data as *const T))
+                Some(&*(self as *const Any as *const T))
             }
         } else {
             None
@@ -242,11 +234,7 @@ pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
     pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
         if self.is::<T>() {
             unsafe {
-                // Get the raw representation of the trait object
-                let to: TraitObject = transmute(self);
-
-                // Extract the data pointer
-                Some(&mut *(to.data as *const T as *mut T))
+                Some(&mut *(self as *mut Any as *mut T))
             }
         } else {
             None
index 45fc5ff80093a99176599d4f760e2a4e1ce45610..9866a39619a82ecfdc3265be60e7e4e4adde7006 100644 (file)
             issue = "27778")]
 
 use borrow::{Borrow, BorrowMut};
-use clone::Clone;
-use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
-use convert::{AsRef, AsMut};
-use default::Default;
+use cmp::Ordering;
 use fmt;
 use hash::{Hash, self};
-use iter::IntoIterator;
-use marker::{Copy, Sized, Unsize};
-use option::Option;
-use slice::{Iter, IterMut, SliceExt};
+use marker::Unsize;
+use slice::{Iter, IterMut};
 
 /// Utility trait implemented only on arrays of fixed size
 ///
index 79330d3a61ea7dcfedeb9f6da18513bf1f4b5f91..3d223465c88a03b44dc01bb913d210b50e14d575 100644 (file)
@@ -12,8 +12,6 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use marker::Sized;
-
 /// A trait for borrowing data.
 ///
 /// In general, there may be several ways to "borrow" a piece of data.  The
index 17ec325e257b028f43ca709041f1769829309500..f0710a1d93578495eeb0ccc3c0365d34df675674 100644 (file)
 //! `Cell<T>`.
 //!
 //! ```
+//! #![feature(core_intrinsics)]
+//! #![feature(shared)]
 //! use std::cell::Cell;
+//! use std::ptr::Shared;
+//! use std::intrinsics::abort;
+//! use std::intrinsics::assume;
 //!
-//! struct Rc<T> {
-//!     ptr: *mut RcBox<T>
+//! struct Rc<T: ?Sized> {
+//!     ptr: Shared<RcBox<T>>
 //! }
 //!
-//! struct RcBox<T> {
-//! # #[allow(dead_code)]
+//! struct RcBox<T: ?Sized> {
+//!     strong: Cell<usize>,
+//!     refcount: Cell<usize>,
 //!     value: T,
-//!     refcount: Cell<usize>
 //! }
 //!
-//! impl<T> Clone for Rc<T> {
+//! impl<T: ?Sized> Clone for Rc<T> {
 //!     fn clone(&self) -> Rc<T> {
-//!         unsafe {
-//!             (*self.ptr).refcount.set((*self.ptr).refcount.get() + 1);
-//!             Rc { ptr: self.ptr }
-//!         }
+//!         self.inc_strong();
+//!         Rc { ptr: self.ptr }
 //!     }
 //! }
+//!
+//! trait RcBoxPtr<T: ?Sized> {
+//!
+//!     fn inner(&self) -> &RcBox<T>;
+//!
+//!     fn strong(&self) -> usize {
+//!         self.inner().strong.get()
+//!     }
+//!
+//!     fn inc_strong(&self) {
+//!         self.inner()
+//!             .strong
+//!             .set(self.strong()
+//!                      .checked_add(1)
+//!                      .unwrap_or_else(|| unsafe { abort() }));
+//!     }
+//! }
+//!
+//! impl<T: ?Sized> RcBoxPtr<T> for Rc<T> {
+//!    fn inner(&self) -> &RcBox<T> {
+//!        unsafe {
+//!            assume(!(*(&self.ptr as *const _ as *const *const ())).is_null());
+//!            &(**self.ptr)
+//!        }
+//!    }
+//! }
 //! ```
 //!
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use clone::Clone;
-use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
-use convert::From;
-use default::Default;
+use cmp::Ordering;
 use fmt::{self, Debug, Display};
-use marker::{Copy, PhantomData, Send, Sync, Sized, Unsize};
-use ops::{Deref, DerefMut, Drop, FnOnce, CoerceUnsized};
-use option::Option;
-use option::Option::{None, Some};
-use result::Result;
-use result::Result::{Ok, Err};
+use marker::{PhantomData, Unsize};
+use ops::{Deref, DerefMut, CoerceUnsized};
 
 /// A mutable memory location that admits only `Copy` data.
 ///
@@ -233,10 +255,28 @@ pub fn set(&self, value: T) {
     /// ```
     #[inline]
     #[unstable(feature = "as_unsafe_cell", issue = "27708")]
+    #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")]
     pub fn as_unsafe_cell(&self) -> &UnsafeCell<T> {
         &self.value
     }
 
+    /// Returns a raw pointer to the underlying data in this cell.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::cell::Cell;
+    ///
+    /// let c = Cell::new(5);
+    ///
+    /// let ptr = c.as_ptr();
+    /// ```
+    #[inline]
+    #[stable(feature = "cell_as_ptr", since = "1.12.0")]
+    pub fn as_ptr(&self) -> *mut T {
+        self.value.get()
+    }
+
     /// Returns a mutable reference to the underlying data.
     ///
     /// This call borrows `Cell` mutably (at compile-time) which guarantees
@@ -337,6 +377,9 @@ fn from(t: T) -> Cell<T> {
     }
 }
 
+#[unstable(feature = "coerce_unsized", issue = "27732")]
+impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {}
+
 /// A mutable memory location with dynamically checked borrow rules
 ///
 /// See the [module-level documentation](index.html) for more.
@@ -653,10 +696,28 @@ pub fn try_borrow_mut(&self) -> Result<RefMut<T>, BorrowMutError<T>> {
     /// ```
     #[inline]
     #[unstable(feature = "as_unsafe_cell", issue = "27708")]
+    #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")]
     pub unsafe fn as_unsafe_cell(&self) -> &UnsafeCell<T> {
         &self.value
     }
 
+    /// Returns a raw pointer to the underlying data in this cell.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::cell::RefCell;
+    ///
+    /// let c = RefCell::new(5);
+    ///
+    /// let ptr = c.as_ptr();
+    /// ```
+    #[inline]
+    #[stable(feature = "cell_as_ptr", since = "1.12.0")]
+    pub fn as_ptr(&self) -> *mut T {
+        self.value.get()
+    }
+
     /// Returns a mutable reference to the underlying data.
     ///
     /// This call borrows `RefCell` mutably (at compile-time) so there is no
@@ -757,6 +818,9 @@ fn from(t: T) -> RefCell<T> {
     }
 }
 
+#[unstable(feature = "coerce_unsized", issue = "27732")]
+impl<T: CoerceUnsized<U>, U> CoerceUnsized<RefCell<U>> for RefCell<T> {}
+
 struct BorrowRef<'b> {
     borrow: &'b Cell<BorrowFlag>,
 }
@@ -1086,3 +1150,13 @@ fn from(t: T) -> UnsafeCell<T> {
         UnsafeCell::new(t)
     }
 }
+
+#[unstable(feature = "coerce_unsized", issue = "27732")]
+impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}
+
+#[allow(unused)]
+fn assert_coerce_unsized(a: UnsafeCell<&i32>, b: Cell<&i32>, c: RefCell<&i32>) {
+    let _: UnsafeCell<&Send> = a;
+    let _: Cell<&Send> = b;
+    let _: RefCell<&Send> = c;
+}
index a3440fe8aa644883f9baad14bdc9102b911ccfd1..ad492c81bd38ac2d1e4eb8dcb7289c835bb4367d 100644 (file)
 #![allow(non_snake_case)]
 #![stable(feature = "core_char", since = "1.2.0")]
 
-use prelude::v1::*;
-
 use char_private::is_printable;
+use convert::TryFrom;
+use fmt;
+use iter::FusedIterator;
 use mem::transmute;
 
 // UTF-8 ranges and tags for encoding characters
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn from_u32(i: u32) -> Option<char> {
-    // catch out-of-bounds and surrogates
-    if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) {
-        None
-    } else {
-        Some(unsafe { from_u32_unchecked(i) })
-    }
+    char::try_from(i).ok()
 }
 
 /// Converts a `u32` to a `char`, ignoring validity.
@@ -176,6 +172,66 @@ pub unsafe fn from_u32_unchecked(i: u32) -> char {
     transmute(i)
 }
 
+#[stable(feature = "char_convert", since = "1.13.0")]
+impl From<char> for u32 {
+    #[inline]
+    fn from(c: char) -> Self {
+        c as u32
+    }
+}
+
+/// Maps a byte in 0x00...0xFF to a `char` whose code point has the same value, in U+0000 to U+00FF.
+///
+/// Unicode is designed such that this effectively decodes bytes
+/// with the character encoding that IANA calls ISO-8859-1.
+/// This encoding is compatible with ASCII.
+///
+/// Note that this is different from ISO/IEC 8859-1 a.k.a. ISO 8859-1 (with one less hypen),
+/// which leaves some "blanks", byte values that are not assigned to any character.
+/// ISO-8859-1 (the IANA one) assigns them to the C0 and C1 control codes.
+///
+/// Note that this is *also* different from Windows-1252 a.k.a. code page 1252,
+/// which is a superset ISO/IEC 8859-1 that assigns some (not all!) blanks
+/// to punctuation and various Latin characters.
+///
+/// To confuse things further, [on the Web](https://encoding.spec.whatwg.org/)
+/// `ascii`, `iso-8859-1`, and `windows-1252` are all aliases
+/// for a superset of Windows-1252 that fills the remaining blanks with corresponding
+/// C0 and C1 control codes.
+#[stable(feature = "char_convert", since = "1.13.0")]
+impl From<u8> for char {
+    #[inline]
+    fn from(i: u8) -> Self {
+        i as char
+    }
+}
+
+#[unstable(feature = "try_from", issue = "33417")]
+impl TryFrom<u32> for char {
+    type Err = CharTryFromError;
+
+    #[inline]
+    fn try_from(i: u32) -> Result<Self, Self::Err> {
+        if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) {
+            Err(CharTryFromError(()))
+        } else {
+            Ok(unsafe { from_u32_unchecked(i) })
+        }
+    }
+}
+
+/// The error type returned when a conversion from u32 to char fails.
+#[unstable(feature = "try_from", issue = "33417")]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct CharTryFromError(());
+
+#[unstable(feature = "try_from", issue = "33417")]
+impl fmt::Display for CharTryFromError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        "converted integer out of range for `char`".fmt(f)
+    }
+}
+
 /// Converts a digit in the given radix to a `char`.
 ///
 /// A 'radix' here is sometimes also called a 'base'. A radix of two
@@ -516,6 +572,9 @@ fn len(&self) -> usize {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl FusedIterator for EscapeUnicode {}
+
 /// An iterator that yields the literal escape code of a `char`.
 ///
 /// This `struct` is created by the [`escape_default()`] method on [`char`]. See
@@ -616,6 +675,9 @@ fn len(&self) -> usize {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl FusedIterator for EscapeDefault {}
+
 /// An iterator that yields the literal escape code of a `char`.
 ///
 /// This `struct` is created by the [`escape_debug()`] method on [`char`]. See its
@@ -637,6 +699,9 @@ fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
 #[unstable(feature = "char_escape_debug", issue = "35068")]
 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.
 ///
@@ -675,6 +740,9 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl FusedIterator for EncodeUtf8 {}
+
 /// An iterator over `u16` entries represending the UTF-16 encoding of a `char`
 /// value.
 ///
@@ -714,6 +782,8 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[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
@@ -737,26 +807,85 @@ pub fn decode_utf8<I: IntoIterator<Item = u8>>(i: I) -> DecodeUtf8<I::IntoIter>
 impl<I: Iterator<Item = u8>> Iterator for DecodeUtf8<I> {
     type Item = Result<char, InvalidSequence>;
     #[inline]
+
     fn next(&mut self) -> Option<Result<char, InvalidSequence>> {
-        self.0.next().map(|b| {
-            if b & 0x80 == 0 { Ok(b as char) } else {
-                let l = (!b).leading_zeros() as usize; // number of bytes in UTF-8 representation
-                if l < 2 || l > 6 { return Err(InvalidSequence(())) };
-                let mut x = (b as u32) & (0x7F >> l);
-                for _ in 0..l-1 {
+        self.0.next().map(|first_byte| {
+            // Emit InvalidSequence according to
+            // Unicode §5.22 Best Practice for U+FFFD Substitution
+            // http://www.unicode.org/versions/Unicode9.0.0/ch05.pdf#G40630
+
+            // Roughly: consume at least one byte,
+            // then validate one byte at a time and stop before the first unexpected byte
+            // (which might be the valid start of the next byte sequence).
+
+            let mut code_point;
+            macro_rules! first_byte {
+                ($mask: expr) => {
+                    code_point = u32::from(first_byte & $mask)
+                }
+            }
+            macro_rules! continuation_byte {
+                () => { continuation_byte!(0x80...0xBF) };
+                ($range: pat) => {
                     match self.0.peek() {
-                        Some(&b) if b & 0xC0 == 0x80 => {
+                        Some(&byte @ $range) => {
+                            code_point = (code_point << 6) | u32::from(byte & 0b0011_1111);
                             self.0.next();
-                            x = (x << 6) | (b as u32) & 0x3F;
-                        },
-                        _ => return Err(InvalidSequence(())),
+                        }
+                        _ => return Err(InvalidSequence(()))
                     }
                 }
-                match from_u32(x) {
-                    Some(x) if l == x.len_utf8() => Ok(x),
-                    _ => Err(InvalidSequence(())),
+            }
+
+            match first_byte {
+                0x00...0x7F => {
+                    first_byte!(0b1111_1111);
+                }
+                0xC2...0xDF => {
+                    first_byte!(0b0001_1111);
+                    continuation_byte!();
+                }
+                0xE0 => {
+                    first_byte!(0b0000_1111);
+                    continuation_byte!(0xA0...0xBF);  // 0x80...0x9F here are overlong
+                    continuation_byte!();
+                }
+                0xE1...0xEC | 0xEE...0xEF => {
+                    first_byte!(0b0000_1111);
+                    continuation_byte!();
+                    continuation_byte!();
+                }
+                0xED => {
+                    first_byte!(0b0000_1111);
+                    continuation_byte!(0x80...0x9F);  // 0xA0..0xBF here are surrogates
+                    continuation_byte!();
                 }
+                0xF0 => {
+                    first_byte!(0b0000_0111);
+                    continuation_byte!(0x90...0xBF);  // 0x80..0x8F here are overlong
+                    continuation_byte!();
+                    continuation_byte!();
+                }
+                0xF1...0xF3 => {
+                    first_byte!(0b0000_0111);
+                    continuation_byte!();
+                    continuation_byte!();
+                    continuation_byte!();
+                }
+                0xF4 => {
+                    first_byte!(0b0000_0111);
+                    continuation_byte!(0x80...0x8F);  // 0x90..0xBF here are beyond char::MAX
+                    continuation_byte!();
+                    continuation_byte!();
+                }
+                _ => return Err(InvalidSequence(()))  // Illegal first byte, overlong, or beyond MAX
+            }
+            unsafe {
+                Ok(from_u32_unchecked(code_point))
             }
         })
     }
 }
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<I: FusedIterator<Item = u8>> FusedIterator for DecodeUtf8<I> {}
index 1d8f95cd4b81cd800aa3320a4510193496caf3f1..708e7cc15e7c97f97f89f9f4c326bc02bf2acd97 100644 (file)
@@ -11,8 +11,6 @@
 // NOTE: The following code was generated by "src/etc/char_private.py",
 //       do not edit directly!
 
-use slice::SliceExt;
-
 fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool {
     for &s in singletons {
         if x == s {
index e8cd36f3cd70bf13d751790bcbefdb2e9a16a937..748bb62a1f3eb51794c40f8611ca7f4d1d1e4f29 100644 (file)
@@ -44,8 +44,6 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use marker::Sized;
-
 /// A common trait for the ability to explicitly duplicate an object.
 ///
 /// Differs from `Copy` in that `Copy` is implicit and extremely inexpensive, while
index bb7c971111853e2b612158d4a772835f5cbc7b8a..670978a2d49aff8f57dd0e9b25c6eb374c7c3aa5 100644 (file)
@@ -34,9 +34,6 @@
 
 use self::Ordering::*;
 
-use marker::Sized;
-use option::Option::{self, Some};
-
 /// Trait for equality comparisons which are [partial equivalence
 /// relations](http://en.wikipedia.org/wiki/Partial_equivalence_relation).
 ///
@@ -386,7 +383,7 @@ fn partial_cmp(&self, other: &Ordering) -> Option<Ordering> {
 /// }
 /// ```
 ///
-/// You may also find it useful to use `partial_cmp()` on your type`s fields. Here
+/// You may also find it useful to use `partial_cmp()` on your type's fields. Here
 /// is an example of `Person` types who have a floating-point `height` field that
 /// is the only field to be used for sorting:
 ///
@@ -571,11 +568,7 @@ pub fn max<T: Ord>(v1: T, v2: T) -> T {
 
 // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
 mod impls {
-    use cmp::{PartialOrd, Ord, PartialEq, Eq, Ordering};
-    use cmp::Ordering::{Less, Greater, Equal};
-    use marker::Sized;
-    use option::Option;
-    use option::Option::{Some, None};
+    use cmp::Ordering::{self, Less, Greater, Equal};
 
     macro_rules! partial_eq_impl {
         ($($t:ty)*) => ($(
@@ -699,38 +692,29 @@ fn cmp(&self, other: &bool) -> Ordering {
 
     ord_impl! { char usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
 
-    // Note: This macro is a temporary hack that can be remove once we are building with a compiler
-    // that supports `!`
-    macro_rules! not_stage0 {
-        () => {
-            #[unstable(feature = "never_type", issue = "35121")]
-            impl PartialEq for ! {
-                fn eq(&self, _: &!) -> bool {
-                    *self
-                }
-            }
-
-            #[unstable(feature = "never_type", issue = "35121")]
-            impl Eq for ! {}
+    #[unstable(feature = "never_type", issue = "35121")]
+    impl PartialEq for ! {
+        fn eq(&self, _: &!) -> bool {
+            *self
+        }
+    }
 
-            #[unstable(feature = "never_type", issue = "35121")]
-            impl PartialOrd for ! {
-                fn partial_cmp(&self, _: &!) -> Option<Ordering> {
-                    *self
-                }
-            }
+    #[unstable(feature = "never_type", issue = "35121")]
+    impl Eq for ! {}
 
-            #[unstable(feature = "never_type", issue = "35121")]
-            impl Ord for ! {
-                fn cmp(&self, _: &!) -> Ordering {
-                    *self
-                }
-            }
+    #[unstable(feature = "never_type", issue = "35121")]
+    impl PartialOrd for ! {
+        fn partial_cmp(&self, _: &!) -> Option<Ordering> {
+            *self
         }
     }
 
-    #[cfg(not(stage0))]
-    not_stage0!();
+    #[unstable(feature = "never_type", issue = "35121")]
+    impl Ord for ! {
+        fn cmp(&self, _: &!) -> Ordering {
+            *self
+        }
+    }
 
     // & pointers
 
index e68f973d8d940e44460f2b4404c25be57e561ac6..5191cd76010649caa6b1e942916606bab6d18831 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use marker::Sized;
-use result::Result;
-
 /// A cheap, reference-to-reference conversion.
 ///
-/// `AsRef` is very similar to, but different than, `Borrow`. See
+/// `AsRef` is very similar to, but different than, [`Borrow`]. See
 /// [the book][book] for more.
 ///
 /// [book]: ../../book/borrow-and-asref.html
+/// [`Borrow`]: ../../std/borrow/trait.Borrow.html
 ///
 /// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which
-/// returns an `Option<T>` or a `Result<T, E>`.
+/// returns an [`Option<T>`] or a [`Result<T, E>`].
+///
+/// [`Option<T>`]: ../../std/option/enum.Option.html
+/// [`Result<T, E>`]: ../../std/result/enum.Result.html
 ///
 /// # Examples
 ///
-/// Both `String` and `&str` implement `AsRef<str>`:
+/// Both [`String`] and `&str` implement `AsRef<str>`:
+///
+/// [`String`]: ../../std/string/struct.String.html
 ///
 /// ```
 /// fn is_hello<T: AsRef<str>>(s: T) {
@@ -84,7 +87,10 @@ pub trait AsRef<T: ?Sized> {
 /// A cheap, mutable reference-to-mutable reference conversion.
 ///
 /// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which
-/// returns an `Option<T>` or a `Result<T, E>`.
+/// returns an [`Option<T>`] or a [`Result<T, E>`].
+///
+/// [`Option<T>`]: ../../std/option/enum.Option.html
+/// [`Result<T, E>`]: ../../std/result/enum.Result.html
 ///
 /// # Generic Impls
 ///
@@ -100,16 +106,16 @@ pub trait AsMut<T: ?Sized> {
 
 /// A conversion that consumes `self`, which may or may not be expensive.
 ///
-/// **Note: this trait must not fail**. If the conversion can fail, use `TryInto` or a dedicated
-/// method which returns an `Option<T>` or a `Result<T, E>`.
+/// **Note: this trait must not fail**. If the conversion can fail, use [`TryInto`] or a dedicated
+/// method which returns an [`Option<T>`] or a [`Result<T, E>`].
 ///
 /// Library authors should not directly implement this trait, but should prefer implementing
-/// the `From` trait, which offers greater flexibility and provides an equivalent `Into`
+/// the [`From`][From] trait, which offers greater flexibility and provides an equivalent `Into`
 /// implementation for free, thanks to a blanket implementation in the standard library.
 ///
 /// # Examples
 ///
-/// `String` implements `Into<Vec<u8>>`:
+/// [`String`] implements `Into<Vec<u8>>`:
 ///
 /// ```
 /// fn is_hello<T: Into<Vec<u8>>>(s: T) {
@@ -123,9 +129,15 @@ pub trait AsMut<T: ?Sized> {
 ///
 /// # Generic Impls
 ///
-/// - `From<T> for U` implies `Into<U> for T`
-/// - `into()` is reflexive, which means that `Into<T> for T` is implemented
+/// - `[From<T>][From] for U` implies `Into<U> for T`
+/// - [`into()`] is reflexive, which means that `Into<T> for T` is implemented
 ///
+/// [`TryInto`]: trait.TryInto.html
+/// [`Option<T>`]: ../../std/option/enum.Option.html
+/// [`Result<T, E>`]: ../../std/result/enum.Result.html
+/// [`String`]: ../../std/string/struct.String.html
+/// [From]: trait.From.html
+/// [`into()`]: trait.Into.html#tymethod.into
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Into<T>: Sized {
     /// Performs the conversion.
@@ -135,12 +147,12 @@ pub trait Into<T>: Sized {
 
 /// Construct `Self` via a conversion.
 ///
-/// **Note: this trait must not fail**. If the conversion can fail, use `TryFrom` or a dedicated
-/// method which returns an `Option<T>` or a `Result<T, E>`.
+/// **Note: this trait must not fail**. If the conversion can fail, use [`TryFrom`] or a dedicated
+/// method which returns an [`Option<T>`] or a [`Result<T, E>`].
 ///
 /// # Examples
 ///
-/// `String` implements `From<&str>`:
+/// [`String`] implements `From<&str>`:
 ///
 /// ```
 /// let string = "hello".to_string();
@@ -150,9 +162,15 @@ pub trait Into<T>: Sized {
 /// ```
 /// # Generic impls
 ///
-/// - `From<T> for U` implies `Into<U> for T`
-/// - `from()` is reflexive, which means that `From<T> for T` is implemented
+/// - `From<T> for U` implies `[Into<U>] for T`
+/// - [`from()`] is reflexive, which means that `From<T> for T` is implemented
 ///
+/// [`TryFrom`]: trait.TryFrom.html
+/// [`Option<T>`]: ../../std/option/enum.Option.html
+/// [`Result<T, E>`]: ../../std/result/enum.Result.html
+/// [`String`]: ../../std/string/struct.String.html
+/// [Into<U>]: trait.Into.html
+/// [`from()`]: trait.From.html#tymethod.from
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait From<T>: Sized {
     /// Performs the conversion.
@@ -163,8 +181,10 @@ pub trait From<T>: Sized {
 /// An attempted conversion that consumes `self`, which may or may not be expensive.
 ///
 /// Library authors should not directly implement this trait, but should prefer implementing
-/// the `TryFrom` trait, which offers greater flexibility and provides an equivalent `TryInto`
+/// the [`TryFrom`] trait, which offers greater flexibility and provides an equivalent `TryInto`
 /// implementation for free, thanks to a blanket implementation in the standard library.
+///
+/// [`TryFrom`]: trait.TryFrom.html
 #[unstable(feature = "try_from", issue = "33417")]
 pub trait TryInto<T>: Sized {
     /// The type returned in the event of a conversion error.
index 485ddae07fbff93b4723c3b9ffe8c45f93028e6c..85e4b2a0067698b385963e3fce5c586909673056 100644 (file)
@@ -12,8 +12,6 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use marker::Sized;
-
 /// A trait for giving a type a useful default value.
 ///
 /// Sometimes, you want to fall back to some kind of default value, and
@@ -38,7 +36,6 @@
 ///     bar: f32,
 /// }
 ///
-///
 /// fn main() {
 ///     let options: SomeOptions = Default::default();
 /// }
index 6cac80ab6245f8bf421ce5be8c7c2c514042aed6..102e3c0bd7b95f04841117ef16b8cb3c4a4e65a4 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
 use fmt::{self, FlagV1};
 
 struct PadAdapter<'a, 'b: 'a> {
index dbd715c722e13ebd4111aeb53ef2af8d70b2276a..66ef92928eb06c590dcda324ed897e454c2935ac 100644 (file)
@@ -12,8 +12,6 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use prelude::v1::*;
-
 use cell::{UnsafeCell, Cell, RefCell, Ref, RefMut, BorrowState};
 use marker::PhantomData;
 use mem;
@@ -905,8 +903,6 @@ pub fn pad_integral(&mut self,
                         prefix: &str,
                         buf: &str)
                         -> Result {
-        use char::CharExt;
-
         let mut width = buf.len();
 
         let mut sign = None;
@@ -1020,7 +1016,6 @@ fn with_padding<F>(&mut self, padding: usize, default: rt::v1::Alignment,
                        f: F) -> Result
         where F: FnOnce(&mut Formatter) -> Result,
     {
-        use char::CharExt;
         let align = match self.align {
             rt::v1::Alignment::Unknown => default,
             _ => self.align
@@ -1363,28 +1358,19 @@ fn fmt(&self, f: &mut Formatter) -> Result { $tr::fmt(&**self, f) }
 
 fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp }
 
-// Note: This macro is a temporary hack that can be remove once we are building with a compiler
-// that supports `!`
-macro_rules! not_stage0 {
-    () => {
-        #[unstable(feature = "never_type", issue = "35121")]
-        impl Debug for ! {
-            fn fmt(&self, _: &mut Formatter) -> Result {
-                *self
-            }
-        }
-
-        #[unstable(feature = "never_type", issue = "35121")]
-        impl Display for ! {
-            fn fmt(&self, _: &mut Formatter) -> Result {
-                *self
-            }
-        }
+#[unstable(feature = "never_type", issue = "35121")]
+impl Debug for ! {
+    fn fmt(&self, _: &mut Formatter) -> Result {
+        *self
     }
 }
 
-#[cfg(not(stage0))]
-not_stage0!();
+#[unstable(feature = "never_type", issue = "35121")]
+impl Display for ! {
+    fn fmt(&self, _: &mut Formatter) -> Result {
+        *self
+    }
+}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Debug for bool {
index d55e0317a949218af2cca35aebd36da2997d1dc3..0145897d8f6909568cdba4b3e066ddf6a7242520 100644 (file)
@@ -14,8 +14,6 @@
 
 // FIXME: #6220 Implement floating point formatting
 
-use prelude::v1::*;
-
 use fmt;
 use num::Zero;
 use ops::{Div, Rem, Sub};
index 27fdbd383017f08ea3e38350b47e0a6b9c9a84aa..081f0c14ec30c978e44611e66c1650d45a3df8b3 100644 (file)
@@ -71,8 +71,6 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use prelude::v1::*;
-
 use fmt;
 use marker;
 use mem;
@@ -288,8 +286,6 @@ fn default() -> BuildHasherDefault<H> {
 //////////////////////////////////////////////////////////////////////////////
 
 mod impls {
-    use prelude::v1::*;
-
     use mem;
     use slice;
     use super::*;
index 4a806a3c98602aa224b963e8a862526d3b1b48ef..bd6cae92b050c6bdb80ffde8b5aa537aacae184b 100644 (file)
@@ -10,8 +10,6 @@
 
 //! An implementation of SipHash.
 
-use prelude::v1::*;
-
 use marker::PhantomData;
 use ptr;
 
index c645608dda7902ed3189dbe7ad6af7b948fdf1b4..8271b85b01a3b93553403fb45f6c096256a1cf79 100644 (file)
@@ -46,8 +46,6 @@
             issue = "0")]
 #![allow(missing_docs)]
 
-use marker::Sized;
-
 extern "rust-intrinsic" {
 
     // NB: These intrinsics take raw pointers because they mutate aliased
     /// crate it is invoked in.
     pub fn type_id<T: ?Sized + 'static>() -> u64;
 
-    /// Creates a value initialized to so that its drop flag,
-    /// if any, says that it has been dropped.
-    ///
-    /// `init_dropped` is unsafe because it returns a datum with all
-    /// of its bytes set to the drop flag, which generally does not
-    /// correspond to a valid value.
-    ///
-    /// This intrinsic is likely to be deprecated in the future when
-    /// Rust moves to non-zeroing dynamic drop (and thus removes the
-    /// embedded drop flags that are being established by this
-    /// intrinsic).
-    pub fn init_dropped<T>() -> T;
-
     /// Creates a value initialized to zero.
     ///
     /// `init` is unsafe because it returns a zeroed-out datum,
index f530009585ecefcfbaeb43e818e9464c8e04edba..6b616f8018156bf8e5e217d46de70b4223d109e8 100644 (file)
@@ -8,19 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use clone::Clone;
-use cmp::{Ord, PartialOrd, PartialEq, Ordering};
-use default::Default;
-use ops::FnMut;
-use option::Option::{self, Some, None};
-use marker::Sized;
+use cmp::Ordering;
 
 use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, FlatMap, Fuse};
 use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, Take, TakeWhile, Rev};
 use super::{Zip, Sum, Product};
-use super::ChainState;
-use super::{DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator};
-use super::{IntoIterator, ZipImpl};
+use super::{ChainState, FromIterator, ZipImpl};
 
 fn _assert_is_object_safe(_: &Iterator<Item=()>) {}
 
index d2de0d46d746ba452c7d3aab0f8d0383b3109f22..b1d3ab1d1febcd18cb81bd4f4a566aad692342c0 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use clone::Clone;
 use cmp;
-use default::Default;
 use fmt;
 use iter_private::TrustedRandomAccess;
-use ops::FnMut;
-use option::Option::{self, Some, None};
 use usize;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::traits::{FromIterator, IntoIterator, DoubleEndedIterator, Extend};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::traits::{ExactSizeIterator, Sum, Product};
+#[unstable(feature = "fused", issue = "35602")]
+pub use self::traits::FusedIterator;
 
 mod iterator;
 mod range;
@@ -370,6 +368,10 @@ fn next_back(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next() }
 impl<I> ExactSizeIterator for Rev<I>
     where I: ExactSizeIterator + DoubleEndedIterator {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> FusedIterator for Rev<I>
+    where I: FusedIterator + DoubleEndedIterator {}
+
 /// An iterator that clones the elements of an underlying iterator.
 ///
 /// This `struct` is created by the [`cloned()`] method on [`Iterator`]. See its
@@ -413,6 +415,11 @@ impl<'a, I, T: 'a> ExactSizeIterator for Cloned<I>
     where I: ExactSizeIterator<Item=&'a T>, T: Clone
 {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, I, T: 'a> FusedIterator for Cloned<I>
+    where I: FusedIterator<Item=&'a T>, T: Clone
+{}
+
 /// An iterator that repeats endlessly.
 ///
 /// This `struct` is created by the [`cycle()`] method on [`Iterator`]. See its
@@ -451,6 +458,9 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> FusedIterator for Cycle<I> where I: Clone + Iterator {}
+
 /// An iterator that strings two iterators together.
 ///
 /// This `struct` is created by the [`chain()`] method on [`Iterator`]. See its
@@ -613,6 +623,13 @@ fn next_back(&mut self) -> Option<A::Item> {
     }
 }
 
+// Note: *both* must be fused to handle double-ended iterators.
+#[unstable(feature = "fused", issue = "35602")]
+impl<A, B> FusedIterator for Chain<A, B>
+    where A: FusedIterator,
+          B: FusedIterator<Item=A::Item>,
+{}
+
 /// An iterator that iterates two other iterators simultaneously.
 ///
 /// This `struct` is created by the [`zip()`] method on [`Iterator`]. See its
@@ -823,6 +840,10 @@ unsafe fn get_unchecked(&mut self, i: usize) -> (A::Item, B::Item) {
 
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<A, B> FusedIterator for Zip<A, B>
+    where A: FusedIterator, B: FusedIterator, {}
+
 /// An iterator that maps the values of `iter` with `f`.
 ///
 /// This `struct` is created by the [`map()`] method on [`Iterator`]. See its
@@ -919,6 +940,10 @@ fn next_back(&mut self) -> Option<B> {
 impl<B, I: ExactSizeIterator, F> ExactSizeIterator for Map<I, F>
     where F: FnMut(I::Item) -> B {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<B, I: FusedIterator, F> FusedIterator for Map<I, F>
+    where F: FnMut(I::Item) -> B {}
+
 /// An iterator that filters the elements of `iter` with `predicate`.
 ///
 /// This `struct` is created by the [`filter()`] method on [`Iterator`]. See its
@@ -979,6 +1004,10 @@ fn next_back(&mut self) -> Option<I::Item> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<I: FusedIterator, P> FusedIterator for Filter<I, P>
+    where P: FnMut(&I::Item) -> bool {}
+
 /// An iterator that uses `f` to both filter and map elements from `iter`.
 ///
 /// This `struct` is created by the [`filter_map()`] method on [`Iterator`]. See its
@@ -1041,6 +1070,10 @@ fn next_back(&mut self) -> Option<B> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<B, I: FusedIterator, F> FusedIterator for FilterMap<I, F>
+    where F: FnMut(I::Item) -> Option<B> {}
+
 /// An iterator that yields the current count and the element during iteration.
 ///
 /// This `struct` is created by the [`enumerate()`] method on [`Iterator`]. See its
@@ -1128,6 +1161,9 @@ unsafe fn get_unchecked(&mut self, i: usize) -> (usize, I::Item) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> FusedIterator for Enumerate<I> where I: FusedIterator {}
+
 /// An iterator with a `peek()` that returns an optional reference to the next
 /// element.
 ///
@@ -1195,6 +1231,9 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I: ExactSizeIterator> ExactSizeIterator for Peekable<I> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<I: FusedIterator> FusedIterator for Peekable<I> {}
+
 impl<I: Iterator> Peekable<I> {
     /// Returns a reference to the next() value without advancing the iterator.
     ///
@@ -1296,6 +1335,10 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<I, P> FusedIterator for SkipWhile<I, P>
+    where I: FusedIterator, P: FnMut(&I::Item) -> bool {}
+
 /// An iterator that only accepts elements while `predicate` is true.
 ///
 /// This `struct` is created by the [`take_while()`] method on [`Iterator`]. See its
@@ -1351,6 +1394,10 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<I, P> FusedIterator for TakeWhile<I, P>
+    where I: FusedIterator, P: FnMut(&I::Item) -> bool {}
+
 /// An iterator that skips over `n` elements of `iter`.
 ///
 /// This `struct` is created by the [`skip()`] method on [`Iterator`]. See its
@@ -1442,6 +1489,9 @@ fn next_back(&mut self) -> Option<Self::Item> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> FusedIterator for Skip<I> where I: FusedIterator {}
+
 /// An iterator that only iterates over the first `n` iterations of `iter`.
 ///
 /// This `struct` is created by the [`take()`] method on [`Iterator`]. See its
@@ -1503,6 +1553,8 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I> ExactSizeIterator for Take<I> where I: ExactSizeIterator {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> FusedIterator for Take<I> where I: FusedIterator {}
 
 /// An iterator to maintain state while iterating another iterator.
 ///
@@ -1549,6 +1601,10 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<B, I, St, F> FusedIterator for Scan<I, St, F>
+    where I: FusedIterator, F: FnMut(&mut St, I::Item) -> Option<B> {}
+
 /// An iterator that maps each element to an iterator, and yields the elements
 /// of the produced iterators.
 ///
@@ -1635,6 +1691,10 @@ fn next_back(&mut self) -> Option<U::Item> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<I, U, F> FusedIterator for FlatMap<I, U, F>
+    where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {}
+
 /// An iterator that yields `None` forever after the underlying iterator
 /// yields `None` once.
 ///
@@ -1651,12 +1711,15 @@ pub struct Fuse<I> {
     done: bool
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> FusedIterator for Fuse<I> where I: Iterator {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I> Iterator for Fuse<I> where I: Iterator {
     type Item = <I as Iterator>::Item;
 
     #[inline]
-    fn next(&mut self) -> Option<<I as Iterator>::Item> {
+    default fn next(&mut self) -> Option<<I as Iterator>::Item> {
         if self.done {
             None
         } else {
@@ -1667,7 +1730,7 @@ fn next(&mut self) -> Option<<I as Iterator>::Item> {
     }
 
     #[inline]
-    fn nth(&mut self, n: usize) -> Option<I::Item> {
+    default fn nth(&mut self, n: usize) -> Option<I::Item> {
         if self.done {
             None
         } else {
@@ -1678,7 +1741,7 @@ fn nth(&mut self, n: usize) -> Option<I::Item> {
     }
 
     #[inline]
-    fn last(self) -> Option<I::Item> {
+    default fn last(self) -> Option<I::Item> {
         if self.done {
             None
         } else {
@@ -1687,7 +1750,7 @@ fn last(self) -> Option<I::Item> {
     }
 
     #[inline]
-    fn count(self) -> usize {
+    default fn count(self) -> usize {
         if self.done {
             0
         } else {
@@ -1696,7 +1759,7 @@ fn count(self) -> usize {
     }
 
     #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
+    default fn size_hint(&self) -> (usize, Option<usize>) {
         if self.done {
             (0, Some(0))
         } else {
@@ -1708,7 +1771,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I> DoubleEndedIterator for Fuse<I> where I: DoubleEndedIterator {
     #[inline]
-    fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
+    default fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
         if self.done {
             None
         } else {
@@ -1719,6 +1782,53 @@ fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
     }
 }
 
+unsafe impl<I> TrustedRandomAccess for Fuse<I>
+    where I: TrustedRandomAccess,
+{
+    unsafe fn get_unchecked(&mut self, i: usize) -> I::Item {
+        self.iter.get_unchecked(i)
+    }
+}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> Iterator for Fuse<I> where I: FusedIterator {
+    #[inline]
+    fn next(&mut self) -> Option<<I as Iterator>::Item> {
+        self.iter.next()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<I::Item> {
+        self.iter.nth(n)
+    }
+
+    #[inline]
+    fn last(self) -> Option<I::Item> {
+        self.iter.last()
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.iter.count()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
+
+#[unstable(feature = "fused", reason = "recently added", issue = "35602")]
+impl<I> DoubleEndedIterator for Fuse<I>
+    where I: DoubleEndedIterator + FusedIterator
+{
+    #[inline]
+    fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
+        self.iter.next_back()
+    }
+}
+
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I> ExactSizeIterator for Fuse<I> where I: ExactSizeIterator {}
 
@@ -1788,3 +1898,7 @@ fn next_back(&mut self) -> Option<I::Item> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I: ExactSizeIterator, F> ExactSizeIterator for Inspect<I, F>
     where F: FnMut(&I::Item) {}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<I: FusedIterator, F> FusedIterator for Inspect<I, F>
+    where F: FnMut(&I::Item) {}
index 079dfe2a81f8090aa8001a590438205d598140da..66d05d81d80cd7e92157bfd865eb5d353713791f 100644 (file)
@@ -8,15 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use clone::Clone;
-use cmp::PartialOrd;
 use mem;
 use ops::{self, Add, Sub};
-use option::Option::{self, Some, None};
-use marker::Sized;
 use usize;
 
-use super::{DoubleEndedIterator, ExactSizeIterator, Iterator};
+use super::FusedIterator;
 
 /// Objects that can be stepped over in both directions.
 ///
@@ -267,14 +263,12 @@ impl<A: Step> ops::RangeFrom<A> {
     /// # Examples
     ///
     /// ```
-    /// # #![feature(step_by)]
-    ///
-    /// for i in (0u8..).step_by(2).take(10) {
-    ///     println!("{}", i);
+    /// #![feature(step_by)]
+    /// fn main() {
+    ///     let result: Vec<_> = (0..).step_by(2).take(5).collect();
+    ///     assert_eq!(result, vec![0, 2, 4, 6, 8]);
     /// }
     /// ```
-    ///
-    /// This prints the first ten even natural integers (0 to 18).
     #[unstable(feature = "step_by", reason = "recent addition",
                issue = "27741")]
     pub fn step_by(self, by: A) -> StepBy<A, Self> {
@@ -295,8 +289,10 @@ impl<A: Step> ops::Range<A> {
     ///
     /// ```
     /// #![feature(step_by)]
-    /// let result: Vec<_> = (0..10).step_by(2).collect();
-    /// assert_eq!(result, vec![0, 2, 4, 6, 8]);
+    /// fn main() {
+    ///     let result: Vec<_> = (0..10).step_by(2).collect();
+    ///     assert_eq!(result, vec![0, 2, 4, 6, 8]);
+    /// }
     /// ```
     #[unstable(feature = "step_by", reason = "recent addition",
                issue = "27741")]
@@ -319,20 +315,8 @@ impl<A: Step> ops::RangeInclusive<A> {
     /// ```
     /// #![feature(step_by, inclusive_range_syntax)]
     ///
-    /// for i in (0...10).step_by(2) {
-    ///     println!("{}", i);
-    /// }
-    /// ```
-    ///
-    /// This prints:
-    ///
-    /// ```text
-    /// 0
-    /// 2
-    /// 4
-    /// 6
-    /// 8
-    /// 10
+    /// let result: Vec<_> = (0...10).step_by(2).collect();
+    /// assert_eq!(result, vec![0, 2, 4, 6, 8, 10]);
     /// ```
     #[unstable(feature = "step_by", reason = "recent addition",
                issue = "27741")]
@@ -364,6 +348,10 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<A> FusedIterator for StepBy<A, ops::RangeFrom<A>>
+    where A: Clone, for<'a> &'a A: Add<&'a A, Output = A> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A: Step + Clone> Iterator for StepBy<A, ops::Range<A>> {
     type Item = A;
@@ -401,6 +389,9 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<A: Step + Clone> FusedIterator for StepBy<A, ops::Range<A>> {}
+
 #[unstable(feature = "inclusive_range",
            reason = "recently added, follows RFC",
            issue = "28237")]
@@ -468,6 +459,9 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<A: Step + Clone> FusedIterator for StepBy<A, ops::RangeInclusive<A>> {}
+
 macro_rules! range_exact_iter_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -526,6 +520,10 @@ fn next_back(&mut self) -> Option<A> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<A> FusedIterator for ops::Range<A>
+    where A: Step, for<'a> &'a A: Add<&'a A, Output = A> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A: Step> Iterator for ops::RangeFrom<A> where
     for<'a> &'a A: Add<&'a A, Output = A>
@@ -540,6 +538,10 @@ fn next(&mut self) -> Option<A> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<A> FusedIterator for ops::RangeFrom<A>
+    where A: Step, for<'a> &'a A: Add<&'a A, Output = A> {}
+
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
 impl<A: Step> Iterator for ops::RangeInclusive<A> where
     for<'a> &'a A: Add<&'a A, Output = A>
@@ -638,3 +640,7 @@ fn next_back(&mut self) -> Option<A> {
         n
     }
 }
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<A> FusedIterator for ops::RangeInclusive<A>
+    where A: Step, for<'a> &'a A: Add<&'a A, Output = A> {}
index ecd4a78b9e760000686fb8c50f51d7704d8eb31f..da346eaf1db96d24ee991be0bfe431e201217b52 100644 (file)
@@ -8,14 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use clone::Clone;
-use default::Default;
 use fmt;
 use marker;
-use option::Option::{self, Some, None};
 use usize;
 
-use super::{DoubleEndedIterator, IntoIterator, Iterator, ExactSizeIterator};
+use super::FusedIterator;
 
 /// An iterator that repeats an element endlessly.
 ///
@@ -44,6 +41,9 @@ impl<A: Clone> DoubleEndedIterator for Repeat<A> {
     fn next_back(&mut self) -> Option<A> { Some(self.element.clone()) }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<A: Clone> FusedIterator for Repeat<A> {}
+
 /// Creates a new iterator that endlessly repeats a single element.
 ///
 /// The `repeat()` function repeats a single value over and over and over and
@@ -138,6 +138,9 @@ fn len(&self) -> usize {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for Empty<T> {}
+
 // not #[derive] because that adds a Clone bound on T,
 // which isn't necessary.
 #[stable(feature = "iter_empty", since = "1.2.0")]
@@ -213,6 +216,9 @@ fn len(&self) -> usize {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for Once<T> {}
+
 /// Creates an iterator that yields an element exactly once.
 ///
 /// This is commonly used to adapt a single value into a [`chain()`] of other
index 4cbabe3f5edafc1036216b05470c7cd7d5478169..59e23c4d960567d6af82c729eada07b6becd1c14 100644 (file)
@@ -8,11 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use option::Option::{self, Some};
-use marker::Sized;
-
-use super::Iterator;
-
 /// Conversion from an `Iterator`.
 ///
 /// By implementing `FromIterator` for a type, you define how it will be
@@ -563,10 +558,11 @@ impl<'a, I: ExactSizeIterator + ?Sized> ExactSizeIterator for &'a mut I {}
 /// implement the trait can be generated by the `sum` method. Like
 /// `FromIterator` this trait should rarely be called directly and instead
 /// interacted with through `Iterator::sum`.
-#[unstable(feature = "iter_arith_traits", issue = "34529")]
+#[stable(feature = "iter_arith_traits", since = "1.12.0")]
 pub trait Sum<A = Self>: Sized {
     /// Method which takes an iterator and generates `Self` from the elements by
     /// "summing up" the items.
+    #[stable(feature = "iter_arith_traits", since = "1.12.0")]
     fn sum<I: Iterator<Item=A>>(iter: I) -> Self;
 }
 
@@ -577,16 +573,17 @@ pub trait Sum<A = Self>: Sized {
 /// which implement the trait can be generated by the `product` method. Like
 /// `FromIterator` this trait should rarely be called directly and instead
 /// interacted with through `Iterator::product`.
-#[unstable(feature = "iter_arith_traits", issue = "34529")]
+#[stable(feature = "iter_arith_traits", since = "1.12.0")]
 pub trait Product<A = Self>: Sized {
     /// Method which takes an iterator and generates `Self` from the elements by
     /// multiplying the items.
+    #[stable(feature = "iter_arith_traits", since = "1.12.0")]
     fn product<I: Iterator<Item=A>>(iter: I) -> Self;
 }
 
 macro_rules! integer_sum_product {
     ($($a:ident)*) => ($(
-        #[unstable(feature = "iter_arith_traits", issue = "34529")]
+        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
         impl Sum for $a {
             fn sum<I: Iterator<Item=$a>>(iter: I) -> $a {
                 iter.fold(0, |a, b| {
@@ -595,7 +592,7 @@ fn sum<I: Iterator<Item=$a>>(iter: I) -> $a {
             }
         }
 
-        #[unstable(feature = "iter_arith_traits", issue = "34529")]
+        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
         impl Product for $a {
             fn product<I: Iterator<Item=$a>>(iter: I) -> $a {
                 iter.fold(1, |a, b| {
@@ -604,7 +601,7 @@ fn product<I: Iterator<Item=$a>>(iter: I) -> $a {
             }
         }
 
-        #[unstable(feature = "iter_arith_traits", issue = "34529")]
+        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
         impl<'a> Sum<&'a $a> for $a {
             fn sum<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
                 iter.fold(0, |a, b| {
@@ -613,7 +610,7 @@ fn sum<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
             }
         }
 
-        #[unstable(feature = "iter_arith_traits", issue = "34529")]
+        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
         impl<'a> Product<&'a $a> for $a {
             fn product<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
                 iter.fold(1, |a, b| {
@@ -626,28 +623,28 @@ fn product<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
 
 macro_rules! float_sum_product {
     ($($a:ident)*) => ($(
-        #[unstable(feature = "iter_arith_traits", issue = "34529")]
+        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
         impl Sum for $a {
             fn sum<I: Iterator<Item=$a>>(iter: I) -> $a {
                 iter.fold(0.0, |a, b| a + b)
             }
         }
 
-        #[unstable(feature = "iter_arith_traits", issue = "34529")]
+        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
         impl Product for $a {
             fn product<I: Iterator<Item=$a>>(iter: I) -> $a {
                 iter.fold(1.0, |a, b| a * b)
             }
         }
 
-        #[unstable(feature = "iter_arith_traits", issue = "34529")]
+        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
         impl<'a> Sum<&'a $a> for $a {
             fn sum<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
                 iter.fold(0.0, |a, b| a + *b)
             }
         }
 
-        #[unstable(feature = "iter_arith_traits", issue = "34529")]
+        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
         impl<'a> Product<&'a $a> for $a {
             fn product<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
                 iter.fold(1.0, |a, b| a * *b)
@@ -658,3 +655,19 @@ fn product<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
 
 integer_sum_product! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
 float_sum_product! { f32 f64 }
+
+/// An iterator that always continues to yield `None` when exhausted.
+///
+/// Calling next on a fused iterator that has returned `None` once is guaranteed
+/// to return `None` again. This trait is should be implemented by all iterators
+/// that behave this way because it allows for some significant optimizations.
+///
+/// Note: In general, you should not use `FusedIterator` in generic bounds if
+/// you need a fused iterator. Instead, you should just call `Iterator::fused()`
+/// on the iterator. If the iterator is already fused, the additional `Fuse`
+/// wrapper will be a no-op with no performance penalty.
+#[unstable(feature = "fused", issue = "35602")]
+pub trait FusedIterator: Iterator {}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {}
index effe43cc67cea8912573c96abd40afb00612b99f..83eeef31ab054cd074c3fa515a78f6ead1401594 100644 (file)
@@ -9,8 +9,6 @@
 // except according to those terms.
 
 
-use iter::ExactSizeIterator;
-
 /// An iterator whose items are random accessible efficiently
 ///
 /// # Safety
index 2a9678203e17805004d88aa07e4b1773810bda01..1ae4cf8e5ef5f05b37c920206786768eba05d41c 100644 (file)
@@ -67,8 +67,6 @@
 #![deny(missing_debug_implementations)]
 #![cfg_attr(not(stage0), deny(warnings))]
 
-#![cfg_attr(stage0, allow(unused_attributes))]
-
 #![feature(allow_internal_unstable)]
 #![feature(asm)]
 #![feature(associated_type_defaults)]
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
 #![feature(question_mark)]
+#![feature(never_type)]
+#![feature(prelude_import)]
 
-// NOTE: remove the cfg_attr next snapshot
-#![cfg_attr(not(stage0), feature(never_type))]
+#[prelude_import]
+#[allow(unused)]
+use prelude::v1::*;
 
 #[macro_use]
 mod macros;
index c916ad930ff105988b7be772c07b45a595f3aa25..f29a49dd5fe1ac236209d833849ad88c12746e29 100644 (file)
@@ -189,10 +189,19 @@ macro_rules! debug_assert_eq {
     ($($arg:tt)*) => (if cfg!(debug_assertions) { assert_eq!($($arg)*); })
 }
 
-/// Helper macro for unwrapping `Result` values while returning early with an
-/// error if the value of the expression is `Err`. Can only be used in
-/// functions that return `Result` because of the early return of `Err` that
-/// it provides.
+/// Helper macro for reducing boilerplate code for matching `Result` together
+/// with converting downstream errors.
+///
+/// `try!` matches the given `Result`. In case of the `Ok` variant, the
+/// expression has the value of the wrapped value.
+///
+/// In case of the `Err` variant, it retrieves the inner error. `try!` then
+/// performs conversion using `From`. This provides automatic conversion
+/// between specialized errors and more general ones. The resulting
+/// error is then immediately returned.
+///
+/// Because of the early return, `try!` can only be used in functions that
+/// return `Result`.
 ///
 /// # Examples
 ///
@@ -201,18 +210,28 @@ macro_rules! debug_assert_eq {
 /// use std::fs::File;
 /// use std::io::prelude::*;
 ///
-/// fn write_to_file_using_try() -> Result<(), io::Error> {
+/// enum MyError {
+///     FileWriteError
+/// }
+///
+/// impl From<io::Error> for MyError {
+///     fn from(e: io::Error) -> MyError {
+///         MyError::FileWriteError
+///     }
+/// }
+///
+/// fn write_to_file_using_try() -> Result<(), MyError> {
 ///     let mut file = try!(File::create("my_best_friends.txt"));
 ///     try!(file.write_all(b"This is a list of my best friends."));
 ///     println!("I wrote to the file");
 ///     Ok(())
 /// }
 /// // This is equivalent to:
-/// fn write_to_file_using_match() -> Result<(), io::Error> {
+/// fn write_to_file_using_match() -> Result<(), MyError> {
 ///     let mut file = try!(File::create("my_best_friends.txt"));
 ///     match file.write_all(b"This is a list of my best friends.") {
 ///         Ok(v) => v,
-///         Err(e) => return Err(e),
+///         Err(e) => return Err(From::from(e)),
 ///     }
 ///     println!("I wrote to the file");
 ///     Ok(())
index 894982abaa939879f58e410e03c595ddf17cb684..0a46813df7eb82774e94d5e081598a2321963e24 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use clone::Clone;
 use cmp;
-use default::Default;
-use option::Option;
 use hash::Hash;
 use hash::Hasher;
 
@@ -414,8 +411,6 @@ fn default() -> $t<T> {
 impls! { PhantomData }
 
 mod impls {
-    use super::{Send, Sync, Sized};
-
     #[stable(feature = "rust1", since = "1.0.0")]
     unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {}
     #[stable(feature = "rust1", since = "1.0.0")]
index 5c2179ccf33a1a6404ef4db66f047c0e7b77e6e7..9c61f76ac8895b9e8817447030606e8b5d1da6e3 100644 (file)
@@ -15,7 +15,6 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use marker::Sized;
 use intrinsics;
 use ptr;
 
@@ -241,27 +240,6 @@ pub unsafe fn zeroed<T>() -> T {
     intrinsics::init()
 }
 
-/// Creates a value initialized to an unspecified series of bytes.
-///
-/// The byte sequence usually indicates that the value at the memory
-/// in question has been dropped. Thus, *if* T carries a drop flag,
-/// any associated destructor will not be run when the value falls out
-/// of scope.
-///
-/// Some code at one time used the `zeroed` function above to
-/// accomplish this goal.
-///
-/// This function is expected to be deprecated with the transition
-/// to non-zeroing drop.
-#[inline]
-#[unstable(feature = "filling_drop", issue = "5016")]
-pub unsafe fn dropped<T>() -> T {
-    #[inline(always)]
-    unsafe fn dropped_impl<T>() -> T { intrinsics::init_dropped() }
-
-    dropped_impl()
-}
-
 /// Bypasses Rust's normal memory-initialization checks by pretending to
 /// produce a value of type T, while doing nothing at all.
 ///
@@ -518,56 +496,6 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn drop<T>(_x: T) { }
 
-macro_rules! repeat_u8_as_u16 {
-    ($name:expr) => { (($name as u16) <<  8 |
-                       ($name as u16)) }
-}
-macro_rules! repeat_u8_as_u32 {
-    ($name:expr) => { (($name as u32) << 24 |
-                       ($name as u32) << 16 |
-                       ($name as u32) <<  8 |
-                       ($name as u32)) }
-}
-macro_rules! repeat_u8_as_u64 {
-    ($name:expr) => { ((repeat_u8_as_u32!($name) as u64) << 32 |
-                       (repeat_u8_as_u32!($name) as u64)) }
-}
-
-// NOTE: Keep synchronized with values used in librustc_trans::trans::adt.
-//
-// In particular, the POST_DROP_U8 marker must never equal the
-// DTOR_NEEDED_U8 marker.
-//
-// For a while pnkfelix was using 0xc1 here.
-// But having the sign bit set is a pain, so 0x1d is probably better.
-//
-// And of course, 0x00 brings back the old world of zero'ing on drop.
-#[unstable(feature = "filling_drop", issue = "5016")]
-#[allow(missing_docs)]
-pub const POST_DROP_U8: u8 = 0x1d;
-#[unstable(feature = "filling_drop", issue = "5016")]
-#[allow(missing_docs)]
-pub const POST_DROP_U16: u16 = repeat_u8_as_u16!(POST_DROP_U8);
-#[unstable(feature = "filling_drop", issue = "5016")]
-#[allow(missing_docs)]
-pub const POST_DROP_U32: u32 = repeat_u8_as_u32!(POST_DROP_U8);
-#[unstable(feature = "filling_drop", issue = "5016")]
-#[allow(missing_docs)]
-pub const POST_DROP_U64: u64 = repeat_u8_as_u64!(POST_DROP_U8);
-
-#[cfg(target_pointer_width = "16")]
-#[unstable(feature = "filling_drop", issue = "5016")]
-#[allow(missing_docs)]
-pub const POST_DROP_USIZE: usize = POST_DROP_U16 as usize;
-#[cfg(target_pointer_width = "32")]
-#[unstable(feature = "filling_drop", issue = "5016")]
-#[allow(missing_docs)]
-pub const POST_DROP_USIZE: usize = POST_DROP_U32 as usize;
-#[cfg(target_pointer_width = "64")]
-#[unstable(feature = "filling_drop", issue = "5016")]
-#[allow(missing_docs)]
-pub const POST_DROP_USIZE: usize = POST_DROP_U64 as usize;
-
 /// Interprets `src` as `&U`, and then reads `src` without moving the contained
 /// value.
 ///
index 92bbc4efb7cc1d78ab45fe0d0828401d544608d3..47afaf77353ee42803a246a61d1bc98a64bb9ef1 100644 (file)
@@ -13,7 +13,6 @@
             reason = "needs an RFC to flesh out the design",
             issue = "27730")]
 
-use marker::Sized;
 use ops::{CoerceUnsized, Deref};
 
 /// Unsafe trait to indicate what types are usable with the NonZero struct
index a881b539cedebf0ba5dbb4b2c6342f458c6c89ba..bc503ba3e46aedc0ccb983818e970680268b5c93 100644 (file)
@@ -27,8 +27,6 @@
             issue = "0")]
 #![macro_use]
 
-use prelude::v1::*;
-
 use mem;
 use intrinsics;
 
@@ -494,6 +492,5 @@ fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
 // this one is used for testing only.
 #[doc(hidden)]
 pub mod tests {
-    use prelude::v1::*;
     define_bignum!(Big8x3: type=u8, n=3);
 }
index 4761727cec03ff93594b2fb4d706c960ba99479a..604bc7c10dea0aedaa886e976f1c63e392314fce 100644 (file)
@@ -10,7 +10,6 @@
 
 //! The various algorithms from the paper.
 
-use prelude::v1::*;
 use cmp::min;
 use cmp::Ordering::{Less, Equal, Greater};
 use num::diy_float::Fp;
@@ -47,7 +46,6 @@ pub fn set_precision<T>() { }
 #[cfg(all(target_arch="x86", not(target_feature="sse2")))]
 mod fpu_precision {
     use mem::size_of;
-    use ops::Drop;
 
     /// A structure used to preserve the original value of the FPU control word, so that it can be
     /// restored when the structure is dropped.
index ff2d85307b1060ef6cb2c5a2bcc619a80fe2b7f5..cd40e399ab95e6639ebb579e0e89776db8179b96 100644 (file)
@@ -92,7 +92,6 @@
             reason = "internal routines only exposed for testing",
             issue = "0")]
 
-use prelude::v1::*;
 use fmt;
 use str::FromStr;
 
index 81e7856633b2571f9f0a33c2295671deefc1bda9..34b41fa9decd295703f903bb48aad4f4d4c5b0cc 100644 (file)
@@ -12,7 +12,6 @@
 
 // FIXME This module's name is a bit unfortunate, since other modules also import `core::num`.
 
-use prelude::v1::*;
 use cmp::Ordering::{self, Less, Equal, Greater};
 
 pub use num::bignum::Big32x40 as Big;
index fce1c250a022e0f44075f52f940d09ffb5b893e6..d20986faa0fc24b1dfde7fcfc65db70ab6c82e6a 100644 (file)
@@ -20,7 +20,6 @@
 //! modules rely on to not panic (or overflow) in turn.
 //! To make matters worse, all that happens in a single pass over the input.
 //! So, be careful when modifying anything, and double-check with the other modules.
-use prelude::v1::*;
 use super::num;
 use self::ParseResult::{Valid, ShortcutToInf, ShortcutToZero, Invalid};
 
index 68e4dc4b359efa73fb3ee5373004d569f756fcd9..e3b58b6cc7ce94407980d2c351e71b2a982f2565 100644 (file)
@@ -27,7 +27,6 @@
 //! Many functions in this module only handle normal numbers. The dec2flt routines conservatively
 //! take the universally-correct slow path (Algorithm M) for very small and very large numbers.
 //! That algorithm needs only next_float() which does handle subnormals and zeros.
-use prelude::v1::*;
 use u32;
 use cmp::Ordering::{Less, Equal, Greater};
 use ops::{Mul, Div, Neg};
index 5420e7bdd2a5a064092b398387c89ec884c97c6b..276667e44aae1a42c65a91e14d2225d805fff8db 100644 (file)
@@ -10,8 +10,6 @@
 
 //! Decodes a floating-point value into individual parts and error ranges.
 
-use prelude::v1::*;
-
 use {f32, f64};
 use num::FpCategory;
 use num::dec2flt::rawfp::RawFloat;
index b549f33424264d3ddcf741b19cc8408486aabd74..f6c03a59f81e4ed7750a3cda89fc5841e64a3505 100644 (file)
             reason = "internal routines only exposed for testing",
             issue = "0")]
 
-use prelude::v1::*;
 use i16;
 pub use self::decoder::{decode, DecodableFloat, FullDecoded, Decoded};
 
index 2d68c3a6d026ec397cd7fdd55ec849e961cf8d72..6aa4f297e75ba7f79fe6164867c36dd01ee860b5 100644 (file)
@@ -15,8 +15,6 @@
     quickly and accurately. SIGPLAN Not. 31, 5 (May. 1996), 108-116.
 */
 
-use prelude::v1::*;
-
 use cmp::Ordering;
 
 use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up};
index 13e01d9a7f7ab548918288fbbe693da00c980cf1..cf70a1978f5e6d53aa3de3fdf7b02fecfd459806 100644 (file)
@@ -16,8 +16,6 @@
     accurately with integers. SIGPLAN Not. 45, 6 (June 2010), 233-243.
 */
 
-use prelude::v1::*;
-
 use num::diy_float::Fp;
 use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up};
 
index 4636811aa46da2c95f96d6c87bf9cdd3a06a09b6..29ee29eb3eb7f61584dbbf0f8b0a1a6708679e81 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use char::CharExt;
-use cmp::PartialOrd;
-use convert::{From, TryFrom};
+use convert::TryFrom;
 use fmt;
 use intrinsics;
-use marker::{Copy, Sized};
 use mem::size_of;
-use option::Option::{self, Some, None};
-use result::Result::{self, Ok, Err};
-use str::{FromStr, StrExt};
-use slice::SliceExt;
+use str::FromStr;
 
 /// Provides intentionally-wrapped arithmetic on `T`.
 ///
index 4ac1b8394f4508cd26016e37945b2bd347c71736..85a52da332db53a8842a803ee14b83dd70fbf2d8 100644 (file)
 //! custom operators are required, you should look toward macros or compiler
 //! plugins to extend Rust's syntax.
 //!
+//! Note that the `&&` and `||` operators short-circuit, i.e. they only
+//! evaluate their second operand if it contributes to the result. Since this
+//! behavior is not enforceable by traits, `&&` and `||` are not supported as
+//! overloadable operators.
+//!
 //! Many of the operators take their operands by value. In non-generic
 //! contexts involving built-in types, this is usually not a problem.
 //! However, using these operators in generic code, requires some
 //! }
 //! ```
 //!
-//! See the documentation for each trait for a minimum implementation that
-//! prints something to the screen.
+//! 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
+//! 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:
+//!
+//! ```rust
+//! fn call_with_one<F>(func: F) -> usize
+//!     where F: Fn(usize) -> usize
+//! {
+//!     func(1)
+//! }
+//!
+//! let double = |x| x * 2;
+//! assert_eq!(call_with_one(double), 2);
+//! ```
+//!
+//! Taking a `FnMut` as a parameter:
+//!
+//! ```rust
+//! fn do_twice<F>(mut func: F)
+//!     where F: FnMut()
+//! {
+//!     func();
+//!     func();
+//! }
+//!
+//! let mut x: usize = 1;
+//! {
+//!     let add_two_to_x = || x += 2;
+//!     do_twice(add_two_to_x);
+//! }
+//!
+//! assert_eq!(x, 5);
+//! ```
+//!
+//! Taking a `FnOnce` as a parameter:
+//!
+//! ```rust
+//! fn consume_with_relish<F>(func: F)
+//!     where F: FnOnce() -> String
+//! {
+//!     // `func` consumes its captured variables, so it cannot be run more
+//!     // than once
+//!     println!("Consumed: {}", func());
+//!
+//!     println!("Delicious!");
+//!
+//!     // Attempting to invoke `func()` again will throw a `use of moved
+//!     // value` error for `func`
+//! }
+//!
+//! let x = String::from("x");
+//! let consume_and_return_x = move || x;
+//! consume_with_relish(consume_and_return_x);
+//!
+//! // `consume_and_return_x` can no longer be invoked at this point
+//! ```
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use cmp::PartialOrd;
 use fmt;
-use marker::{Sized, Unsize};
+use marker::Unsize;
 
 /// The `Drop` trait is used to run some code when a value goes out of scope.
 /// This is sometimes called a 'destructor'.
@@ -107,6 +177,13 @@ pub trait Drop {
     ///
     /// After this function is over, the memory of `self` will be deallocated.
     ///
+    /// This function cannot be called explicitly. This is compiler error
+    /// [0040]. However, the [`std::mem::drop`] function in the prelude can be
+    /// used to call the argument's `Drop` implementation.
+    ///
+    /// [0040]: https://doc.rust-lang.org/error-index.html#E0040
+    /// [`std::mem::drop`]: https://doc.rust-lang.org/std/mem/fn.drop.html
+    ///
     /// # Panics
     ///
     /// Given that a `panic!` will call `drop()` as it unwinds, any `panic!` in
@@ -171,27 +248,46 @@ fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
 ///
 /// # Examples
 ///
-/// A trivial implementation of `Add`. When `Foo + Foo` happens, it ends up
-/// calling `add`, and therefore, `main` prints `Adding!`.
+/// This example creates a `Point` struct that implements the `Add` trait, and
+/// then demonstrates adding two `Point`s.
 ///
 /// ```
 /// use std::ops::Add;
 ///
-/// struct Foo;
+/// #[derive(Debug)]
+/// struct Point {
+///     x: i32,
+///     y: i32,
+/// }
 ///
-/// impl Add for Foo {
-///     type Output = Foo;
+/// impl Add for Point {
+///     type Output = Point;
 ///
-///     fn add(self, _rhs: Foo) -> Foo {
-///         println!("Adding!");
-///         self
+///     fn add(self, other: Point) -> Point {
+///         Point {
+///             x: self.x + other.x,
+///             y: self.y + other.y,
+///         }
+///     }
+/// }
+///
+/// impl PartialEq for Point {
+///     fn eq(&self, other: &Self) -> bool {
+///         self.x == other.x && self.y == other.y
 ///     }
 /// }
 ///
 /// fn main() {
-///     Foo + Foo;
+///     assert_eq!(Point { x: 1, y: 0 } + Point { x: 2, y: 3 },
+///                Point { x: 3, y: 3 });
 /// }
 /// ```
+///
+/// Note that `RHS = Self` by default, but this is not mandatory. For example,
+/// [std::time::SystemTime] implements `Add<Duration>`, which permits
+/// operations of the form `SystemTime = SystemTime + Duration`.
+///
+/// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html
 #[lang = "add"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Add<RHS=Self> {
@@ -225,27 +321,46 @@ fn add(self, other: $t) -> $t { self + other }
 ///
 /// # Examples
 ///
-/// A trivial implementation of `Sub`. When `Foo - Foo` happens, it ends up
-/// calling `sub`, and therefore, `main` prints `Subtracting!`.
+/// This example creates a `Point` struct that implements the `Sub` trait, and
+/// then demonstrates subtracting two `Point`s.
 ///
 /// ```
 /// use std::ops::Sub;
 ///
-/// struct Foo;
+/// #[derive(Debug)]
+/// struct Point {
+///     x: i32,
+///     y: i32,
+/// }
 ///
-/// impl Sub for Foo {
-///     type Output = Foo;
+/// impl Sub for Point {
+///     type Output = Point;
 ///
-///     fn sub(self, _rhs: Foo) -> Foo {
-///         println!("Subtracting!");
-///         self
+///     fn sub(self, other: Point) -> Point {
+///         Point {
+///             x: self.x - other.x,
+///             y: self.y - other.y,
+///         }
+///     }
+/// }
+///
+/// impl PartialEq for Point {
+///     fn eq(&self, other: &Self) -> bool {
+///         self.x == other.x && self.y == other.y
 ///     }
 /// }
 ///
 /// fn main() {
-///     Foo - Foo;
+///     assert_eq!(Point { x: 3, y: 3 } - Point { x: 2, y: 3 },
+///                Point { x: 1, y: 0 });
 /// }
 /// ```
+///
+/// Note that `RHS = Self` by default, but this is not mandatory. For example,
+/// [std::time::SystemTime] implements `Sub<Duration>`, which permits
+/// operations of the form `SystemTime = SystemTime - Duration`.
+///
+/// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html
 #[lang = "sub"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Sub<RHS=Self> {
@@ -279,26 +394,94 @@ fn sub(self, other: $t) -> $t { self - other }
 ///
 /// # Examples
 ///
-/// A trivial implementation of `Mul`. When `Foo * Foo` happens, it ends up
-/// calling `mul`, and therefore, `main` prints `Multiplying!`.
+/// Implementing a `Mul`tipliable rational number struct:
 ///
 /// ```
 /// use std::ops::Mul;
 ///
-/// struct Foo;
+/// // The uniqueness of rational numbers in lowest terms is a consequence of
+/// // the fundamental theorem of arithmetic.
+/// #[derive(Eq)]
+/// #[derive(PartialEq, Debug)]
+/// struct Rational {
+///     nominator: usize,
+///     denominator: usize,
+/// }
+///
+/// impl Rational {
+///     fn new(nominator: usize, denominator: usize) -> Self {
+///         if denominator == 0 {
+///             panic!("Zero is an invalid denominator!");
+///         }
+///
+///         // Reduce to lowest terms by dividing by the greatest common
+///         // divisor.
+///         let gcd = gcd(nominator, denominator);
+///         Rational {
+///             nominator: nominator / gcd,
+///             denominator: denominator / gcd,
+///         }
+///     }
+/// }
 ///
-/// impl Mul for Foo {
-///     type Output = Foo;
+/// impl Mul for Rational {
+///     // The multiplication of rational numbers is a closed operation.
+///     type Output = Self;
 ///
-///     fn mul(self, _rhs: Foo) -> Foo {
-///         println!("Multiplying!");
-///         self
+///     fn mul(self, rhs: Self) -> Self {
+///         let nominator = self.nominator * rhs.nominator;
+///         let denominator = self.denominator * rhs.denominator;
+///         Rational::new(nominator, denominator)
 ///     }
 /// }
 ///
-/// fn main() {
-///     Foo * Foo;
+/// // Euclid's two-thousand-year-old algorithm for finding the greatest common
+/// // divisor.
+/// fn gcd(x: usize, y: usize) -> usize {
+///     let mut x = x;
+///     let mut y = y;
+///     while y != 0 {
+///         let t = y;
+///         y = x % y;
+///         x = t;
+///     }
+///     x
+/// }
+///
+/// assert_eq!(Rational::new(1, 2), Rational::new(2, 4));
+/// assert_eq!(Rational::new(2, 3) * Rational::new(3, 4),
+///            Rational::new(1, 2));
+/// ```
+///
+/// Note that `RHS = Self` by default, but this is not mandatory. Here is an
+/// implementation which enables multiplication of vectors by scalars, as is
+/// done in linear algebra.
+///
+/// ```
+/// use std::ops::Mul;
+///
+/// struct Scalar {value: usize};
+///
+/// #[derive(Debug)]
+/// struct Vector {value: Vec<usize>};
+///
+/// impl Mul<Vector> for Scalar {
+///     type Output = Vector;
+///
+///     fn mul(self, rhs: Vector) -> Vector {
+///         Vector {value: rhs.value.iter().map(|v| self.value * v).collect()}
+///     }
 /// }
+///
+/// impl PartialEq<Vector> for Vector {
+///     fn eq(&self, other: &Self) -> bool {
+///         self.value == other.value
+///     }
+/// }
+///
+/// let scalar = Scalar{value: 3};
+/// let vector = Vector{value: vec![2, 4, 6]};
+/// assert_eq!(scalar * vector, Vector{value: vec![6, 12, 18]});
 /// ```
 #[lang = "mul"]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -333,27 +516,101 @@ fn mul(self, other: $t) -> $t { self * other }
 ///
 /// # Examples
 ///
-/// A trivial implementation of `Div`. When `Foo / Foo` happens, it ends up
-/// calling `div`, and therefore, `main` prints `Dividing!`.
+/// Implementing a `Div`idable rational number struct:
 ///
 /// ```
 /// use std::ops::Div;
 ///
-/// struct Foo;
+/// // The uniqueness of rational numbers in lowest terms is a consequence of
+/// // the fundamental theorem of arithmetic.
+/// #[derive(Eq)]
+/// #[derive(PartialEq, Debug)]
+/// struct Rational {
+///     nominator: usize,
+///     denominator: usize,
+/// }
+///
+/// impl Rational {
+///     fn new(nominator: usize, denominator: usize) -> Self {
+///         if denominator == 0 {
+///             panic!("Zero is an invalid denominator!");
+///         }
+///
+///         // Reduce to lowest terms by dividing by the greatest common
+///         // divisor.
+///         let gcd = gcd(nominator, denominator);
+///         Rational {
+///             nominator: nominator / gcd,
+///             denominator: denominator / gcd,
+///         }
+///     }
+/// }
 ///
-/// impl Div for Foo {
-///     type Output = Foo;
+/// impl Div for Rational {
+///     // The division of rational numbers is a closed operation.
+///     type Output = Self;
 ///
-///     fn div(self, _rhs: Foo) -> Foo {
-///         println!("Dividing!");
-///         self
+///     fn div(self, rhs: Self) -> Self {
+///         if rhs.nominator == 0 {
+///             panic!("Cannot divide by zero-valued `Rational`!");
+///         }
+///
+///         let nominator = self.nominator * rhs.denominator;
+///         let denominator = self.denominator * rhs.nominator;
+///         Rational::new(nominator, denominator)
 ///     }
 /// }
 ///
+/// // Euclid's two-thousand-year-old algorithm for finding the greatest common
+/// // divisor.
+/// fn gcd(x: usize, y: usize) -> usize {
+///     let mut x = x;
+///     let mut y = y;
+///     while y != 0 {
+///         let t = y;
+///         y = x % y;
+///         x = t;
+///     }
+///     x
+/// }
+///
 /// fn main() {
-///     Foo / Foo;
+///     assert_eq!(Rational::new(1, 2), Rational::new(2, 4));
+///     assert_eq!(Rational::new(1, 2) / Rational::new(3, 4),
+///                Rational::new(2, 3));
 /// }
 /// ```
+///
+/// Note that `RHS = Self` by default, but this is not mandatory. Here is an
+/// implementation which enables division of vectors by scalars, as is done in
+/// linear algebra.
+///
+/// ```
+/// use std::ops::Div;
+///
+/// struct Scalar {value: f32};
+///
+/// #[derive(Debug)]
+/// struct Vector {value: Vec<f32>};
+///
+/// impl Div<Scalar> for Vector {
+///     type Output = Vector;
+///
+///     fn div(self, rhs: Scalar) -> Vector {
+///         Vector {value: self.value.iter().map(|v| v / rhs.value).collect()}
+///     }
+/// }
+///
+/// impl PartialEq<Vector> for Vector {
+///     fn eq(&self, other: &Self) -> bool {
+///         self.value == other.value
+///     }
+/// }
+///
+/// let scalar = Scalar{value: 2f32};
+/// let vector = Vector{value: vec![2f32, 4f32, 6f32]};
+/// assert_eq!(vector / scalar, Vector{value: vec![1f32, 2f32, 3f32]});
+/// ```
 #[lang = "div"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Div<RHS=Self> {
@@ -404,26 +661,34 @@ fn div(self, other: $t) -> $t { self / other }
 ///
 /// # Examples
 ///
-/// A trivial implementation of `Rem`. When `Foo % Foo` happens, it ends up
-/// calling `rem`, and therefore, `main` prints `Remainder-ing!`.
+/// This example implements `Rem` on a `SplitSlice` object. After `Rem` is
+/// implemented, one can use the `%` operator to find out what the remaining
+/// elements of the slice would be after splitting it into equal slices of a
+/// given length.
 ///
 /// ```
 /// use std::ops::Rem;
 ///
-/// struct Foo;
+/// #[derive(PartialEq, Debug)]
+/// struct SplitSlice<'a, T: 'a> {
+///     slice: &'a [T],
+/// }
 ///
-/// impl Rem for Foo {
-///     type Output = Foo;
+/// impl<'a, T> Rem<usize> for SplitSlice<'a, T> {
+///     type Output = SplitSlice<'a, T>;
 ///
-///     fn rem(self, _rhs: Foo) -> Foo {
-///         println!("Remainder-ing!");
-///         self
+///     fn rem(self, modulus: usize) -> Self {
+///         let len = self.slice.len();
+///         let rem = len % modulus;
+///         let start = len - rem;
+///         SplitSlice {slice: &self.slice[start..]}
 ///     }
 /// }
 ///
-/// fn main() {
-///     Foo % Foo;
-/// }
+/// // If we were to divide &[0, 1, 2, 3, 4, 5, 6, 7] into slices of size 3,
+/// // the remainder would be &[6, 7]
+/// assert_eq!(SplitSlice { slice: &[0, 1, 2, 3, 4, 5, 6, 7] } % 3,
+///            SplitSlice { slice: &[6, 7] });
 /// ```
 #[lang = "rem"]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -475,26 +740,37 @@ fn rem(self, other: $t) -> $t { self % other }
 ///
 /// # Examples
 ///
-/// A trivial implementation of `Neg`. When `-Foo` happens, it ends up calling
-/// `neg`, and therefore, `main` prints `Negating!`.
+/// An implementation of `Neg` for `Sign`, which allows the use of `-` to
+/// negate its value.
 ///
 /// ```
 /// use std::ops::Neg;
 ///
-/// struct Foo;
+/// #[derive(Debug, PartialEq)]
+/// enum Sign {
+///     Negative,
+///     Zero,
+///     Positive,
+/// }
 ///
-/// impl Neg for Foo {
-///     type Output = Foo;
+/// impl Neg for Sign {
+///     type Output = Sign;
 ///
-///     fn neg(self) -> Foo {
-///         println!("Negating!");
-///         self
+///     fn neg(self) -> Sign {
+///         match self {
+///             Sign::Negative => Sign::Positive,
+///             Sign::Zero => Sign::Zero,
+///             Sign::Positive => Sign::Negative,
+///         }
 ///     }
 /// }
 ///
-/// fn main() {
-///     -Foo;
-/// }
+/// // a negative positive is a negative
+/// assert_eq!(-Sign::Positive, Sign::Negative);
+/// // a double negative is a positive
+/// assert_eq!(-Sign::Negative, Sign::Positive);
+/// // zero is its own negation
+/// assert_eq!(-Sign::Zero, Sign::Zero);
 /// ```
 #[lang = "neg"]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -543,26 +819,31 @@ macro_rules! neg_impl_unsigned {
 ///
 /// # Examples
 ///
-/// A trivial implementation of `Not`. When `!Foo` happens, it ends up calling
-/// `not`, and therefore, `main` prints `Not-ing!`.
+/// An implementation of `Not` for `Answer`, which enables the use of `!` to
+/// invert its value.
 ///
 /// ```
 /// use std::ops::Not;
 ///
-/// struct Foo;
+/// #[derive(Debug, PartialEq)]
+/// enum Answer {
+///     Yes,
+///     No,
+/// }
 ///
-/// impl Not for Foo {
-///     type Output = Foo;
+/// impl Not for Answer {
+///     type Output = Answer;
 ///
-///     fn not(self) -> Foo {
-///         println!("Not-ing!");
-///         self
+///     fn not(self) -> Answer {
+///         match self {
+///             Answer::Yes => Answer::No,
+///             Answer::No => Answer::Yes
+///         }
 ///     }
 /// }
 ///
-/// fn main() {
-///     !Foo;
-/// }
+/// assert_eq!(!Answer::Yes, Answer::No);
+/// assert_eq!(!Answer::No, Answer::Yes);
 /// ```
 #[lang = "not"]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -596,25 +877,55 @@ fn not(self) -> $t { !self }
 ///
 /// # Examples
 ///
-/// A trivial implementation of `BitAnd`. When `Foo & Foo` happens, it ends up
-/// calling `bitand`, and therefore, `main` prints `Bitwise And-ing!`.
+/// In this example, the `&` operator is lifted to a trivial `Scalar` type.
 ///
 /// ```
 /// use std::ops::BitAnd;
 ///
-/// struct Foo;
+/// #[derive(Debug, PartialEq)]
+/// struct Scalar(bool);
 ///
-/// impl BitAnd for Foo {
-///     type Output = Foo;
+/// impl BitAnd for Scalar {
+///     type Output = Self;
 ///
-///     fn bitand(self, _rhs: Foo) -> Foo {
-///         println!("Bitwise And-ing!");
-///         self
+///     // rhs is the "right-hand side" of the expression `a & b`
+///     fn bitand(self, rhs: Self) -> Self {
+///         Scalar(self.0 & rhs.0)
+///     }
+/// }
+///
+/// fn main() {
+///     assert_eq!(Scalar(true) & Scalar(true), Scalar(true));
+///     assert_eq!(Scalar(true) & Scalar(false), Scalar(false));
+///     assert_eq!(Scalar(false) & Scalar(true), Scalar(false));
+///     assert_eq!(Scalar(false) & Scalar(false), Scalar(false));
+/// }
+/// ```
+///
+/// In this example, the `BitAnd` trait is implemented for a `BooleanVector`
+/// struct.
+///
+/// ```
+/// use std::ops::BitAnd;
+///
+/// #[derive(Debug, PartialEq)]
+/// struct BooleanVector(Vec<bool>);
+///
+/// impl BitAnd for BooleanVector {
+///     type Output = Self;
+///
+///     fn bitand(self, BooleanVector(rhs): Self) -> Self {
+///         let BooleanVector(lhs) = self;
+///         assert_eq!(lhs.len(), rhs.len());
+///         BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x && *y).collect())
 ///     }
 /// }
 ///
 /// fn main() {
-///     Foo & Foo;
+///     let bv1 = BooleanVector(vec![true, true, false, false]);
+///     let bv2 = BooleanVector(vec![true, false, true, false]);
+///     let expected = BooleanVector(vec![true, false, false, false]);
+///     assert_eq!(bv1 & bv2, expected);
 /// }
 /// ```
 #[lang = "bitand"]
@@ -649,25 +960,55 @@ fn bitand(self, rhs: $t) -> $t { self & rhs }
 ///
 /// # Examples
 ///
-/// A trivial implementation of `BitOr`. When `Foo | Foo` happens, it ends up
-/// calling `bitor`, and therefore, `main` prints `Bitwise Or-ing!`.
+/// In this example, the `|` operator is lifted to a trivial `Scalar` type.
 ///
 /// ```
 /// use std::ops::BitOr;
 ///
-/// struct Foo;
+/// #[derive(Debug, PartialEq)]
+/// struct Scalar(bool);
 ///
-/// impl BitOr for Foo {
-///     type Output = Foo;
+/// impl BitOr for Scalar {
+///     type Output = Self;
 ///
-///     fn bitor(self, _rhs: Foo) -> Foo {
-///         println!("Bitwise Or-ing!");
-///         self
+///     // rhs is the "right-hand side" of the expression `a | b`
+///     fn bitor(self, rhs: Self) -> Self {
+///         Scalar(self.0 | rhs.0)
+///     }
+/// }
+///
+/// fn main() {
+///     assert_eq!(Scalar(true) | Scalar(true), Scalar(true));
+///     assert_eq!(Scalar(true) | Scalar(false), Scalar(true));
+///     assert_eq!(Scalar(false) | Scalar(true), Scalar(true));
+///     assert_eq!(Scalar(false) | Scalar(false), Scalar(false));
+/// }
+/// ```
+///
+/// In this example, the `BitOr` trait is implemented for a `BooleanVector`
+/// struct.
+///
+/// ```
+/// use std::ops::BitOr;
+///
+/// #[derive(Debug, PartialEq)]
+/// struct BooleanVector(Vec<bool>);
+///
+/// impl BitOr for BooleanVector {
+///     type Output = Self;
+///
+///     fn bitor(self, BooleanVector(rhs): Self) -> Self {
+///         let BooleanVector(lhs) = self;
+///         assert_eq!(lhs.len(), rhs.len());
+///         BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x || *y).collect())
 ///     }
 /// }
 ///
 /// fn main() {
-///     Foo | Foo;
+///     let bv1 = BooleanVector(vec![true, true, false, false]);
+///     let bv2 = BooleanVector(vec![true, false, true, false]);
+///     let expected = BooleanVector(vec![true, true, true, false]);
+///     assert_eq!(bv1 | bv2, expected);
 /// }
 /// ```
 #[lang = "bitor"]
@@ -702,25 +1043,58 @@ fn bitor(self, rhs: $t) -> $t { self | rhs }
 ///
 /// # Examples
 ///
-/// A trivial implementation of `BitXor`. When `Foo ^ Foo` happens, it ends up
-/// calling `bitxor`, and therefore, `main` prints `Bitwise Xor-ing!`.
+/// In this example, the `^` operator is lifted to a trivial `Scalar` type.
 ///
 /// ```
 /// use std::ops::BitXor;
 ///
-/// struct Foo;
+/// #[derive(Debug, PartialEq)]
+/// struct Scalar(bool);
 ///
-/// impl BitXor for Foo {
-///     type Output = Foo;
+/// impl BitXor for Scalar {
+///     type Output = Self;
 ///
-///     fn bitxor(self, _rhs: Foo) -> Foo {
-///         println!("Bitwise Xor-ing!");
-///         self
+///     // rhs is the "right-hand side" of the expression `a ^ b`
+///     fn bitxor(self, rhs: Self) -> Self {
+///         Scalar(self.0 ^ rhs.0)
 ///     }
 /// }
 ///
 /// fn main() {
-///     Foo ^ Foo;
+///     assert_eq!(Scalar(true) ^ Scalar(true), Scalar(false));
+///     assert_eq!(Scalar(true) ^ Scalar(false), Scalar(true));
+///     assert_eq!(Scalar(false) ^ Scalar(true), Scalar(true));
+///     assert_eq!(Scalar(false) ^ Scalar(false), Scalar(false));
+/// }
+/// ```
+///
+/// In this example, the `BitXor` trait is implemented for a `BooleanVector`
+/// struct.
+///
+/// ```
+/// use std::ops::BitXor;
+///
+/// #[derive(Debug, PartialEq)]
+/// struct BooleanVector(Vec<bool>);
+///
+/// impl BitXor for BooleanVector {
+///     type Output = Self;
+///
+///     fn bitxor(self, BooleanVector(rhs): Self) -> Self {
+///         let BooleanVector(lhs) = self;
+///         assert_eq!(lhs.len(), rhs.len());
+///         BooleanVector(lhs.iter()
+///                          .zip(rhs.iter())
+///                          .map(|(x, y)| (*x || *y) && !(*x && *y))
+///                          .collect())
+///     }
+/// }
+///
+/// fn main() {
+///     let bv1 = BooleanVector(vec![true, true, false, false]);
+///     let bv2 = BooleanVector(vec![true, false, true, false]);
+///     let expected = BooleanVector(vec![false, true, true, false]);
+///     assert_eq!(bv1 ^ bv2, expected);
 /// }
 /// ```
 #[lang = "bitxor"]
@@ -755,25 +1129,54 @@ fn bitxor(self, other: $t) -> $t { self ^ other }
 ///
 /// # Examples
 ///
-/// A trivial implementation of `Shl`. When `Foo << Foo` happens, it ends up
-/// calling `shl`, and therefore, `main` prints `Shifting left!`.
+/// An implementation of `Shl` that lifts the `<<` operation on integers to a
+/// `Scalar` struct.
 ///
 /// ```
 /// use std::ops::Shl;
 ///
-/// struct Foo;
+/// #[derive(PartialEq, Debug)]
+/// struct Scalar(usize);
 ///
-/// impl Shl<Foo> for Foo {
-///     type Output = Foo;
+/// impl Shl<Scalar> for Scalar {
+///     type Output = Self;
 ///
-///     fn shl(self, _rhs: Foo) -> Foo {
-///         println!("Shifting left!");
-///         self
+///     fn shl(self, Scalar(rhs): Self) -> Scalar {
+///         let Scalar(lhs) = self;
+///         Scalar(lhs << rhs)
+///     }
+/// }
+/// fn main() {
+///     assert_eq!(Scalar(4) << Scalar(2), Scalar(16));
+/// }
+/// ```
+///
+/// An implementation of `Shl` that spins a vector leftward by a given amount.
+///
+/// ```
+/// use std::ops::Shl;
+///
+/// #[derive(PartialEq, Debug)]
+/// struct SpinVector<T: Clone> {
+///     vec: Vec<T>,
+/// }
+///
+/// impl<T: Clone> Shl<usize> for SpinVector<T> {
+///     type Output = Self;
+///
+///     fn shl(self, rhs: usize) -> SpinVector<T> {
+///         // rotate the vector by `rhs` places
+///         let (a, b) = self.vec.split_at(rhs);
+///         let mut spun_vector: Vec<T> = vec![];
+///         spun_vector.extend_from_slice(b);
+///         spun_vector.extend_from_slice(a);
+///         SpinVector { vec: spun_vector }
 ///     }
 /// }
 ///
 /// fn main() {
-///     Foo << Foo;
+///     assert_eq!(SpinVector { vec: vec![0, 1, 2, 3, 4] } << 2,
+///                SpinVector { vec: vec![2, 3, 4, 0, 1] });
 /// }
 /// ```
 #[lang = "shl"]
@@ -827,25 +1230,54 @@ macro_rules! shl_impl_all {
 ///
 /// # Examples
 ///
-/// A trivial implementation of `Shr`. When `Foo >> Foo` happens, it ends up
-/// calling `shr`, and therefore, `main` prints `Shifting right!`.
+/// An implementation of `Shr` that lifts the `>>` operation on integers to a
+/// `Scalar` struct.
 ///
 /// ```
 /// use std::ops::Shr;
 ///
-/// struct Foo;
+/// #[derive(PartialEq, Debug)]
+/// struct Scalar(usize);
 ///
-/// impl Shr<Foo> for Foo {
-///     type Output = Foo;
+/// impl Shr<Scalar> for Scalar {
+///     type Output = Self;
 ///
-///     fn shr(self, _rhs: Foo) -> Foo {
-///         println!("Shifting right!");
-///         self
+///     fn shr(self, Scalar(rhs): Self) -> Scalar {
+///         let Scalar(lhs) = self;
+///         Scalar(lhs >> rhs)
+///     }
+/// }
+/// fn main() {
+///     assert_eq!(Scalar(16) >> Scalar(2), Scalar(4));
+/// }
+/// ```
+///
+/// An implementation of `Shr` that spins a vector rightward by a given amount.
+///
+/// ```
+/// use std::ops::Shr;
+///
+/// #[derive(PartialEq, Debug)]
+/// struct SpinVector<T: Clone> {
+///     vec: Vec<T>,
+/// }
+///
+/// impl<T: Clone> Shr<usize> for SpinVector<T> {
+///     type Output = Self;
+///
+///     fn shr(self, rhs: usize) -> SpinVector<T> {
+///         // rotate the vector by `rhs` places
+///         let (a, b) = self.vec.split_at(self.vec.len() - rhs);
+///         let mut spun_vector: Vec<T> = vec![];
+///         spun_vector.extend_from_slice(b);
+///         spun_vector.extend_from_slice(a);
+///         SpinVector { vec: spun_vector }
 ///     }
 /// }
 ///
 /// fn main() {
-///     Foo >> Foo;
+///     assert_eq!(SpinVector { vec: vec![0, 1, 2, 3, 4] } >> 2,
+///                SpinVector { vec: vec![3, 4, 0, 1, 2] });
 /// }
 /// ```
 #[lang = "shr"]
@@ -899,25 +1331,36 @@ macro_rules! shr_impl_all {
 ///
 /// # Examples
 ///
-/// A trivial implementation of `AddAssign`. When `Foo += Foo` happens, it ends up
-/// calling `add_assign`, and therefore, `main` prints `Adding!`.
+/// This example creates a `Point` struct that implements the `AddAssign`
+/// trait, and then demonstrates add-assigning to a mutable `Point`.
 ///
 /// ```
 /// use std::ops::AddAssign;
 ///
-/// struct Foo;
+/// #[derive(Debug)]
+/// struct Point {
+///     x: i32,
+///     y: i32,
+/// }
 ///
-/// impl AddAssign for Foo {
-///     fn add_assign(&mut self, _rhs: Foo) {
-///         println!("Adding!");
+/// impl AddAssign for Point {
+///     fn add_assign(&mut self, other: Point) {
+///         *self = Point {
+///             x: self.x + other.x,
+///             y: self.y + other.y,
+///         };
 ///     }
 /// }
 ///
-/// # #[allow(unused_assignments)]
-/// fn main() {
-///     let mut foo = Foo;
-///     foo += Foo;
+/// impl PartialEq for Point {
+///     fn eq(&self, other: &Self) -> bool {
+///         self.x == other.x && self.y == other.y
+///     }
 /// }
+///
+/// let mut point = Point { x: 1, y: 0 };
+/// point += Point { x: 2, y: 3 };
+/// assert_eq!(point, Point { x: 3, y: 3 });
 /// ```
 #[lang = "add_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -944,25 +1387,36 @@ fn add_assign(&mut self, other: $t) { *self += other }
 ///
 /// # Examples
 ///
-/// A trivial implementation of `SubAssign`. When `Foo -= Foo` happens, it ends up
-/// calling `sub_assign`, and therefore, `main` prints `Subtracting!`.
+/// This example creates a `Point` struct that implements the `SubAssign`
+/// trait, and then demonstrates sub-assigning to a mutable `Point`.
 ///
 /// ```
 /// use std::ops::SubAssign;
 ///
-/// struct Foo;
+/// #[derive(Debug)]
+/// struct Point {
+///     x: i32,
+///     y: i32,
+/// }
 ///
-/// impl SubAssign for Foo {
-///     fn sub_assign(&mut self, _rhs: Foo) {
-///         println!("Subtracting!");
+/// impl SubAssign for Point {
+///     fn sub_assign(&mut self, other: Point) {
+///         *self = Point {
+///             x: self.x - other.x,
+///             y: self.y - other.y,
+///         };
 ///     }
 /// }
 ///
-/// # #[allow(unused_assignments)]
-/// fn main() {
-///     let mut foo = Foo;
-///     foo -= Foo;
+/// impl PartialEq for Point {
+///     fn eq(&self, other: &Self) -> bool {
+///         self.x == other.x && self.y == other.y
+///     }
 /// }
+///
+/// let mut point = Point { x: 3, y: 3 };
+/// point -= Point { x: 2, y: 3 };
+/// assert_eq!(point, Point {x: 1, y: 0});
 /// ```
 #[lang = "sub_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
@@ -1122,24 +1576,66 @@ fn rem_assign(&mut self, other: $t) { *self %= other }
 ///
 /// # Examples
 ///
-/// A trivial implementation of `BitAndAssign`. When `Foo &= Foo` happens, it ends up
-/// calling `bitand_assign`, and therefore, `main` prints `Bitwise And-ing!`.
+/// In this example, the `&=` operator is lifted to a trivial `Scalar` type.
 ///
 /// ```
 /// use std::ops::BitAndAssign;
 ///
-/// struct Foo;
+/// #[derive(Debug, PartialEq)]
+/// struct Scalar(bool);
 ///
-/// impl BitAndAssign for Foo {
-///     fn bitand_assign(&mut self, _rhs: Foo) {
-///         println!("Bitwise And-ing!");
+/// impl BitAndAssign for Scalar {
+///     // rhs is the "right-hand side" of the expression `a &= b`
+///     fn bitand_assign(&mut self, rhs: Self) {
+///         *self = Scalar(self.0 & rhs.0)
 ///     }
 /// }
 ///
-/// # #[allow(unused_assignments)]
 /// fn main() {
-///     let mut foo = Foo;
-///     foo &= Foo;
+///     let mut scalar = Scalar(true);
+///     scalar &= Scalar(true);
+///     assert_eq!(scalar, Scalar(true));
+///
+///     let mut scalar = Scalar(true);
+///     scalar &= Scalar(false);
+///     assert_eq!(scalar, Scalar(false));
+///
+///     let mut scalar = Scalar(false);
+///     scalar &= Scalar(true);
+///     assert_eq!(scalar, Scalar(false));
+///
+///     let mut scalar = Scalar(false);
+///     scalar &= Scalar(false);
+///     assert_eq!(scalar, Scalar(false));
+/// }
+/// ```
+///
+/// In this example, the `BitAndAssign` trait is implemented for a
+/// `BooleanVector` struct.
+///
+/// ```
+/// use std::ops::BitAndAssign;
+///
+/// #[derive(Debug, PartialEq)]
+/// struct BooleanVector(Vec<bool>);
+///
+/// impl BitAndAssign for BooleanVector {
+///     // rhs is the "right-hand side" of the expression `a &= b`
+///     fn bitand_assign(&mut self, rhs: Self) {
+///         assert_eq!(self.0.len(), rhs.0.len());
+///         *self = BooleanVector(self.0
+///                                   .iter()
+///                                   .zip(rhs.0.iter())
+///                                   .map(|(x, y)| *x && *y)
+///                                   .collect());
+///     }
+/// }
+///
+/// fn main() {
+///     let mut bv = BooleanVector(vec![true, true, false, false]);
+///     bv &= BooleanVector(vec![true, false, true, false]);
+///     let expected = BooleanVector(vec![true, false, false, false]);
+///     assert_eq!(bv, expected);
 /// }
 /// ```
 #[lang = "bitand_assign"]
@@ -1381,28 +1877,44 @@ macro_rules! shr_assign_impl_all {
 ///
 /// # Examples
 ///
-/// A trivial implementation of `Index`. When `Foo[Bar]` happens, it ends up
-/// calling `index`, and therefore, `main` prints `Indexing!`.
+/// This example implements `Index` on a read-only `NucleotideCount` container,
+/// enabling individual counts to be retrieved with index syntax.
 ///
 /// ```
 /// use std::ops::Index;
 ///
-/// #[derive(Copy, Clone)]
-/// struct Foo;
-/// struct Bar;
+/// enum Nucleotide {
+///     A,
+///     C,
+///     G,
+///     T,
+/// }
 ///
-/// impl Index<Bar> for Foo {
-///     type Output = Foo;
+/// struct NucleotideCount {
+///     a: usize,
+///     c: usize,
+///     g: usize,
+///     t: usize,
+/// }
 ///
-///     fn index<'a>(&'a self, _index: Bar) -> &'a Foo {
-///         println!("Indexing!");
-///         self
+/// impl Index<Nucleotide> for NucleotideCount {
+///     type Output = usize;
+///
+///     fn index(&self, nucleotide: Nucleotide) -> &usize {
+///         match nucleotide {
+///             Nucleotide::A => &self.a,
+///             Nucleotide::C => &self.c,
+///             Nucleotide::G => &self.g,
+///             Nucleotide::T => &self.t,
+///         }
 ///     }
 /// }
 ///
-/// fn main() {
-///     Foo[Bar];
-/// }
+/// let nucleotide_count = NucleotideCount {a: 14, c: 9, g: 10, t: 12};
+/// assert_eq!(nucleotide_count[Nucleotide::A], 14);
+/// assert_eq!(nucleotide_count[Nucleotide::C], 9);
+/// assert_eq!(nucleotide_count[Nucleotide::G], 10);
+/// assert_eq!(nucleotide_count[Nucleotide::T], 12);
 /// ```
 #[lang = "index"]
 #[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
@@ -1467,17 +1979,30 @@ pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
 ///
 /// # Examples
 ///
+/// The `..` syntax is a `RangeFull`:
+///
+/// ```
+/// assert_eq!((..), std::ops::RangeFull);
 /// ```
-/// fn main() {
-///     assert_eq!((..), std::ops::RangeFull);
 ///
-///     let arr = [0, 1, 2, 3];
-///     assert_eq!(arr[ .. ], [0,1,2,3]);  // RangeFull
-///     assert_eq!(arr[ ..3], [0,1,2  ]);
-///     assert_eq!(arr[1.. ], [  1,2,3]);
-///     assert_eq!(arr[1..3], [  1,2  ]);
+/// It does not have an `IntoIterator` implementation, so you can't use it in a
+/// `for` loop directly. This won't compile:
+///
+/// ```ignore
+/// for i in .. {
+///    // ...
 /// }
 /// ```
+///
+/// Used as a slicing index, `RangeFull` produces the full array as a slice.
+///
+/// ```
+/// let arr = [0, 1, 2, 3];
+/// assert_eq!(arr[ .. ], [0,1,2,3]);  // RangeFull
+/// assert_eq!(arr[ ..3], [0,1,2  ]);
+/// assert_eq!(arr[1.. ], [  1,2,3]);
+/// assert_eq!(arr[1..3], [  1,2  ]);
+/// ```
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RangeFull;
@@ -1610,17 +2135,33 @@ pub fn contains(&self, item: Idx) -> bool {
 ///
 /// It cannot serve as an iterator because it doesn't have a starting point.
 ///
+/// # Examples
+///
+/// The `..{integer}` syntax is a `RangeTo`:
+///
+/// ```
+/// assert_eq!((..5), std::ops::RangeTo{ end: 5 });
 /// ```
-/// fn main() {
-///     assert_eq!((..5), std::ops::RangeTo{ end: 5 });
 ///
-///     let arr = [0, 1, 2, 3];
-///     assert_eq!(arr[ .. ], [0,1,2,3]);
-///     assert_eq!(arr[ ..3], [0,1,2  ]);  // RangeTo
-///     assert_eq!(arr[1.. ], [  1,2,3]);
-///     assert_eq!(arr[1..3], [  1,2  ]);
+/// It does not have an `IntoIterator` implementation, so you can't use it in a
+/// `for` loop directly. This won't compile:
+///
+/// ```ignore
+/// for i in ..5 {
+///     // ...
 /// }
 /// ```
+///
+/// When used as a slicing index, `RangeTo` produces a slice of all array
+/// elements before the index indicated by `end`.
+///
+/// ```
+/// let arr = [0, 1, 2, 3];
+/// assert_eq!(arr[ .. ], [0,1,2,3]);
+/// assert_eq!(arr[ ..3], [0,1,2  ]);  // RangeTo
+/// assert_eq!(arr[1.. ], [  1,2,3]);
+/// assert_eq!(arr[1..3], [  1,2  ]);
+/// ```
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RangeTo<Idx> {
@@ -1748,16 +2289,31 @@ pub fn contains(&self, item: Idx) -> bool {
 ///
 /// # Examples
 ///
+/// The `...{integer}` syntax is a `RangeToInclusive`:
+///
 /// ```
 /// #![feature(inclusive_range,inclusive_range_syntax)]
-/// fn main() {
-///     assert_eq!((...5), std::ops::RangeToInclusive{ end: 5 });
+/// assert_eq!((...5), std::ops::RangeToInclusive{ end: 5 });
+/// ```
 ///
-///     let arr = [0, 1, 2, 3];
-///     assert_eq!(arr[ ...2], [0,1,2  ]);  // RangeToInclusive
-///     assert_eq!(arr[1...2], [  1,2  ]);
+/// It does not have an `IntoIterator` implementation, so you can't use it in a
+/// `for` loop directly. This won't compile:
+///
+/// ```ignore
+/// for i in ...5 {
+///     // ...
 /// }
 /// ```
+///
+/// When used as a slicing index, `RangeToInclusive` produces a slice of all
+/// array elements up to and including the index indicated by `end`.
+///
+/// ```
+/// #![feature(inclusive_range_syntax)]
+/// let arr = [0, 1, 2, 3];
+/// assert_eq!(arr[ ...2], [0,1,2  ]);  // RangeToInclusive
+/// assert_eq!(arr[1...2], [  1,2  ]);
+/// ```
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
 pub struct RangeToInclusive<Idx> {
@@ -1906,6 +2462,35 @@ fn deref_mut(&mut self) -> &mut T { *self }
 }
 
 /// A version of the call operator that takes an immutable receiver.
+///
+/// # Examples
+///
+/// Closures automatically implement this trait, which allows them to be
+/// invoked. Note, however, that `Fn` takes an immutable reference to any
+/// captured variables. To take a mutable capture, implement [`FnMut`], and to
+/// consume the capture, implement [`FnOnce`].
+///
+/// [`FnMut`]: trait.FnMut.html
+/// [`FnOnce`]: trait.FnOnce.html
+///
+/// ```
+/// let square = |x| x * x;
+/// assert_eq!(square(5), 25);
+/// ```
+///
+/// Closures can also be passed to higher-level functions through a `Fn`
+/// parameter (or a `FnMut` or `FnOnce` parameter, which are supertraits of
+/// `Fn`).
+///
+/// ```
+/// fn call_with_one<F>(func: F) -> usize
+///     where F: Fn(usize) -> usize {
+///     func(1)
+/// }
+///
+/// let double = |x| x * 2;
+/// assert_eq!(call_with_one(double), 2);
+/// ```
 #[lang = "fn"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_paren_sugar]
@@ -1917,6 +2502,40 @@ pub trait Fn<Args> : FnMut<Args> {
 }
 
 /// A version of the call operator that takes a mutable receiver.
+///
+/// # Examples
+///
+/// Closures that mutably capture variables automatically implement this trait,
+/// which allows them to be invoked.
+///
+/// ```
+/// let mut x = 5;
+/// {
+///     let mut square_x = || x *= x;
+///     square_x();
+/// }
+/// assert_eq!(x, 25);
+/// ```
+///
+/// Closures can also be passed to higher-level functions through a `FnMut`
+/// parameter (or a `FnOnce` parameter, which is a supertrait of `FnMut`).
+///
+/// ```
+/// fn do_twice<F>(mut func: F)
+///     where F: FnMut()
+/// {
+///     func();
+///     func();
+/// }
+///
+/// let mut x: usize = 1;
+/// {
+///     let add_two_to_x = || x += 2;
+///     do_twice(add_two_to_x);
+/// }
+///
+/// assert_eq!(x, 5);
+/// ```
 #[lang = "fn_mut"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_paren_sugar]
@@ -1928,6 +2547,41 @@ pub trait FnMut<Args> : FnOnce<Args> {
 }
 
 /// A version of the call operator that takes a by-value receiver.
+///
+/// # Examples
+///
+/// By-value closures automatically implement this trait, which allows them to
+/// be invoked.
+///
+/// ```
+/// let x = 5;
+/// let square_x = move || x * x;
+/// assert_eq!(square_x(), 25);
+/// ```
+///
+/// By-value Closures can also be passed to higher-level functions through a
+/// `FnOnce` parameter.
+///
+/// ```
+/// fn consume_with_relish<F>(func: F)
+///     where F: FnOnce() -> String
+/// {
+///     // `func` consumes its captured variables, so it cannot be run more
+///     // than once
+///     println!("Consumed: {}", func());
+///
+///     println!("Delicious!");
+///
+///     // Attempting to invoke `func()` again will throw a `use of moved
+///     // value` error for `func`
+/// }
+///
+/// let x = String::from("x");
+/// let consume_and_return_x = move || x;
+/// consume_with_relish(consume_and_return_x);
+///
+/// // `consume_and_return_x` can no longer be invoked at this point
+/// ```
 #[lang = "fn_once"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_paren_sugar]
@@ -1943,9 +2597,6 @@ pub trait FnOnce<Args> {
 }
 
 mod impls {
-    use marker::Sized;
-    use super::{Fn, FnMut, FnOnce};
-
     #[stable(feature = "rust1", since = "1.0.0")]
     impl<'a,A,F:?Sized> Fn<A> for &'a F
         where F : Fn<A>
@@ -2150,3 +2801,74 @@ pub trait BoxPlace<Data: ?Sized> : Place<Data> {
     /// Creates a globally fresh place.
     fn make_place() -> Self;
 }
+
+/// A trait for types which have success and error states and are meant to work
+/// with the question mark operator.
+/// When the `?` operator is used with a value, whether the value is in the
+/// success or error state is determined by calling `translate`.
+///
+/// This trait is **very** experimental, it will probably be iterated on heavily
+/// before it is stabilised. Implementors should expect change. Users of `?`
+/// should not rely on any implementations of `Carrier` other than `Result`,
+/// i.e., you should not expect `?` to continue to work with `Option`, etc.
+#[unstable(feature = "question_mark_carrier", issue = "31436")]
+pub trait Carrier {
+    /// The type of the value when computation succeeds.
+    type Success;
+    /// The type of the value when computation errors out.
+    type Error;
+
+    /// Create a `Carrier` from a success value.
+    fn from_success(Self::Success) -> Self;
+
+    /// Create a `Carrier` from an error value.
+    fn from_error(Self::Error) -> Self;
+
+    /// Translate this `Carrier` to another implementation of `Carrier` with the
+    /// same associated types.
+    fn translate<T>(self) -> T where T: Carrier<Success=Self::Success, Error=Self::Error>;
+}
+
+#[unstable(feature = "question_mark_carrier", issue = "31436")]
+impl<U, V> Carrier for Result<U, V> {
+    type Success = U;
+    type Error = V;
+
+    fn from_success(u: U) -> Result<U, V> {
+        Ok(u)
+    }
+
+    fn from_error(e: V) -> Result<U, V> {
+        Err(e)
+    }
+
+    fn translate<T>(self) -> T
+        where T: Carrier<Success=U, Error=V>
+    {
+        match self {
+            Ok(u) => T::from_success(u),
+            Err(e) => T::from_error(e),
+        }
+    }
+}
+
+struct _DummyErrorType;
+
+impl Carrier for _DummyErrorType {
+    type Success = ();
+    type Error = ();
+
+    fn from_success(_: ()) -> _DummyErrorType {
+        _DummyErrorType
+    }
+
+    fn from_error(_: ()) -> _DummyErrorType {
+        _DummyErrorType
+    }
+
+    fn translate<T>(self) -> T
+        where T: Carrier<Success=(), Error=()>
+    {
+        T::from_success(())
+    }
+}
index fe508adb71380089d4e313114288410fcb6274eb..cf52849e019722a71797d4a300983f06f9eab291 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use self::Option::*;
-
-use clone::Clone;
-use convert::From;
-use default::Default;
-use iter::ExactSizeIterator;
-use iter::{Iterator, DoubleEndedIterator, FromIterator, IntoIterator};
+use iter::{FromIterator, FusedIterator};
 use mem;
-use ops::FnOnce;
-use result::Result::{Ok, Err};
-use result::Result;
 
 // Note that this is not a lang item per se, but it has a hidden dependency on
 // `Iterator`, which is one. The compiler assumes that the `next` method of
@@ -796,6 +787,7 @@ fn next_back(&mut self) -> Option<A> {
 }
 
 impl<A> ExactSizeIterator for Item<A> {}
+impl<A> FusedIterator for Item<A> {}
 
 /// An iterator over a reference of the contained item in an Option.
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -821,6 +813,9 @@ fn next_back(&mut self) -> Option<&'a A> { self.inner.next_back() }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, A> ExactSizeIterator for Iter<'a, A> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, A> FusedIterator for Iter<'a, A> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, A> Clone for Iter<'a, A> {
     fn clone(&self) -> Iter<'a, A> {
@@ -852,6 +847,9 @@ fn next_back(&mut self) -> Option<&'a mut A> { self.inner.next_back() }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, A> ExactSizeIterator for IterMut<'a, A> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, A> FusedIterator for IterMut<'a, A> {}
+
 /// An iterator over the item contained inside an Option.
 #[derive(Clone, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -876,6 +874,9 @@ fn next_back(&mut self) -> Option<A> { self.inner.next_back() }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A> ExactSizeIterator for IntoIter<A> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<A> FusedIterator for IntoIter<A> {}
+
 /////////////////////////////////////////////////////////////////////////////
 // FromIterator
 /////////////////////////////////////////////////////////////////////////////
index 925cdfec900dbd6da769a2f4a24eeee6be972ee0..8c8925251e5cf4ef9d4c1a75aa6f0d8966fa8d4b 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use clone::Clone;
 use intrinsics;
 use ops::{CoerceUnsized, Deref};
 use fmt;
 use hash;
-use option::Option::{self, Some, None};
-use marker::{Copy, PhantomData, Send, Sized, Sync, Unsize};
+use marker::{PhantomData, Unsize};
 use mem;
 use nonzero::NonZero;
 
-use cmp::{PartialEq, Eq, Ord, PartialOrd};
 use cmp::Ordering::{self, Less, Equal, Greater};
 
 // FIXME #19649: intrinsic docs don't render, so these have no docs :(
@@ -128,7 +125,9 @@ pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
 /// let x = 12;
 /// let y = &x as *const i32;
 ///
-/// unsafe { println!("{}", std::ptr::read(y)); }
+/// unsafe {
+///     assert_eq!(std::ptr::read(y), 12);
+/// }
 /// ```
 #[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -138,21 +137,6 @@ pub unsafe fn read<T>(src: *const T) -> T {
     tmp
 }
 
-#[allow(missing_docs)]
-#[inline(always)]
-#[unstable(feature = "filling_drop",
-           reason = "may play a larger role in std::ptr future extensions",
-           issue = "5016")]
-pub unsafe fn read_and_drop<T>(dest: *mut T) -> T {
-    // Copy the data out from `dest`:
-    let tmp = read(&*dest);
-
-    // Now mark `dest` as dropped:
-    write_bytes(dest, mem::POST_DROP_U8, 1);
-
-    tmp
-}
-
 /// Overwrites a memory location with the given value without reading or
 /// dropping the old value.
 ///
@@ -178,7 +162,7 @@ pub unsafe fn read_and_drop<T>(dest: *mut T) -> T {
 ///
 /// unsafe {
 ///     std::ptr::write(y, z);
-///     println!("{}", std::ptr::read(y));
+///     assert_eq!(std::ptr::read(y), 12);
 /// }
 /// ```
 #[inline]
@@ -220,7 +204,9 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
 /// let x = 12;
 /// let y = &x as *const i32;
 ///
-/// unsafe { println!("{}", std::ptr::read_volatile(y)); }
+/// unsafe {
+///     assert_eq!(std::ptr::read_volatile(y), 12);
+/// }
 /// ```
 #[inline]
 #[stable(feature = "volatile", since = "1.9.0")]
@@ -266,7 +252,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 ///
 /// unsafe {
 ///     std::ptr::write_volatile(y, z);
-///     println!("{}", std::ptr::read_volatile(y));
+///     assert_eq!(std::ptr::read_volatile(y), 12);
 /// }
 /// ```
 #[inline]
index c7ca70fc1622d8ea2d811d5a81d2c54bd9104e5e..49eb5619bc6baafa72ea7b32a6e9259656e67a24 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use self::Result::{Ok, Err};
-
-use clone::Clone;
 use fmt;
-use iter::{Iterator, DoubleEndedIterator, FromIterator, ExactSizeIterator, IntoIterator};
-use ops::FnOnce;
-use option::Option::{self, None, Some};
+use iter::{FromIterator, FusedIterator};
 
 /// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
 ///
@@ -869,6 +864,9 @@ fn next_back(&mut self) -> Option<&'a T> { self.inner.take() }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Iter<'a, T> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> Clone for Iter<'a, T> {
     fn clone(&self) -> Iter<'a, T> { Iter { inner: self.inner } }
@@ -901,6 +899,9 @@ fn next_back(&mut self) -> Option<&'a mut T> { self.inner.take() }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for IterMut<'a, T> {}
+
 /// An iterator over the value in a `Ok` variant of a `Result`.
 #[derive(Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -928,6 +929,9 @@ fn next_back(&mut self) -> Option<T> { self.inner.take() }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ExactSizeIterator for IntoIter<T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for IntoIter<T> {}
+
 /////////////////////////////////////////////////////////////////////////////
 // FromIterator
 /////////////////////////////////////////////////////////////////////////////
index 3a820a14f1214aa8424a0222cf6b3885c6f3163f..baa41aa7af5b274298181abc13424fe93d949a35 100644 (file)
 // * The `raw` and `bytes` submodules.
 // * Boilerplate trait implementations.
 
-use clone::Clone;
-use cmp::{Ordering, PartialEq, PartialOrd, Eq, Ord};
-use cmp::Ordering::{Less, Equal, Greater};
+use cmp::Ordering::{self, Less, Equal, Greater};
 use cmp;
-use convert::AsRef;
-use default::Default;
 use fmt;
 use intrinsics::assume;
 use iter::*;
-use ops::{FnMut, self};
-use ops::RangeFull;
-use option::Option;
-use option::Option::{None, Some};
-use result::Result;
-use result::Result::{Ok, Err};
+use ops::{self, RangeFull};
 use ptr;
 use mem;
-use marker::{Copy, Send, Sync, self};
+use marker;
 use iter_private::TrustedRandomAccess;
 
 #[repr(C)]
@@ -992,6 +983,9 @@ fn iter_nth(&mut self, n: usize) -> Option<&'a T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Iter<'a, T> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> Clone for Iter<'a, T> {
     fn clone(&self) -> Iter<'a, T> { Iter { ptr: self.ptr, end: self.end, _marker: self._marker } }
@@ -1110,6 +1104,9 @@ fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for IterMut<'a, T> {}
+
 /// An internal abstraction over the splitting iterators, so that
 /// splitn, splitn_mut etc can be implemented once.
 #[doc(hidden)]
@@ -1202,6 +1199,9 @@ fn finish(&mut self) -> Option<&'a [T]> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T, P> FusedIterator for Split<'a, T, P> where P: FnMut(&T) -> bool {}
+
 /// An iterator over the subslices of the vector which are separated
 /// by elements that match `pred`.
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1292,6 +1292,9 @@ fn next_back(&mut self) -> Option<&'a mut [T]> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {}
+
 /// An private iterator over subslices separated by elements that
 /// match a predicate function, splitting at most a fixed number of
 /// times.
@@ -1408,6 +1411,10 @@ fn size_hint(&self) -> (usize, Option<usize>) {
                 self.inner.size_hint()
             }
         }
+
+        #[unstable(feature = "fused", issue = "35602")]
+        impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P>
+            where P: FnMut(&T) -> bool {}
     }
 }
 
@@ -1506,6 +1513,9 @@ fn next_back(&mut self) -> Option<&'a [T]> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for Windows<'a, T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Windows<'a, T> {}
+
 /// An iterator over a slice in (non-overlapping) chunks (`size` elements at a
 /// time).
 ///
@@ -1609,6 +1619,9 @@ fn next_back(&mut self) -> Option<&'a [T]> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for Chunks<'a, T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Chunks<'a, T> {}
+
 /// An iterator over a slice in (non-overlapping) mutable chunks (`size`
 /// elements at a time). When the slice len is not evenly divided by the chunk
 /// size, the last slice of the iteration will be the remainder.
@@ -1704,6 +1717,9 @@ fn next_back(&mut self) -> Option<&'a mut [T]> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for ChunksMut<'a, T> {}
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for ChunksMut<'a, T> {}
+
 //
 // Free functions
 //
index fdcadd43a0fb64deeda403b43c42ebf3a74c4277..18e43c02c648fb7973fd5eb9b46722fc08e9d7dd 100644 (file)
 use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
 
 use char;
-use clone::Clone;
-use convert::AsRef;
-use default::Default;
 use fmt;
-use iter::ExactSizeIterator;
-use iter::{Map, Cloned, Iterator, DoubleEndedIterator};
-use marker::Sized;
+use iter::{Map, Cloned, FusedIterator};
 use mem;
-use ops::{Fn, FnMut, FnOnce};
-use option::Option::{self, None, Some};
-use result::Result::{self, Ok, Err};
-use slice::{self, SliceExt};
+use slice;
 
 pub mod pattern;
 
@@ -388,8 +380,9 @@ pub fn next_code_point<'a, I: Iterator<Item = &'a u8>>(bytes: &mut I) -> Option<
 /// Reads the last code point out of a byte iterator (assuming a
 /// UTF-8-like encoding).
 #[inline]
-fn next_code_point_reverse<'a,
-                           I: DoubleEndedIterator<Item = &'a u8>>(bytes: &mut I) -> Option<u32> {
+fn next_code_point_reverse<'a, I>(bytes: &mut I) -> Option<u32>
+    where I: DoubleEndedIterator<Item = &'a u8>,
+{
     // Decode UTF-8
     let w = match bytes.next_back() {
         None => return None,
@@ -454,6 +447,9 @@ fn next_back(&mut self) -> Option<char> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for Chars<'a> {}
+
 impl<'a> Chars<'a> {
     /// View the underlying data as a subslice of the original data.
     ///
@@ -525,6 +521,9 @@ fn next_back(&mut self) -> Option<(usize, char)> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for CharIndices<'a> {}
+
 impl<'a> CharIndices<'a> {
     /// View the underlying data as a subslice of the original data.
     ///
@@ -593,6 +592,9 @@ fn len(&self) -> usize {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for Bytes<'a> {}
+
 /// This macro generates a Clone impl for string pattern API
 /// wrapper types of the form X<'a, P>
 macro_rules! derive_pattern_clone {
@@ -739,6 +741,13 @@ fn clone(&self) -> Self {
             }
         }
 
+        #[unstable(feature = "fused", issue = "35602")]
+        impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {}
+
+        #[unstable(feature = "fused", issue = "35602")]
+        impl<'a, P: Pattern<'a>> FusedIterator for $reverse_iterator<'a, P>
+            where P::Searcher: ReverseSearcher<'a> {}
+
         generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*,
                                                 $forward_iterator,
                                                 $reverse_iterator, $iterty);
@@ -1088,6 +1097,9 @@ fn next_back(&mut self) -> Option<&'a str> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for Lines<'a> {}
+
 /// Created with the method [`lines_any()`].
 ///
 /// [`lines_any()`]: ../../std/primitive.str.html#method.lines_any
@@ -1151,6 +1163,10 @@ fn next_back(&mut self) -> Option<&'a str> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+#[allow(deprecated)]
+impl<'a> FusedIterator for LinesAny<'a> {}
+
 /*
 Section: Comparing strings
 */
@@ -1314,11 +1330,9 @@ macro_rules! next { () => {{
 */
 
 mod traits {
-    use cmp::{Ord, Ordering, PartialEq, PartialOrd, Eq};
-    use option::Option;
-    use option::Option::Some;
+    use cmp::Ordering;
     use ops;
-    use str::{StrExt, eq_slice};
+    use str::eq_slice;
 
     #[stable(feature = "rust1", since = "1.0.0")]
     impl Ord for str {
index 53804c611e66ed52dc196b01e68eee88cce6820b..7dced2ba7514c2ac492167f882adcede4e7970bb 100644 (file)
@@ -17,8 +17,6 @@
             reason = "API not fully fleshed out and ready to be stabilized",
             issue = "27721")]
 
-use prelude::v1::*;
-
 use cmp;
 use fmt;
 use usize;
index 5701a89d8bc42aa0484e37c8f5d4e3597b09a039..75ddd2021a8f7fa74f9afa82b162f3820b4d6142 100644 (file)
 
 use self::Ordering::*;
 
-use marker::{Send, Sync};
-
 use intrinsics;
 use cell::UnsafeCell;
-
-use result::Result::{self, Ok, Err};
-
-use default::Default;
 use fmt;
 
 /// A boolean type which can be safely shared between threads.
+///
+/// This type has the same in-memory representation as a `bool`.
 #[cfg(target_has_atomic = "8")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct AtomicBool {
@@ -110,6 +106,8 @@ fn default() -> Self {
 unsafe impl Sync for AtomicBool {}
 
 /// A raw pointer type which can be safely shared between threads.
+///
+/// This type has the same in-memory representation as a `*mut T`.
 #[cfg(target_has_atomic = "ptr")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct AtomicPtr<T> {
@@ -191,6 +189,48 @@ pub const fn new(v: bool) -> AtomicBool {
         AtomicBool { v: UnsafeCell::new(v as u8) }
     }
 
+    /// Returns a mutable reference to the underlying `bool`.
+    ///
+    /// This is safe because the mutable reference guarantees that no other threads are
+    /// concurrently accessing the atomic data.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(atomic_access)]
+    /// use std::sync::atomic::{AtomicBool, Ordering};
+    ///
+    /// let mut some_bool = AtomicBool::new(true);
+    /// assert_eq!(*some_bool.get_mut(), true);
+    /// *some_bool.get_mut() = false;
+    /// assert_eq!(some_bool.load(Ordering::SeqCst), false);
+    /// ```
+    #[inline]
+    #[unstable(feature = "atomic_access", issue = "35603")]
+    pub fn get_mut(&mut self) -> &mut bool {
+        unsafe { &mut *(self.v.get() as *mut bool) }
+    }
+
+    /// Consumes the atomic and returns the contained value.
+    ///
+    /// This is safe because passing `self` by value guarantees that no other threads are
+    /// concurrently accessing the atomic data.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(atomic_access)]
+    /// use std::sync::atomic::AtomicBool;
+    ///
+    /// let some_bool = AtomicBool::new(true);
+    /// assert_eq!(some_bool.into_inner(), true);
+    /// ```
+    #[inline]
+    #[unstable(feature = "atomic_access", issue = "35603")]
+    pub fn into_inner(self) -> bool {
+        unsafe { self.v.into_inner() != 0 }
+    }
+
     /// Loads a value from the bool.
     ///
     /// `load` takes an `Ordering` argument which describes the memory ordering of this operation.
@@ -528,6 +568,47 @@ pub const fn new(p: *mut T) -> AtomicPtr<T> {
         AtomicPtr { p: UnsafeCell::new(p) }
     }
 
+    /// Returns a mutable reference to the underlying pointer.
+    ///
+    /// This is safe because the mutable reference guarantees that no other threads are
+    /// concurrently accessing the atomic data.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(atomic_access)]
+    /// use std::sync::atomic::{AtomicPtr, Ordering};
+    ///
+    /// let mut atomic_ptr = AtomicPtr::new(&mut 10);
+    /// *atomic_ptr.get_mut() = &mut 5;
+    /// assert_eq!(unsafe { *atomic_ptr.load(Ordering::SeqCst) }, 5);
+    /// ```
+    #[inline]
+    #[unstable(feature = "atomic_access", issue = "35603")]
+    pub fn get_mut(&mut self) -> &mut *mut T {
+        unsafe { &mut *self.p.get() }
+    }
+
+    /// Consumes the atomic and returns the contained value.
+    ///
+    /// This is safe because passing `self` by value guarantees that no other threads are
+    /// concurrently accessing the atomic data.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(atomic_access)]
+    /// use std::sync::atomic::AtomicPtr;
+    ///
+    /// let atomic_ptr = AtomicPtr::new(&mut 5);
+    /// assert_eq!(unsafe { *atomic_ptr.into_inner() }, 5);
+    /// ```
+    #[inline]
+    #[unstable(feature = "atomic_access", issue = "35603")]
+    pub fn into_inner(self) -> *mut T {
+        unsafe { self.p.into_inner() }
+    }
+
     /// Loads a value from the pointer.
     ///
     /// `load` takes an `Ordering` argument which describes the memory ordering of this operation.
@@ -730,8 +811,11 @@ macro_rules! atomic_int {
     ($stable:meta,
      $stable_cxchg:meta,
      $stable_debug:meta,
+     $stable_access:meta,
      $int_type:ident $atomic_type:ident $atomic_init:ident) => {
         /// An integer type which can be safely shared between threads.
+        ///
+        /// This type has the same in-memory representation as the underlying integer type.
         #[$stable]
         pub struct $atomic_type {
             v: UnsafeCell<$int_type>,
@@ -777,6 +861,48 @@ pub const fn new(v: $int_type) -> Self {
                 $atomic_type {v: UnsafeCell::new(v)}
             }
 
+            /// Returns a mutable reference to the underlying integer.
+            ///
+            /// This is safe because the mutable reference guarantees that no other threads are
+            /// concurrently accessing the atomic data.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// #![feature(atomic_access)]
+            /// use std::sync::atomic::{AtomicIsize, Ordering};
+            ///
+            /// let mut some_isize = AtomicIsize::new(10);
+            /// assert_eq!(*some_isize.get_mut(), 10);
+            /// *some_isize.get_mut() = 5;
+            /// assert_eq!(some_isize.load(Ordering::SeqCst), 5);
+            /// ```
+            #[inline]
+            #[$stable_access]
+            pub fn get_mut(&mut self) -> &mut $int_type {
+                unsafe { &mut *self.v.get() }
+            }
+
+            /// Consumes the atomic and returns the contained value.
+            ///
+            /// This is safe because passing `self` by value guarantees that no other threads are
+            /// concurrently accessing the atomic data.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// #![feature(atomic_access)]
+            /// use std::sync::atomic::AtomicIsize;
+            ///
+            /// let some_isize = AtomicIsize::new(5);
+            /// assert_eq!(some_isize.into_inner(), 5);
+            /// ```
+            #[inline]
+            #[$stable_access]
+            pub fn into_inner(self) -> $int_type {
+                unsafe { self.v.into_inner() }
+            }
+
             /// Loads a value from the atomic integer.
             ///
             /// `load` takes an `Ordering` argument which describes the memory ordering of this
@@ -1057,6 +1183,7 @@ pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     i8 AtomicI8 ATOMIC_I8_INIT
 }
 #[cfg(target_has_atomic = "8")]
@@ -1064,6 +1191,7 @@ pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     u8 AtomicU8 ATOMIC_U8_INIT
 }
 #[cfg(target_has_atomic = "16")]
@@ -1071,6 +1199,7 @@ pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     i16 AtomicI16 ATOMIC_I16_INIT
 }
 #[cfg(target_has_atomic = "16")]
@@ -1078,6 +1207,7 @@ pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     u16 AtomicU16 ATOMIC_U16_INIT
 }
 #[cfg(target_has_atomic = "32")]
@@ -1085,6 +1215,7 @@ pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     i32 AtomicI32 ATOMIC_I32_INIT
 }
 #[cfg(target_has_atomic = "32")]
@@ -1092,6 +1223,7 @@ pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     u32 AtomicU32 ATOMIC_U32_INIT
 }
 #[cfg(target_has_atomic = "64")]
@@ -1099,6 +1231,7 @@ pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     i64 AtomicI64 ATOMIC_I64_INIT
 }
 #[cfg(target_has_atomic = "64")]
@@ -1106,6 +1239,7 @@ pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     u64 AtomicU64 ATOMIC_U64_INIT
 }
 #[cfg(target_has_atomic = "ptr")]
@@ -1113,6 +1247,7 @@ pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
     stable(feature = "rust1", since = "1.0.0"),
     stable(feature = "extended_compare_and_swap", since = "1.10.0"),
     stable(feature = "atomic_debug", since = "1.3.0"),
+    unstable(feature = "atomic_access", issue = "35603"),
     isize AtomicIsize ATOMIC_ISIZE_INIT
 }
 #[cfg(target_has_atomic = "ptr")]
@@ -1120,6 +1255,7 @@ pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
     stable(feature = "rust1", since = "1.0.0"),
     stable(feature = "extended_compare_and_swap", since = "1.10.0"),
     stable(feature = "atomic_debug", since = "1.3.0"),
+    unstable(feature = "atomic_access", issue = "35603"),
     usize AtomicUsize ATOMIC_USIZE_INIT
 }
 
index abaabfd129b383d31584a10657dc0a71232f7a3c..c3608b60a31a7ad9d9d422681aee947e0f8add51 100644 (file)
 
 // See src/libstd/primitive_docs.rs for documentation.
 
-use clone::Clone;
 use cmp::*;
 use cmp::Ordering::*;
-use default::Default;
-use option::Option;
-use option::Option::Some;
 
 // FIXME(#19630) Remove this work-around
 macro_rules! e {
index a635620d12abd3618e3acda562b0c2ed49686153..a7c230ba979beacae2ba90a258ea37f69a44a492 100644 (file)
@@ -176,21 +176,21 @@ fn accessor(&self) -> RefMut<u32> {
 }
 
 #[test]
-fn as_unsafe_cell() {
+fn as_ptr() {
     let c1: Cell<usize> = Cell::new(0);
     c1.set(1);
-    assert_eq!(1, unsafe { *c1.as_unsafe_cell().get() });
+    assert_eq!(1, unsafe { *c1.as_ptr() });
 
     let c2: Cell<usize> = Cell::new(0);
-    unsafe { *c2.as_unsafe_cell().get() = 1; }
+    unsafe { *c2.as_ptr() = 1; }
     assert_eq!(1, c2.get());
 
     let r1: RefCell<usize> = RefCell::new(0);
     *r1.borrow_mut() = 1;
-    assert_eq!(1, unsafe { *r1.as_unsafe_cell().get() });
+    assert_eq!(1, unsafe { *r1.as_ptr() });
 
     let r2: RefCell<usize> = RefCell::new(0);
-    unsafe { *r2.as_unsafe_cell().get() = 1; }
+    unsafe { *r2.as_ptr() = 1; }
     assert_eq!(1, *r2.borrow());
 }
 
index 4632419336d7f5f047e0057d02a3ce48d45a44b2..199437a431eeea6c298947f6640b00c3921d71a1 100644 (file)
@@ -9,6 +9,24 @@
 // except according to those terms.
 
 use std::char;
+use std::convert::TryFrom;
+
+#[test]
+fn test_convert() {
+    assert_eq!(u32::from('a'), 0x61);
+    assert_eq!(char::from(b'\0'), '\0');
+    assert_eq!(char::from(b'a'), 'a');
+    assert_eq!(char::from(b'\xFF'), '\u{FF}');
+    assert_eq!(char::try_from(0_u32), Ok('\0'));
+    assert_eq!(char::try_from(0x61_u32), Ok('a'));
+    assert_eq!(char::try_from(0xD7FF_u32), Ok('\u{D7FF}'));
+    assert!(char::try_from(0xD800_u32).is_err());
+    assert!(char::try_from(0xDFFF_u32).is_err());
+    assert_eq!(char::try_from(0xE000_u32), Ok('\u{E000}'));
+    assert_eq!(char::try_from(0x10FFFF_u32), Ok('\u{10FFFF}'));
+    assert!(char::try_from(0x110000_u32).is_err());
+    assert!(char::try_from(0xFFFF_FFFF_u32).is_err());
+}
 
 #[test]
 fn test_is_lowercase() {
@@ -358,29 +376,50 @@ fn check(c: char) {
 
 #[test]
 fn test_decode_utf8() {
-    use core::char::*;
-    use core::iter::FromIterator;
-
-    for &(str, bs) in [("", &[] as &[u8]),
-                       ("A", &[0x41u8] as &[u8]),
-                       ("�", &[0xC1u8, 0x81u8] as &[u8]),
-                       ("♥", &[0xE2u8, 0x99u8, 0xA5u8]),
-                       ("♥A", &[0xE2u8, 0x99u8, 0xA5u8, 0x41u8] as &[u8]),
-                       ("�", &[0xE2u8, 0x99u8] as &[u8]),
-                       ("�A", &[0xE2u8, 0x99u8, 0x41u8] as &[u8]),
-                       ("�", &[0xC0u8] as &[u8]),
-                       ("�A", &[0xC0u8, 0x41u8] as &[u8]),
-                       ("�", &[0x80u8] as &[u8]),
-                       ("�A", &[0x80u8, 0x41u8] as &[u8]),
-                       ("�", &[0xFEu8] as &[u8]),
-                       ("�A", &[0xFEu8, 0x41u8] as &[u8]),
-                       ("�", &[0xFFu8] as &[u8]),
-                       ("�A", &[0xFFu8, 0x41u8] as &[u8])].into_iter() {
-        assert!(Iterator::eq(str.chars(),
-                             decode_utf8(bs.into_iter().map(|&b|b))
-                                 .map(|r_b| r_b.unwrap_or('\u{FFFD}'))),
-                "chars = {}, bytes = {:?}, decoded = {:?}", str, bs,
-                Vec::from_iter(decode_utf8(bs.into_iter().map(|&b|b))
-                                   .map(|r_b| r_b.unwrap_or('\u{FFFD}'))));
+    macro_rules! assert_decode_utf8 {
+        ($input_bytes: expr, $expected_str: expr) => {
+            let input_bytes: &[u8] = &$input_bytes;
+            let s = char::decode_utf8(input_bytes.iter().cloned())
+                .map(|r_b| r_b.unwrap_or('\u{FFFD}'))
+                .collect::<String>();
+            assert_eq!(s, $expected_str,
+                       "input bytes: {:?}, expected str: {:?}, result: {:?}",
+                       input_bytes, $expected_str, s);
+            assert_eq!(String::from_utf8_lossy(&$input_bytes), $expected_str);
+        }
     }
+
+    assert_decode_utf8!([], "");
+    assert_decode_utf8!([0x41], "A");
+    assert_decode_utf8!([0xC1, 0x81], "��");
+    assert_decode_utf8!([0xE2, 0x99, 0xA5], "♥");
+    assert_decode_utf8!([0xE2, 0x99, 0xA5, 0x41], "♥A");
+    assert_decode_utf8!([0xE2, 0x99], "�");
+    assert_decode_utf8!([0xE2, 0x99, 0x41], "�A");
+    assert_decode_utf8!([0xC0], "�");
+    assert_decode_utf8!([0xC0, 0x41], "�A");
+    assert_decode_utf8!([0x80], "�");
+    assert_decode_utf8!([0x80, 0x41], "�A");
+    assert_decode_utf8!([0xFE], "�");
+    assert_decode_utf8!([0xFE, 0x41], "�A");
+    assert_decode_utf8!([0xFF], "�");
+    assert_decode_utf8!([0xFF, 0x41], "�A");
+    assert_decode_utf8!([0xC0, 0x80], "��");
+
+    // Surrogates
+    assert_decode_utf8!([0xED, 0x9F, 0xBF], "\u{D7FF}");
+    assert_decode_utf8!([0xED, 0xA0, 0x80], "���");
+    assert_decode_utf8!([0xED, 0xBF, 0x80], "���");
+    assert_decode_utf8!([0xEE, 0x80, 0x80], "\u{E000}");
+
+    // char::MAX
+    assert_decode_utf8!([0xF4, 0x8F, 0xBF, 0xBF], "\u{10FFFF}");
+    assert_decode_utf8!([0xF4, 0x8F, 0xBF, 0x41], "�A");
+    assert_decode_utf8!([0xF4, 0x90, 0x80, 0x80], "����");
+
+    // 5 and 6 bytes sequence
+    // Part of the original design of UTF-8,
+    // but invalid now that UTF-8 is artificially restricted to match the range of UTF-16.
+    assert_decode_utf8!([0xF8, 0x80, 0x80, 0x80, 0x80], "�����");
+    assert_decode_utf8!([0xFC, 0x80, 0x80, 0x80, 0x80, 0x80], "������");
 }
index b4c94509477a31097ee489948f374ad1fe2b817c..590bf478aa723a2ffe92ebf3820f19f291ab6dbe 100644 (file)
@@ -10,7 +10,6 @@
 
 #![deny(warnings)]
 
-#![feature(as_unsafe_cell)]
 #![feature(borrow_state)]
 #![feature(box_syntax)]
 #![feature(cell_extras)]
index e0a9f4e5d422c19f2c617b65132f645e5301c97f..f7fe61896f85e84e03ca00f2c81052a61fe71a31 100644 (file)
@@ -173,12 +173,16 @@ fn test_unsized_unique() {
 }
 
 #[test]
-fn test_variadic_fnptr() {
+#[allow(warnings)]
+// Have a symbol for the test below. It doesn’t need to be an actual variadic function, match the
+// ABI, or even point to an actual executable code, because the function itself is never invoked.
+#[no_mangle]
+pub fn test_variadic_fnptr() {
     use core::hash::{Hash, SipHasher};
-    extern "C" {
-        fn printf(_: *const u8, ...);
+    extern {
+        fn test_variadic_fnptr(_: u64, ...) -> f64;
     }
-    let p: unsafe extern "C" fn(*const u8, ...) = printf;
+    let p: unsafe extern fn(u64, ...) -> f64 = test_variadic_fnptr;
     let q = p.clone();
     assert_eq!(p, q);
     assert!(!(p < q));
index 5066b7dcab7e700844b0e2ba71b8af9dc627a59b..49d64cae0699ed9d9ed84810d737a26b0b519da8 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5066b7dcab7e700844b0e2ba71b8af9dc627a59b
+Subproject commit 49d64cae0699ed9d9ed84810d737a26b0b519da8
index fdae8f69a9c0ef31f49fca61b919c7e17cfa0244..c2e8eccbd22a43d041dfb258f6c6cc2d82e6bf7d 100644 (file)
@@ -124,7 +124,7 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
 const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1
 
-#[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
+#[cfg(any(target_arch = "mips", target_arch = "mipsel", target_arch = "mips64"))]
 const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1
 
 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
@@ -264,30 +264,6 @@ unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> EHAction {
     eh::find_eh_action(lsda, &eh_context)
 }
 
-// *** Delete after a new snapshot ***
-#[cfg(all(stage0, any(target_os = "ios", not(target_arch = "arm"))))]
-#[lang = "eh_personality_catch"]
-#[no_mangle]
-pub unsafe extern "C" fn rust_eh_personality_catch(version: c_int,
-                                                    actions: uw::_Unwind_Action,
-                                                    exception_class: uw::_Unwind_Exception_Class,
-                                                    ue_header: *mut uw::_Unwind_Exception,
-                                                    context: *mut uw::_Unwind_Context)
-                                                    -> uw::_Unwind_Reason_Code {
-    rust_eh_personality(version, actions, exception_class, ue_header, context)
-}
-
-// *** Delete after a new snapshot ***
-#[cfg(all(stage0, target_arch = "arm", not(target_os = "ios")))]
-#[lang = "eh_personality_catch"]
-#[no_mangle]
-pub unsafe extern "C" fn rust_eh_personality_catch(state: uw::_Unwind_State,
-                                                    ue_header: *mut uw::_Unwind_Exception,
-                                                    context: *mut uw::_Unwind_Context)
-                                                    -> uw::_Unwind_Reason_Code {
-    rust_eh_personality(state, ue_header, context)
-}
-
 // See docs in the `unwind` module.
 #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
 #[lang = "eh_unwind_resume"]
index 3642e2488958e921fa8b1efd6a514858873a5de8..e6d3920b29cb0106da0f6e02a0ec5c09561a0929 100644 (file)
@@ -81,21 +81,6 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
 // This is considered acceptable, because the behavior of throwing exceptions
 // through a C ABI boundary is undefined.
 
-// *** Delete after a new snapshot ***
-#[cfg(stage0)]
-#[lang = "eh_personality_catch"]
-#[cfg(not(test))]
-unsafe extern "C" fn rust_eh_personality_catch(exceptionRecord: *mut c::EXCEPTION_RECORD,
-                                               establisherFrame: c::LPVOID,
-                                               contextRecord: *mut c::CONTEXT,
-                                               dispatcherContext: *mut c::DISPATCHER_CONTEXT)
-                                               -> c::EXCEPTION_DISPOSITION {
-    rust_eh_personality(exceptionRecord,
-                        establisherFrame,
-                        contextRecord,
-                        dispatcherContext)
-}
-
 #[lang = "eh_personality"]
 #[cfg(not(test))]
 unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut c::EXCEPTION_RECORD,
index 4edbeab5dfb11049cbedf1255d30608c16abcc6f..5a8a52f7dfc6e15d9b5bc215395f620ae75e1747 100644 (file)
@@ -173,12 +173,12 @@ pub fn is_empty(&self) -> bool {
         self.start == self.end
     }
 
-    pub fn as_str_slice(&self) -> &'doc str {
+    pub fn as_str(&self) -> &'doc str {
         str::from_utf8(&self.data[self.start..self.end]).unwrap()
     }
 
-    pub fn as_str(&self) -> String {
-        self.as_str_slice().to_string()
+    pub fn to_string(&self) -> String {
+        self.as_str().to_string()
     }
 }
 
@@ -726,7 +726,7 @@ fn read_u16(&mut self) -> DecodeResult<u16> {
         fn read_u8(&mut self) -> DecodeResult<u8> {
             Ok(doc_as_u8(self.next_doc(EsU8)?))
         }
-        fn read_uint(&mut self) -> DecodeResult<usize> {
+        fn read_usize(&mut self) -> DecodeResult<usize> {
             let v = self._next_int(EsU8, EsU64)?;
             if v > (::std::usize::MAX as u64) {
                 Err(IntTooBig(v as usize))
@@ -747,7 +747,7 @@ fn read_i16(&mut self) -> DecodeResult<i16> {
         fn read_i8(&mut self) -> DecodeResult<i8> {
             Ok(doc_as_u8(self.next_doc(EsI8)?) as i8)
         }
-        fn read_int(&mut self) -> DecodeResult<isize> {
+        fn read_isize(&mut self) -> DecodeResult<isize> {
             let v = self._next_int(EsI8, EsI64)? as i64;
             if v > (isize::MAX as i64) || v < (isize::MIN as i64) {
                 debug!("FIXME \\#6122: Removing this makes this function miscompile");
@@ -773,7 +773,7 @@ fn read_char(&mut self) -> DecodeResult<char> {
             Ok(char::from_u32(doc_as_u32(self.next_doc(EsChar)?)).unwrap())
         }
         fn read_str(&mut self) -> DecodeResult<String> {
-            Ok(self.next_doc(EsStr)?.as_str())
+            Ok(self.next_doc(EsStr)?.to_string())
         }
 
         // Compound types:
@@ -1219,7 +1219,7 @@ fn emit_nil(&mut self) -> EncodeResult {
             Ok(())
         }
 
-        fn emit_uint(&mut self, v: usize) -> EncodeResult {
+        fn emit_usize(&mut self, v: usize) -> EncodeResult {
             self.emit_u64(v as u64)
         }
         fn emit_u64(&mut self, v: u64) -> EncodeResult {
@@ -1247,7 +1247,7 @@ fn emit_u8(&mut self, v: u8) -> EncodeResult {
             self.wr_tagged_raw_u8(EsU8 as usize, v)
         }
 
-        fn emit_int(&mut self, v: isize) -> EncodeResult {
+        fn emit_isize(&mut self, v: isize) -> EncodeResult {
             self.emit_i64(v as i64)
         }
         fn emit_i64(&mut self, v: i64) -> EncodeResult {
index 10f419d169181da14639fa1eee06bf9d1d6cb1ee..6dc7a72b1b1bb0d234a50f128e820934f5c573e9 100644 (file)
@@ -54,7 +54,7 @@ fn emit_nil(&mut self) -> EncodeResult {
         Ok(())
     }
 
-    fn emit_uint(&mut self, v: usize) -> EncodeResult {
+    fn emit_usize(&mut self, v: usize) -> EncodeResult {
         write_uleb128!(self, v)
     }
 
@@ -75,7 +75,7 @@ fn emit_u8(&mut self, v: u8) -> EncodeResult {
         Ok(())
     }
 
-    fn emit_int(&mut self, v: isize) -> EncodeResult {
+    fn emit_isize(&mut self, v: isize) -> EncodeResult {
         write_sleb128!(self, v)
     }
 
@@ -120,7 +120,7 @@ fn emit_char(&mut self, v: char) -> EncodeResult {
     }
 
     fn emit_str(&mut self, v: &str) -> EncodeResult {
-        self.emit_uint(v.len())?;
+        self.emit_usize(v.len())?;
         let _ = self.cursor.write_all(v.as_bytes());
         Ok(())
     }
@@ -139,7 +139,7 @@ fn emit_enum_variant<F>(&mut self,
                             -> EncodeResult
         where F: FnOnce(&mut Self) -> EncodeResult
     {
-        self.emit_uint(v_id)?;
+        self.emit_usize(v_id)?;
         f(self)
     }
 
@@ -221,7 +221,7 @@ fn emit_option_some<F>(&mut self, f: F) -> EncodeResult
     fn emit_seq<F>(&mut self, len: usize, f: F) -> EncodeResult
         where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
     {
-        self.emit_uint(len)?;
+        self.emit_usize(len)?;
         f(self)
     }
 
@@ -234,7 +234,7 @@ fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -> EncodeResult
     fn emit_map<F>(&mut self, len: usize, f: F) -> EncodeResult
         where F: FnOnce(&mut Encoder<'a>) -> EncodeResult
     {
-        self.emit_uint(len)?;
+        self.emit_usize(len)?;
         f(self)
     }
 
@@ -329,7 +329,7 @@ fn read_u8(&mut self) -> Result<u8, Self::Error> {
         Ok(value)
     }
 
-    fn read_uint(&mut self) -> Result<usize, Self::Error> {
+    fn read_usize(&mut self) -> Result<usize, Self::Error> {
         read_uleb128!(self, usize)
     }
 
@@ -351,7 +351,7 @@ fn read_i8(&mut self) -> Result<i8, Self::Error> {
         unsafe { Ok(::std::mem::transmute(as_u8)) }
     }
 
-    fn read_int(&mut self) -> Result<isize, Self::Error> {
+    fn read_isize(&mut self) -> Result<isize, Self::Error> {
         read_sleb128!(self, isize)
     }
 
@@ -376,7 +376,7 @@ fn read_char(&mut self) -> Result<char, Self::Error> {
     }
 
     fn read_str(&mut self) -> Result<String, Self::Error> {
-        let len = self.read_uint()?;
+        let len = self.read_usize()?;
         let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap();
         self.position += len;
         Ok(s.to_string())
@@ -391,7 +391,7 @@ fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error>
     fn read_enum_variant<T, F>(&mut self, _: &[&str], mut f: F) -> Result<T, Self::Error>
         where F: FnMut(&mut Decoder<'a>, usize) -> Result<T, Self::Error>
     {
-        let disr = self.read_uint()?;
+        let disr = self.read_usize()?;
         f(self, disr)
     }
 
@@ -404,7 +404,7 @@ fn read_enum_variant_arg<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::
     fn read_enum_struct_variant<T, F>(&mut self, _: &[&str], mut f: F) -> Result<T, Self::Error>
         where F: FnMut(&mut Decoder<'a>, usize) -> Result<T, Self::Error>
     {
-        let disr = self.read_uint()?;
+        let disr = self.read_usize()?;
         f(self, disr)
     }
 
@@ -483,7 +483,7 @@ fn read_option<T, F>(&mut self, mut f: F) -> Result<T, Self::Error>
     fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error>
         where F: FnOnce(&mut Decoder<'a>, usize) -> Result<T, Self::Error>
     {
-        let len = self.read_uint()?;
+        let len = self.read_usize()?;
         f(self, len)
     }
 
@@ -496,7 +496,7 @@ fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
     fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error>
         where F: FnOnce(&mut Decoder<'a>, usize) -> Result<T, Self::Error>
     {
-        let len = self.read_uint()?;
+        let len = self.read_usize()?;
         f(self, len)
     }
 
index 40fd3dede3d08b5399312d8fc2fa82719c188d42..18179027c25de9a6ef68d5746e73d6b8dace658a 100644 (file)
@@ -132,7 +132,7 @@ pub enum DepNode<D: Clone + Debug> {
     // which would yield an overly conservative dep-graph.
     TraitItems(D),
     ReprHints(D),
-    TraitSelect(D, Vec<D>),
+    TraitSelect(Vec<D>),
 }
 
 impl<D: Clone + Debug> DepNode<D> {
@@ -147,6 +147,11 @@ macro_rules! check {
             }
         }
 
+        if label == "Krate" {
+            // special case
+            return Ok(DepNode::Krate);
+        }
+
         check! {
             CollectItem,
             BorrowCheck,
@@ -232,10 +237,9 @@ pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
             TraitImpls(ref d) => op(d).map(TraitImpls),
             TraitItems(ref d) => op(d).map(TraitItems),
             ReprHints(ref d) => op(d).map(ReprHints),
-            TraitSelect(ref d, ref type_ds) => {
-                let d = try_opt!(op(d));
+            TraitSelect(ref type_ds) => {
                 let type_ds = try_opt!(type_ds.iter().map(|d| op(d)).collect());
-                Some(TraitSelect(d, type_ds))
+                Some(TraitSelect(type_ds))
             }
         }
     }
index 07e54dc9e8796e77f8ef9fed8ffb4e985ff995ba..de68cc707ad7a2020e3d7e6061f46968697ce394 100644 (file)
@@ -1527,6 +1527,37 @@ fn main() {
 ```
 "##,
 
+E0478: r##"
+A lifetime bound was not satisfied.
+
+Erroneous code example:
+
+```compile_fail,E0478
+// Check that the explicit lifetime bound (`'SnowWhite`, in this example) must
+// outlive all the superbounds from the trait (`'kiss`, in this example).
+
+trait Wedding<'t>: 't { }
+
+struct Prince<'kiss, 'SnowWhite> {
+    child: Box<Wedding<'kiss> + 'SnowWhite>,
+    // error: lifetime bound not satisfied
+}
+```
+
+In this example, the `'SnowWhite` lifetime is supposed to outlive the `'kiss`
+lifetime but the declaration of the `Prince` struct doesn't enforce it. To fix
+this issue, you need to specify it:
+
+```
+trait Wedding<'t>: 't { }
+
+struct Prince<'kiss, 'SnowWhite: 'kiss> { // You say here that 'kiss must live
+                                          // longer than 'SnowWhite.
+    child: Box<Wedding<'kiss> + 'SnowWhite>, // And now it's all good!
+}
+```
+"##,
+
 E0496: r##"
 A lifetime name is shadowing another lifetime name. Erroneous code example:
 
@@ -1690,6 +1721,50 @@ fn cookie() -> ! { // error: definition of an unknown language item: `cookie`
 ```
 "##,
 
+E0525: r##"
+A closure was attempted to get used whereas it doesn't implement the expected
+trait.
+
+Erroneous code example:
+
+```compile_fail,E0525
+struct X;
+
+fn foo<T>(_: T) {}
+fn bar<T: Fn(u32)>(_: T) {}
+
+fn main() {
+    let x = X;
+    let closure = |_| foo(x); // error: expected a closure that implements
+                              //        the `Fn` trait, but this closure only
+                              //        implements `FnOnce`
+    bar(closure);
+}
+```
+
+In the example above, `closure` is an `FnOnce` closure whereas the `bar`
+function expected an `Fn` closure. In this case, it's simple to fix the issue,
+you just have to implement `Copy` and `Clone` traits on `struct X` and it'll
+be ok:
+
+```
+#[derive(Clone, Copy)] // We implement `Clone` and `Copy` traits.
+struct X;
+
+fn foo<T>(_: T) {}
+fn bar<T: Fn(u32)>(_: T) {}
+
+fn main() {
+    let x = X;
+    let closure = |_| foo(x);
+    bar(closure); // ok!
+}
+```
+
+To understand better how closures work in Rust, read:
+https://doc.rust-lang.org/book/closures.html
+"##,
+
 }
 
 
@@ -1715,7 +1790,6 @@ fn cookie() -> ! { // error: definition of an unknown language item: `cookie`
     E0475, // index of slice outside its lifetime
     E0476, // lifetime of the source pointer does not outlive lifetime bound...
     E0477, // the type `..` does not fulfill the required lifetime...
-    E0478, // lifetime bound not satisfied
     E0479, // the type `..` (provided as the value of a type parameter) is...
     E0480, // lifetime of method receiver does not outlive the method call
     E0481, // lifetime of function argument does not outlive the function call
@@ -1730,5 +1804,5 @@ fn cookie() -> ! { // error: definition of an unknown language item: `cookie`
     E0490, // a value of type `..` is borrowed for too long
     E0491, // in type `..`, reference has a longer lifetime than the data it...
     E0495, // cannot infer an appropriate lifetime due to conflicting requirements
-    E0525  // expected a closure that implements `..` but this closure only implements `..`
+    E0566  // conflicting representation hints
 }
index a1c04dfcab5e66be6616e59a307ff81eaa5fbff4..53624702c848b4138ace55642e6ed8c95c21deba 100644 (file)
@@ -11,7 +11,6 @@
 use session::Session;
 
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax::visit;
 use syntax::visit::Visitor;
 
@@ -52,18 +51,34 @@ fn check_repr(&self, attr: &ast::Attribute, target: Target) {
                 return;
             }
         };
+
+        let mut conflicting_reprs = 0;
         for word in words {
-            let word: &str = &word.name();
-            let message = match word {
+            let name = match word.name() {
+                Some(word) => word,
+                None => continue,
+            };
+
+            let message = match &*name {
                 "C" => {
+                    conflicting_reprs += 1;
                     if target != Target::Struct && target != Target::Enum {
-                            "attribute should be applied to struct or enum"
+                        "attribute should be applied to struct or enum"
+                    } else {
+                        continue
+                    }
+                }
+                "packed" => {
+                    // Do not increment conflicting_reprs here, because "packed"
+                    // can be used to modify another repr hint
+                    if target != Target::Struct {
+                        "attribute should be applied to struct"
                     } else {
                         continue
                     }
                 }
-                "packed" |
                 "simd" => {
+                    conflicting_reprs += 1;
                     if target != Target::Struct {
                         "attribute should be applied to struct"
                     } else {
@@ -73,16 +88,22 @@ fn check_repr(&self, attr: &ast::Attribute, target: Target) {
                 "i8" | "u8" | "i16" | "u16" |
                 "i32" | "u32" | "i64" | "u64" |
                 "isize" | "usize" => {
+                    conflicting_reprs += 1;
                     if target != Target::Enum {
-                            "attribute should be applied to enum"
+                        "attribute should be applied to enum"
                     } else {
                         continue
                     }
                 }
                 _ => continue,
             };
+
             span_err!(self.sess, attr.span, E0517, "{}", message);
         }
+        if conflicting_reprs > 1 {
+            span_warn!(self.sess, attr.span, E0566,
+                       "conflicting representation hints");
+        }
     }
 
     fn check_attribute(&self, attr: &ast::Attribute, target: Target) {
index 0edfd16bdfd1b7ca07d9e3af5d222e5a44e796d0..12bc49c10dabc77bd5b57f38204ffbd037844e98 100644 (file)
@@ -12,8 +12,8 @@
 //! and returns a piece of the same type.
 
 use hir::*;
-use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_, MetaItem};
-use syntax::ast::MetaItemKind;
+use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_};
+use syntax::ast::{NestedMetaItem, NestedMetaItemKind, MetaItem, MetaItemKind};
 use hir;
 use syntax_pos::Span;
 use syntax::codemap::{respan, Spanned};
@@ -38,6 +38,10 @@ fn fold_meta_items(&mut self, meta_items: HirVec<P<MetaItem>>) -> HirVec<P<MetaI
         noop_fold_meta_items(meta_items, self)
     }
 
+    fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem {
+        noop_fold_meta_list_item(list_item, self)
+    }
+
     fn fold_meta_item(&mut self, meta_item: P<MetaItem>) -> P<MetaItem> {
         noop_fold_meta_item(meta_item, self)
     }
@@ -271,16 +275,10 @@ pub fn noop_fold_view_path<T: Folder>(view_path: P<ViewPath>, fld: &mut T) -> P<
                     ViewPathList(fld.fold_path(path),
                                  path_list_idents.move_map(|path_list_ident| {
                                      Spanned {
-                                         node: match path_list_ident.node {
-                                             PathListIdent { id, name, rename } => PathListIdent {
-                                                 id: fld.new_id(id),
-                                                 name: name,
-                                                 rename: rename,
-                                             },
-                                             PathListMod { id, rename } => PathListMod {
-                                                 id: fld.new_id(id),
-                                                 rename: rename,
-                                             },
+                                         node: PathListItem_ {
+                                             id: fld.new_id(path_list_ident.node.id),
+                                             name: path_list_ident.node.name,
+                                             rename: path_list_ident.node.rename,
                                          },
                                          span: fld.new_span(path_list_ident.span),
                                      }
@@ -486,13 +484,26 @@ pub fn noop_fold_attribute<T: Folder>(at: Attribute, fld: &mut T) -> Option<Attr
     })
 }
 
+pub fn noop_fold_meta_list_item<T: Folder>(li: NestedMetaItem, fld: &mut T)
+    -> NestedMetaItem {
+    Spanned {
+        node: match li.node {
+            NestedMetaItemKind::MetaItem(mi) =>  {
+                NestedMetaItemKind::MetaItem(fld.fold_meta_item(mi))
+            },
+            NestedMetaItemKind::Literal(lit) => NestedMetaItemKind::Literal(lit)
+        },
+        span: fld.new_span(li.span)
+    }
+}
+
 pub fn noop_fold_meta_item<T: Folder>(mi: P<MetaItem>, fld: &mut T) -> P<MetaItem> {
     mi.map(|Spanned { node, span }| {
         Spanned {
             node: match node {
                 MetaItemKind::Word(id) => MetaItemKind::Word(id),
                 MetaItemKind::List(id, mis) => {
-                    MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_item(e)))
+                    MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_list_item(e)))
                 }
                 MetaItemKind::NameValue(id, s) => MetaItemKind::NameValue(id, s),
             },
@@ -577,13 +588,14 @@ pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: Option<Lifetime>, fld: &mut T) ->
     o_lt.map(|lt| fld.fold_lifetime(lt))
 }
 
-pub fn noop_fold_generics<T: Folder>(Generics { ty_params, lifetimes, where_clause }: Generics,
+pub fn noop_fold_generics<T: Folder>(Generics {ty_params, lifetimes, where_clause, span}: Generics,
                                      fld: &mut T)
                                      -> Generics {
     Generics {
         ty_params: fld.fold_ty_params(ty_params),
         lifetimes: fld.fold_lifetime_defs(lifetimes),
         where_clause: fld.fold_where_clause(where_clause),
+        span: fld.new_span(span),
     }
 }
 
index 92b956788860ee1058d4c7fb9b773f72b2d70e19..bc1dff7c6fc312e27e08d3fa10b2792ebc110e8d 100644 (file)
@@ -444,12 +444,12 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) {
     }
 }
 
-pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V,
-                                               _prefix: &'v Path,
-                                               item: &'v PathListItem) {
-    visitor.visit_id(item.node.id());
-    walk_opt_name(visitor, item.span, item.node.name());
-    walk_opt_name(visitor, item.span, item.node.rename());
+pub fn walk_path_list_item<'v, V>(visitor: &mut V, _prefix: &'v Path, item: &'v PathListItem)
+    where V: Visitor<'v>,
+{
+    visitor.visit_id(item.node.id);
+    visitor.visit_name(item.span, item.node.name);
+    walk_opt_name(visitor, item.span, item.node.rename);
 }
 
 pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V,
index c2b211238b2f1d1262ac1c812fa8a3667b6eac83..6739d3f662ac6f69dbe664be258138cde9a7f8e0 100644 (file)
@@ -218,16 +218,10 @@ fn lower_view_path(&mut self, view_path: &ViewPath) -> P<hir::ViewPath> {
 
     fn lower_path_list_item(&mut self, path_list_ident: &PathListItem) -> hir::PathListItem {
         Spanned {
-            node: match path_list_ident.node {
-                PathListItemKind::Ident { id, name, rename } => hir::PathListIdent {
-                    id: id,
-                    name: name.name,
-                    rename: rename.map(|x| x.name),
-                },
-                PathListItemKind::Mod { id, rename } => hir::PathListMod {
-                    id: id,
-                    rename: rename.map(|x| x.name),
-                },
+            node: hir::PathListItem_ {
+                id: path_list_ident.node.id,
+                name: path_list_ident.node.name.name,
+                rename: path_list_ident.node.rename.map(|rename| rename.name),
             },
             span: path_list_ident.span,
         }
@@ -466,6 +460,7 @@ fn lower_generics(&mut self, g: &Generics) -> hir::Generics {
             ty_params: self.lower_ty_params(&g.ty_params),
             lifetimes: self.lower_lifetime_defs(&g.lifetimes),
             where_clause: self.lower_where_clause(&g.where_clause),
+            span: g.span,
         }
     }
 
@@ -643,6 +638,7 @@ fn lower_item_kind(&mut self, i: &ItemKind) -> hir::Item_ {
                 let struct_def = self.lower_variant_data(struct_def);
                 hir::ItemStruct(struct_def, self.lower_generics(generics))
             }
+            ItemKind::Union(..) => panic!("`union` is not yet implemented"),
             ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
                 hir::ItemDefaultImpl(self.lower_unsafety(unsafety),
                                      self.lower_trait_ref(trait_ref))
@@ -809,8 +805,8 @@ fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety {
         }
     }
 
-    fn lower_constness(&mut self, c: Constness) -> hir::Constness {
-        match c {
+    fn lower_constness(&mut self, c: Spanned<Constness>) -> hir::Constness {
+        match c.node {
             Constness::Const => hir::Constness::Const,
             Constness::NotConst => hir::Constness::NotConst,
         }
@@ -966,7 +962,7 @@ fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
                     let inplace_finalize = ["ops", "InPlace", "finalize"];
 
                     let make_call = |this: &mut LoweringContext, p, args| {
-                        let path = this.core_path(e.span, p);
+                        let path = this.std_path(e.span, p);
                         let path = this.expr_path(path, ThinVec::new());
                         this.expr_call(e.span, path, args)
                     };
@@ -1159,15 +1155,13 @@ fn make_struct(this: &mut LoweringContext,
                                    ast_expr: &Expr,
                                    path: &[&str],
                                    fields: &[(&str, &P<Expr>)]) -> P<hir::Expr> {
-                        let strs = this.std_path(&iter::once(&"ops")
-                                                        .chain(path)
-                                                        .map(|s| *s)
-                                                        .collect::<Vec<_>>());
-
-                        let structpath = this.path_global(ast_expr.span, strs);
+                        let struct_path = this.std_path(ast_expr.span,
+                                                        &iter::once(&"ops").chain(path)
+                                                                           .map(|s| *s)
+                                                                           .collect::<Vec<_>>());
 
                         let hir_expr = if fields.len() == 0 {
-                            this.expr_path(structpath, ast_expr.attrs.clone())
+                            this.expr_path(struct_path, ast_expr.attrs.clone())
                         } else {
                             let fields = fields.into_iter().map(|&(s, e)| {
                                 let expr = this.lower_expr(&e);
@@ -1180,7 +1174,7 @@ fn make_struct(this: &mut LoweringContext,
                             }).collect();
                             let attrs = ast_expr.attrs.clone();
 
-                            this.expr_struct(ast_expr.span, structpath, fields, None, attrs)
+                            this.expr_struct(ast_expr.span, struct_path, fields, None, attrs)
                         };
 
                         this.signal_block_expr(hir_vec![],
@@ -1463,11 +1457,7 @@ fn make_struct(this: &mut LoweringContext,
 
                     // `match ::std::iter::Iterator::next(&mut iter) { ... }`
                     let match_expr = {
-                        let next_path = {
-                            let strs = self.std_path(&["iter", "Iterator", "next"]);
-
-                            self.path_global(e.span, strs)
-                        };
+                        let next_path = self.std_path(e.span, &["iter", "Iterator", "next"]);
                         let iter = self.expr_ident(e.span, iter, iter_pat.id);
                         let ref_mut_iter = self.expr_mut_addr_of(e.span, iter);
                         let next_path = self.expr_path(next_path, ThinVec::new());
@@ -1494,11 +1484,8 @@ fn make_struct(this: &mut LoweringContext,
 
                     // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
                     let into_iter_expr = {
-                        let into_iter_path = {
-                            let strs = self.std_path(&["iter", "IntoIterator", "into_iter"]);
-
-                            self.path_global(e.span, strs)
-                        };
+                        let into_iter_path = self.std_path(e.span,
+                                                           &["iter", "IntoIterator", "into_iter"]);
 
                         let into_iter = self.expr_path(into_iter_path, ThinVec::new());
                         self.expr_call(e.span, into_iter, hir_vec![head])
@@ -1527,16 +1514,32 @@ fn make_struct(this: &mut LoweringContext,
                     // to:
                     //
                     // {
-                    //     match <expr> {
+                    //     match { Carrier::translate( { <expr> } ) } {
                     //         Ok(val) => val,
-                    //         Err(err) => {
-                    //             return Err(From::from(err))
-                    //         }
+                    //         Err(err) => { return Carrier::from_error(From::from(err)); }
                     //     }
                     // }
 
-                    // expand <expr>
-                    let sub_expr = self.lower_expr(sub_expr);
+                    // { Carrier::translate( { <expr> } ) }
+                    let discr = {
+                        // expand <expr>
+                        let sub_expr = self.lower_expr(sub_expr);
+                        let sub_expr = self.signal_block_expr(hir_vec![],
+                                                              sub_expr,
+                                                              e.span,
+                                                              hir::PopUnstableBlock,
+                                                              ThinVec::new());
+
+                        let path = self.std_path(e.span, &["ops", "Carrier", "translate"]);
+                        let path = self.expr_path(path, ThinVec::new());
+                        let call = self.expr_call(e.span, path, hir_vec![sub_expr]);
+
+                        self.signal_block_expr(hir_vec![],
+                                               call,
+                                               e.span,
+                                               hir::PushUnstableBlock,
+                                               ThinVec::new())
+                    };
 
                     // Ok(val) => val
                     let ok_arm = {
@@ -1548,32 +1551,35 @@ fn make_struct(this: &mut LoweringContext,
                         self.arm(hir_vec![ok_pat], val_expr)
                     };
 
-                    // Err(err) => return Err(From::from(err))
+                    // Err(err) => { return Carrier::from_error(From::from(err)); }
                     let err_arm = {
                         let err_ident = self.str_to_ident("err");
                         let err_local = self.pat_ident(e.span, err_ident);
                         let from_expr = {
-                            let path = self.std_path(&["convert", "From", "from"]);
-                            let path = self.path_global(e.span, path);
+                            let path = self.std_path(e.span, &["convert", "From", "from"]);
                             let from = self.expr_path(path, ThinVec::new());
                             let err_expr = self.expr_ident(e.span, err_ident, err_local.id);
 
                             self.expr_call(e.span, from, hir_vec![err_expr])
                         };
-                        let err_expr = {
-                            let path = self.std_path(&["result", "Result", "Err"]);
-                            let path = self.path_global(e.span, path);
-                            let err_ctor = self.expr_path(path, ThinVec::new());
-                            self.expr_call(e.span, err_ctor, hir_vec![from_expr])
+                        let from_err_expr = {
+                            let path = self.std_path(e.span, &["ops", "Carrier", "from_error"]);
+                            let from_err = self.expr_path(path, ThinVec::new());
+                            self.expr_call(e.span, from_err, hir_vec![from_expr])
                         };
-                        let err_pat = self.pat_err(e.span, err_local);
+
                         let ret_expr = self.expr(e.span,
-                                                 hir::Expr_::ExprRet(Some(err_expr)),
-                                                 ThinVec::new());
-                        self.arm(hir_vec![err_pat], ret_expr)
+                                                 hir::Expr_::ExprRet(Some(from_err_expr)),
+                                                                     ThinVec::new());
+                        let ret_stmt = self.stmt_expr(ret_expr);
+                        let block = self.signal_block_stmt(ret_stmt, e.span,
+                                                           hir::PushUnstableBlock, ThinVec::new());
+
+                        let err_pat = self.pat_err(e.span, err_local);
+                        self.arm(hir_vec![err_pat], block)
                     };
 
-                    return self.expr_match(e.span, sub_expr, hir_vec![err_arm, ok_arm],
+                    return self.expr_match(e.span, discr, hir_vec![err_arm, ok_arm],
                                            hir::MatchSource::TryDesugar);
                 }
 
@@ -1787,6 +1793,15 @@ fn stmt_let(&mut self, sp: Span, mutbl: bool, ident: Name, ex: P<hir::Expr>)
         (respan(sp, hir::StmtDecl(P(decl), self.next_id())), pat_id)
     }
 
+    // Turns `<expr>` into `<expr>;`, note that this produces a StmtSemi, not a
+    // StmtExpr.
+    fn stmt_expr(&self, expr: P<hir::Expr>) -> hir::Stmt {
+        hir::Stmt {
+            span: expr.span,
+            node: hir::StmtSemi(expr, self.next_id()),
+        }
+    }
+
     fn block_expr(&mut self, expr: P<hir::Expr>) -> P<hir::Block> {
         self.block_all(expr.span, hir::HirVec::new(), Some(expr))
     }
@@ -1803,26 +1818,22 @@ fn block_all(&mut self, span: Span, stmts: hir::HirVec<hir::Stmt>, expr: Option<
     }
 
     fn pat_ok(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
-        let ok = self.std_path(&["result", "Result", "Ok"]);
-        let path = self.path_global(span, ok);
+        let path = self.std_path(span, &["result", "Result", "Ok"]);
         self.pat_enum(span, path, hir_vec![pat])
     }
 
     fn pat_err(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
-        let err = self.std_path(&["result", "Result", "Err"]);
-        let path = self.path_global(span, err);
+        let path = self.std_path(span, &["result", "Result", "Err"]);
         self.pat_enum(span, path, hir_vec![pat])
     }
 
     fn pat_some(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
-        let some = self.std_path(&["option", "Option", "Some"]);
-        let path = self.path_global(span, some);
+        let path = self.std_path(span, &["option", "Option", "Some"]);
         self.pat_enum(span, path, hir_vec![pat])
     }
 
     fn pat_none(&mut self, span: Span) -> P<hir::Pat> {
-        let none = self.std_path(&["option", "Option", "None"]);
-        let path = self.path_global(span, none);
+        let path = self.std_path(span, &["option", "Option", "None"]);
         self.pat_enum(span, path, hir_vec![])
     }
 
@@ -1920,7 +1931,7 @@ fn path_all(&mut self,
         }
     }
 
-    fn std_path(&mut self, components: &[&str]) -> Vec<Name> {
+    fn std_path_components(&mut self, components: &[&str]) -> Vec<Name> {
         let mut v = Vec::new();
         if let Some(s) = self.crate_root {
             v.push(token::intern(s));
@@ -1931,8 +1942,8 @@ fn std_path(&mut self, components: &[&str]) -> Vec<Name> {
 
     // Given suffix ["b","c","d"], returns path `::std::b::c::d` when
     // `fld.cx.use_std`, and `::core::b::c::d` otherwise.
-    fn core_path(&mut self, span: Span, components: &[&str]) -> hir::Path {
-        let idents = self.std_path(components);
+    fn std_path(&mut self, span: Span, components: &[&str]) -> hir::Path {
+        let idents = self.std_path_components(components);
         self.path_global(span, idents)
     }
 
@@ -1953,4 +1964,21 @@ fn signal_block_expr(&mut self,
         });
         self.expr_block(block, attrs)
     }
+
+    fn signal_block_stmt(&mut self,
+                         stmt: hir::Stmt,
+                         span: Span,
+                         rule: hir::BlockCheckMode,
+                         attrs: ThinVec<Attribute>)
+                         -> P<hir::Expr> {
+        let id = self.next_id();
+        let block = P(hir::Block {
+            rules: rule,
+            span: span,
+            id: id,
+            stmts: hir_vec![stmt],
+            expr: None,
+        });
+        self.expr_block(block, attrs)
+    }
 }
index 50e8c6e7ab842e59adbec3e7336a1ec2a62492d7..4487234885692f05f34e205b58c4d0fedcbfa1a1 100644 (file)
 
 pub use self::Code::*;
 
+use hir as ast;
 use hir::map::{self, Node};
-use syntax::abi;
 use hir::{Block, FnDecl};
+use hir::intravisit::FnKind;
+use syntax::abi;
 use syntax::ast::{Attribute, Name, NodeId};
-use hir as ast;
 use syntax_pos::Span;
-use hir::intravisit::FnKind;
 
 /// An FnLikeNode is a Node that is like a fn, in that it has a decl
 /// and a body (as well as a NodeId, a span, etc).
index b70190181af8fcf80123a70d575af4cc1bda43e9..280c0f304856990810b38169af7f76a4d43b7848 100644 (file)
@@ -120,7 +120,7 @@ fn visit_item(&mut self, i: &'ast Item) {
                     match view_path.node {
                         ViewPathList(_, ref paths) => {
                             for path in paths {
-                                this.insert(path.node.id(), NodeItem(i));
+                                this.insert(path.node.id, NodeItem(i));
                             }
                         }
                         _ => ()
index 752b0e9a253dd9a7ee1cf41cd922c1f8467ce1c2..77567fc7a46031ff29d07e3dfd978715d9d06cf8 100644 (file)
@@ -133,7 +133,7 @@ fn visit_item(&mut self, i: &Item) {
         let def_data = match i.node {
             ItemKind::DefaultImpl(..) | ItemKind::Impl(..) =>
                 DefPathData::Impl,
-            ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Trait(..) |
+            ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) |
             ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
                 DefPathData::TypeNs(i.ident.name.as_str()),
             ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()),
@@ -164,7 +164,7 @@ fn visit_item(&mut self, i: &Item) {
                         });
                     }
                 }
-                ItemKind::Struct(ref struct_def, _) => {
+                ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => {
                     // If this is a tuple-like struct, register the constructor.
                     if !struct_def.is_struct() {
                         this.create_def(struct_def.id(),
index 7e82a4a05a76461216731761e4ed6b1c9b33284e..5e14bb51ce8672fe5dffd5ec332d8bf7cc543dd1 100644 (file)
@@ -315,8 +315,7 @@ fn dep_node(&self, id0: NodeId) -> DepNode<DefId> {
                     RootInlinedParent(parent) => match *parent {
                         InlinedItem::Item(def_id, _) |
                         InlinedItem::TraitItem(def_id, _) |
-                        InlinedItem::ImplItem(def_id, _) |
-                        InlinedItem::Foreign(def_id, _) =>
+                        InlinedItem::ImplItem(def_id, _) =>
                             return DepNode::MetaData(def_id)
                     },
 
@@ -569,6 +568,13 @@ pub fn expect_item(&self, id: NodeId) -> &'ast Item {
         }
     }
 
+    pub fn expect_impl_item(&self, id: NodeId) -> &'ast ImplItem {
+        match self.find(id) {
+            Some(NodeImplItem(item)) => item,
+            _ => bug!("expected impl item, found {}", self.node_to_string(id))
+        }
+    }
+
     pub fn expect_trait_item(&self, id: NodeId) -> &'ast TraitItem {
         match self.find(id) {
             Some(NodeTraitItem(item)) => item,
@@ -933,8 +939,6 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
             II::ImplItem(fld.fold_ops.new_def_id(d),
                          ii.map(|ii| fld.fold_impl_item(ii)))
         }
-        II::Foreign(d, i) => II::Foreign(fld.fold_ops.new_def_id(d),
-                                         i.map(|i| fld.fold_foreign_item(i)))
     };
 
     let ii = map.forest.inlined_items.alloc(ii);
index d41cdfabdf4c04a55b841385bb6dccadd131cd39..295a49d26d0fed82b8a3046d7bfe276557e3d014 100644 (file)
@@ -20,7 +20,6 @@
 pub use self::ForeignItem_::*;
 pub use self::Item_::*;
 pub use self::Mutability::*;
-pub use self::PathListItem_::*;
 pub use self::PrimTy::*;
 pub use self::Stmt_::*;
 pub use self::TraitItem_::*;
@@ -36,7 +35,7 @@
 use hir::def_id::DefId;
 use util::nodemap::{NodeMap, FnvHashSet};
 
-use syntax_pos::{BytePos, mk_sp, Span, ExpnId};
+use syntax_pos::{mk_sp, Span, ExpnId, DUMMY_SP};
 use syntax::codemap::{self, respan, Spanned};
 use syntax::abi::Abi;
 use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect};
@@ -301,6 +300,7 @@ pub struct Generics {
     pub lifetimes: HirVec<LifetimeDef>,
     pub ty_params: HirVec<TyParam>,
     pub where_clause: WhereClause,
+    pub span: Span,
 }
 
 impl Generics {
@@ -312,6 +312,7 @@ pub fn empty() -> Generics {
                 id: DUMMY_NODE_ID,
                 predicates: HirVec::new(),
             },
+            span: DUMMY_SP,
         }
     }
 
@@ -326,38 +327,6 @@ pub fn is_type_parameterized(&self) -> bool {
     pub fn is_parameterized(&self) -> bool {
         self.is_lt_parameterized() || self.is_type_parameterized()
     }
-
-    // Does return a span which includes lifetimes and type parameters,
-    // not where clause.
-    pub fn span(&self) -> Option<Span> {
-        if !self.is_parameterized() {
-            None
-        } else {
-            let mut span: Option<Span> = None;
-            for lifetime in self.lifetimes.iter() {
-                if let Some(ref mut span) = span {
-                    let life_span = lifetime.lifetime.span;
-                    span.hi = if span.hi > life_span.hi { span.hi } else { life_span.hi };
-                    span.lo = if span.lo < life_span.lo { span.lo } else { life_span.lo };
-                } else {
-                    span = Some(lifetime.lifetime.span.clone());
-                }
-            }
-            for ty_param in self.ty_params.iter() {
-                if let Some(ref mut span) = span {
-                    span.lo = if span.lo < ty_param.span.lo { span.lo } else { ty_param.span.lo };
-                    span.hi = if span.hi > ty_param.span.hi { span.hi } else { ty_param.span.hi };
-                } else {
-                    span = Some(ty_param.span.clone());
-                }
-            }
-            if let Some(ref mut span) = span {
-                span.lo = span.lo - BytePos(1);
-                span.hi = span.hi + BytePos(1);
-            }
-            span
-        }
-    }
 }
 
 /// A `where` clause in a definition
@@ -1337,39 +1306,11 @@ pub struct Variant_ {
 pub type Variant = Spanned<Variant_>;
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum PathListItem_ {
-    PathListIdent {
-        name: Name,
-        /// renamed in list, eg `use foo::{bar as baz};`
-        rename: Option<Name>,
-        id: NodeId,
-    },
-    PathListMod {
-        /// renamed in list, eg `use foo::{self as baz};`
-        rename: Option<Name>,
-        id: NodeId,
-    },
-}
-
-impl PathListItem_ {
-    pub fn id(&self) -> NodeId {
-        match *self {
-            PathListIdent { id, .. } | PathListMod { id, .. } => id,
-        }
-    }
-
-    pub fn name(&self) -> Option<Name> {
-        match *self {
-            PathListIdent { name, .. } => Some(name),
-            PathListMod { .. } => None,
-        }
-    }
-
-    pub fn rename(&self) -> Option<Name> {
-        match *self {
-            PathListIdent { rename, .. } | PathListMod { rename, .. } => rename,
-        }
-    }
+pub struct PathListItem_ {
+    pub name: Name,
+    /// renamed in list, eg `use foo::{bar as baz};`
+    pub rename: Option<Name>,
+    pub id: NodeId,
 }
 
 pub type PathListItem = Spanned<PathListItem_>;
@@ -1621,7 +1562,7 @@ pub struct Freevar {
 
 pub type CaptureModeMap = NodeMap<CaptureClause>;
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct TraitCandidate {
     pub def_id: DefId,
     pub import_id: Option<NodeId>,
index 66c1bc7642c56b682ce9da0b33d4844483f4fedc..893d6708ead4b4993582017fb347a3e0150b88c7 100644 (file)
@@ -523,6 +523,7 @@ pub fn print_type(&mut self, ty: &hir::Ty) -> io::Result<()> {
                         id: ast::DUMMY_NODE_ID,
                         predicates: hir::HirVec::new(),
                     },
+                    span: syntax_pos::DUMMY_SP,
                 };
                 self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &generics)?;
             }
@@ -2133,16 +2134,7 @@ pub fn print_view_path(&mut self, vp: &hir::ViewPath) -> io::Result<()> {
                     self.print_path(path, false, 0)?;
                     word(&mut self.s, "::{")?;
                 }
-                self.commasep(Inconsistent, &segments[..], |s, w| {
-                    match w.node {
-                        hir::PathListIdent { name, .. } => {
-                            s.print_name(name)
-                        }
-                        hir::PathListMod { .. } => {
-                            word(&mut s.s, "self")
-                        }
-                    }
-                })?;
+                self.commasep(Inconsistent, &segments[..], |s, w| s.print_name(w.node.name))?;
                 word(&mut self.s, "}")
             }
         }
@@ -2224,6 +2216,7 @@ pub fn print_ty_fn(&mut self,
                 id: ast::DUMMY_NODE_ID,
                 predicates: hir::HirVec::new(),
             },
+            span: syntax_pos::DUMMY_SP,
         };
         self.print_fn(decl,
                       unsafety,
index d4e797c9f2d25b758cea756355739c4be43158ee..ae1f9d3028c2c08075934fc18654d212bb7decaa 100644 (file)
@@ -17,6 +17,7 @@
 
 use std::fmt;
 use std::hash::{Hash, Hasher};
+use serialize::{Encodable, Decodable, Encoder, Decoder};
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub struct Svh {
@@ -51,3 +52,17 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.pad(&self.to_string())
     }
 }
+
+impl Encodable for Svh {
+    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        s.emit_u64(self.as_u64().to_le())
+    }
+}
+
+impl Decodable for Svh {
+    fn decode<D: Decoder>(d: &mut D) -> Result<Svh, D::Error> {
+        d.read_u64()
+         .map(u64::from_le)
+         .map(Svh::new)
+    }
+}
index 125f815feda6fa6d902bea13a91be128cb1a603c..4acb8b807d594efcc0f6b8be67ec1165a93c9a9f 100644 (file)
@@ -106,7 +106,8 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         }
     }
 
-    fn regions(&mut self, a: ty::Region, _: ty::Region) -> RelateResult<'tcx, ty::Region> {
+    fn regions(&mut self, a: &'tcx ty::Region, _: &'tcx ty::Region)
+               -> RelateResult<'tcx, &'tcx ty::Region> {
         Ok(a)
     }
 
index b4818f963b3ba76e4b6ae71f2ad4f381dbbd1616..5ce30484ede0027aab5c595d58a5ef906067ea86 100644 (file)
@@ -329,8 +329,8 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
 
-    fn fold_region(&mut self, r: ty::Region) -> ty::Region {
-        match r {
+    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+        match *r {
             // Never make variables for regions bound within the type itself,
             // nor for erased regions.
             ty::ReLateBound(..) |
index e06f7303acb2927ac99950a43b087c39f9c6c7ac..bf247acec5a2d31112c5a787ac2b7772ab029318 100644 (file)
@@ -79,7 +79,8 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         }
     }
 
-    fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+    fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
+               -> RelateResult<'tcx, &'tcx ty::Region> {
         debug!("{}.regions({:?}, {:?})",
                self.tag(),
                a,
index 9a6375719c1bcd406138ce002a37e941c8bdc178..0cd39882b7cded58095b89aaf1db114ce6d2a0f8 100644 (file)
@@ -99,7 +99,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn note_and_explain_region(self,
                                    err: &mut DiagnosticBuilder,
                                    prefix: &str,
-                                   region: ty::Region,
+                                   region: &'tcx ty::Region,
                                    suffix: &str) {
         fn item_scope_tag(item: &hir::Item) -> &'static str {
             match item.node {
@@ -120,7 +120,7 @@ fn explain_span<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
              Some(span))
         }
 
-        let (description, span) = match region {
+        let (description, span) = match *region {
             ty::ReScope(scope) => {
                 let new_string;
                 let unknown_scope = || {
@@ -405,12 +405,12 @@ fn new(sub_fr: ty::FreeRegion,
         }
 
         fn free_regions_from_same_fn<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                                     sub: Region,
-                                                     sup: Region)
+                                                     sub: &'tcx Region,
+                                                     sup: &'tcx Region)
                                                      -> Option<FreeRegionsFromSameFn> {
             debug!("free_regions_from_same_fn(sub={:?}, sup={:?})", sub, sup);
             let (scope_id, fr1, fr2) = match (sub, sup) {
-                (ReFree(fr1), ReFree(fr2)) => {
+                (&ReFree(fr1), &ReFree(fr2)) => {
                     if fr1.scope != fr2.scope {
                         return None
                     }
@@ -523,6 +523,7 @@ fn note_error_origin(&self,
     pub fn note_type_err(&self,
                          diag: &mut DiagnosticBuilder<'tcx>,
                          origin: TypeOrigin,
+                         secondary_span: Option<(Span, String)>,
                          values: Option<ValuePairs<'tcx>>,
                          terr: &TypeError<'tcx>)
     {
@@ -553,6 +554,9 @@ pub fn note_type_err(&self,
         }
 
         diag.span_label(span, &terr);
+        if let Some((sp, msg)) = secondary_span {
+            diag.span_label(sp, &msg);
+        }
 
         self.note_error_origin(diag, &origin);
         self.check_and_note_conflicting_crates(diag, terr, span);
@@ -569,7 +573,7 @@ pub fn report_and_explain_type_error(&self,
             self.tcx.sess, trace.origin.span(), E0308,
             "{}", trace.origin.as_failure_str()
         );
-        self.note_type_err(&mut diag, trace.origin, Some(trace.values), terr);
+        self.note_type_err(&mut diag, trace.origin, None, Some(trace.values), terr);
         diag
     }
 
@@ -598,7 +602,7 @@ fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
     fn report_generic_bound_failure(&self,
                                     origin: SubregionOrigin<'tcx>,
                                     bound_kind: GenericKind<'tcx>,
-                                    sub: Region)
+                                    sub: &'tcx Region)
     {
         // FIXME: it would be better to report the first error message
         // with the span of the parameter itself, rather than the span
@@ -612,7 +616,7 @@ fn report_generic_bound_failure(&self,
                 format!("the associated type `{}`", p),
         };
 
-        let mut err = match sub {
+        let mut err = match *sub {
             ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
                 // Does the required lifetime have a nice name we can print?
                 let mut err = struct_span_err!(self.tcx.sess,
@@ -663,8 +667,8 @@ fn report_generic_bound_failure(&self,
 
     fn report_concrete_failure(&self,
                                origin: SubregionOrigin<'tcx>,
-                               sub: Region,
-                               sup: Region)
+                               sub: &'tcx Region,
+                               sup: &'tcx Region)
                                 -> DiagnosticBuilder<'tcx> {
         match origin {
             infer::Subtype(trace) => {
@@ -935,9 +939,9 @@ fn report_concrete_failure(&self,
     fn report_sub_sup_conflict(&self,
                                var_origin: RegionVariableOrigin,
                                sub_origin: SubregionOrigin<'tcx>,
-                               sub_region: Region,
+                               sub_region: &'tcx Region,
                                sup_origin: SubregionOrigin<'tcx>,
-                               sup_region: Region) {
+                               sup_region: &'tcx Region) {
         let mut err = self.report_inference_failure(var_origin);
 
         self.tcx.note_and_explain_region(&mut err,
@@ -1026,7 +1030,8 @@ fn give_suggestion(&self, err: &mut DiagnosticBuilder, same_regions: &[SameRegio
                                     = node_inner.expect("expect item fn");
         let rebuilder = Rebuilder::new(self.tcx, fn_decl, generics, same_regions, &life_giver);
         let (fn_decl, generics) = rebuilder.rebuild();
-        self.give_expl_lifetime_param(err, &fn_decl, unsafety, constness, name, &generics, span);
+        self.give_expl_lifetime_param(
+            err, &fn_decl, unsafety, constness, name, &generics, span);
     }
 
     pub fn issue_32330_warnings(&self, span: Span, issue32330s: &[ty::Issue32330]) {
@@ -1293,6 +1298,7 @@ fn rebuild_generics(&self,
             lifetimes: lifetimes.into(),
             ty_params: ty_params,
             where_clause: where_clause,
+            span: generics.span,
         }
     }
 
index ecd9759c721b2f11062386e08b259c9249737f4c..f793d489cab064866ce927a07b32a8f707bf396a 100644 (file)
@@ -32,7 +32,8 @@
 
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::fold::TypeFolder;
-use std::collections::hash_map::{self, Entry};
+use util::nodemap::FnvHashMap;
+use std::collections::hash_map::Entry;
 
 use super::InferCtxt;
 use super::unify_key::ToType;
@@ -40,7 +41,7 @@
 pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
     freshen_count: u32,
-    freshen_map: hash_map::HashMap<ty::InferTy, Ty<'tcx>>,
+    freshen_map: FnvHashMap<ty::InferTy, Ty<'tcx>>,
 }
 
 impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
@@ -49,7 +50,7 @@ pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
         TypeFreshener {
             infcx: infcx,
             freshen_count: 0,
-            freshen_map: hash_map::HashMap::new(),
+            freshen_map: FnvHashMap(),
         }
     }
 
@@ -83,8 +84,8 @@ fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> {
         self.infcx.tcx
     }
 
-    fn fold_region(&mut self, r: ty::Region) -> ty::Region {
-        match r {
+    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+        match *r {
             ty::ReEarlyBound(..) |
             ty::ReLateBound(..) => {
                 // leave bound regions alone
@@ -99,7 +100,7 @@ fn fold_region(&mut self, r: ty::Region) -> ty::Region {
             ty::ReEmpty |
             ty::ReErased => {
                 // replace all free regions with 'erased
-                ty::ReErased
+                self.tcx().mk_region(ty::ReErased)
             }
         }
     }
index 5dd85a31a9a2087effd0487c3e1393c0b058107c..a5709e1880801d8942d87f909a1de2d46e301308 100644 (file)
@@ -57,7 +57,8 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         lattice::super_lattice_tys(self, a, b)
     }
 
-    fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+    fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
+               -> RelateResult<'tcx, &'tcx ty::Region> {
         debug!("{}.regions({:?}, {:?})",
                self.tag(),
                a,
index 743d6135fbb5b555a9c61b151a023626a2325dd1..90be5e935baf16a2733ec7e28f4a447d00135599 100644 (file)
@@ -164,7 +164,7 @@ pub fn higher_ranked_match<T, U>(&mut self,
                 .map(|(&skol, &(br, ref regions))| {
                     let representative =
                         regions.iter()
-                               .filter(|r| !skol_resolution_map.contains_key(r))
+                               .filter(|&&r| !skol_resolution_map.contains_key(r))
                                .cloned()
                                .next()
                                .unwrap_or_else(|| { // [1]
@@ -268,9 +268,9 @@ fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                              snapshot: &CombinedSnapshot,
                                              debruijn: ty::DebruijnIndex,
                                              new_vars: &[ty::RegionVid],
-                                             a_map: &FnvHashMap<ty::BoundRegion, ty::Region>,
-                                             r0: ty::Region)
-                                             -> ty::Region {
+                                             a_map: &FnvHashMap<ty::BoundRegion, &'tcx ty::Region>,
+                                             r0: &'tcx ty::Region)
+                                             -> &'tcx ty::Region {
             // Regions that pre-dated the LUB computation stay as they are.
             if !is_var_in_set(new_vars, r0) {
                 assert!(!r0.is_bound());
@@ -301,7 +301,7 @@ fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                     debug!("generalize_region(r0={:?}): \
                             replacing with {:?}, tainted={:?}",
                            r0, *a_br, tainted);
-                    return ty::ReLateBound(debruijn, *a_br);
+                    return infcx.tcx.mk_region(ty::ReLateBound(debruijn, *a_br));
                 }
             }
 
@@ -364,10 +364,12 @@ fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                              snapshot: &CombinedSnapshot,
                                              debruijn: ty::DebruijnIndex,
                                              new_vars: &[ty::RegionVid],
-                                             a_map: &FnvHashMap<ty::BoundRegion, ty::Region>,
+                                             a_map: &FnvHashMap<ty::BoundRegion,
+                                                                &'tcx ty::Region>,
                                              a_vars: &[ty::RegionVid],
                                              b_vars: &[ty::RegionVid],
-                                             r0: ty::Region) -> ty::Region {
+                                             r0: &'tcx ty::Region)
+                                             -> &'tcx ty::Region {
             if !is_var_in_set(new_vars, r0) {
                 assert!(!r0.is_bound());
                 return r0;
@@ -419,7 +421,7 @@ fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
 
             if a_r.is_some() && b_r.is_some() && only_new_vars {
                 // Related to exactly one bound variable from each fn:
-                return rev_lookup(span, a_map, a_r.unwrap());
+                return rev_lookup(infcx, span, a_map, a_r.unwrap());
             } else if a_r.is_none() && b_r.is_none() {
                 // Not related to bound variables from either fn:
                 assert!(!r0.is_bound());
@@ -430,13 +432,14 @@ fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
             }
         }
 
-        fn rev_lookup(span: Span,
-                      a_map: &FnvHashMap<ty::BoundRegion, ty::Region>,
-                      r: ty::Region) -> ty::Region
+        fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                      span: Span,
+                                      a_map: &FnvHashMap<ty::BoundRegion, &'tcx ty::Region>,
+                                      r: &'tcx ty::Region) -> &'tcx ty::Region
         {
             for (a_br, a_r) in a_map {
                 if *a_r == r {
-                    return ty::ReLateBound(ty::DebruijnIndex::new(1), *a_br);
+                    return infcx.tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), *a_br));
                 }
             }
             span_bug!(
@@ -445,19 +448,21 @@ fn rev_lookup(span: Span,
                 r);
         }
 
-        fn fresh_bound_variable(infcx: &InferCtxt, debruijn: ty::DebruijnIndex) -> ty::Region {
+        fn fresh_bound_variable<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+                                                debruijn: ty::DebruijnIndex)
+                                                -> &'tcx ty::Region {
             infcx.region_vars.new_bound(debruijn)
         }
     }
 }
 
 fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>,
-                           map: &FnvHashMap<ty::BoundRegion, ty::Region>)
+                           map: &FnvHashMap<ty::BoundRegion, &'tcx ty::Region>)
                            -> Vec<ty::RegionVid> {
     map.iter()
-       .map(|(_, r)| match *r {
+       .map(|(_, &r)| match *r {
            ty::ReVar(r) => { r }
-           r => {
+           _ => {
                span_bug!(
                    fields.trace.origin.span(),
                    "found non-region-vid: {:?}",
@@ -467,8 +472,8 @@ fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>,
        .collect()
 }
 
-fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool {
-    match r {
+fn is_var_in_set(new_vars: &[ty::RegionVid], r: &ty::Region) -> bool {
+    match *r {
         ty::ReVar(ref v) => new_vars.iter().any(|x| x == v),
         _ => false
     }
@@ -479,13 +484,13 @@ fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                          mut fldr: F)
                                          -> T
     where T: TypeFoldable<'tcx>,
-          F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
+          F: FnMut(&'tcx ty::Region, ty::DebruijnIndex) -> &'tcx ty::Region,
 {
     tcx.fold_regions(unbound_value, &mut false, |region, current_depth| {
         // we should only be encountering "escaping" late-bound regions here,
         // because the ones at the current level should have been replaced
         // with fresh variables
-        assert!(match region {
+        assert!(match *region {
             ty::ReLateBound(..) => false,
             _ => true
         });
@@ -497,9 +502,9 @@ fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     fn tainted_regions(&self,
                        snapshot: &CombinedSnapshot,
-                       r: ty::Region,
+                       r: &'tcx ty::Region,
                        directions: TaintDirections)
-                       -> FnvHashSet<ty::Region> {
+                       -> FnvHashSet<&'tcx ty::Region> {
         self.region_vars.tainted(&snapshot.region_vars_snapshot, r, directions)
     }
 
@@ -596,7 +601,7 @@ fn region_vars_confined_to_snapshot(&self,
     pub fn skolemize_late_bound_regions<T>(&self,
                                            binder: &ty::Binder<T>,
                                            snapshot: &CombinedSnapshot)
-                                           -> (T, SkolemizationMap)
+                                           -> (T, SkolemizationMap<'tcx>)
         where T : TypeFoldable<'tcx>
     {
         let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| {
@@ -619,7 +624,7 @@ pub fn skolemize_late_bound_regions<T>(&self,
     pub fn leak_check(&self,
                       overly_polymorphic: bool,
                       span: Span,
-                      skol_map: &SkolemizationMap,
+                      skol_map: &SkolemizationMap<'tcx>,
                       snapshot: &CombinedSnapshot)
                       -> RelateResult<'tcx, ()>
     {
@@ -673,7 +678,7 @@ pub fn leak_check(&self,
             for &tainted_region in &incoming_taints {
                 // Each skolemized should only be relatable to itself
                 // or new variables:
-                match tainted_region {
+                match *tainted_region {
                     ty::ReVar(vid) => {
                         if new_vars.contains(&vid) {
                             warnings.extend(
@@ -742,7 +747,7 @@ pub fn leak_check(&self,
     /// to the depth of the predicate, in this case 1, so that the final
     /// predicate is `for<'a> &'a int : Clone`.
     pub fn plug_leaks<T>(&self,
-                         skol_map: SkolemizationMap,
+                         skol_map: SkolemizationMap<'tcx>,
                          snapshot: &CombinedSnapshot,
                          value: &T) -> T
         where T : TypeFoldable<'tcx>
@@ -755,7 +760,7 @@ pub fn plug_leaks<T>(&self,
         // region back to the `ty::BoundRegion` that it originally
         // represented. Because `leak_check` passed, we know that
         // these taint sets are mutually disjoint.
-        let inv_skol_map: FnvHashMap<ty::Region, ty::BoundRegion> =
+        let inv_skol_map: FnvHashMap<&'tcx ty::Region, ty::BoundRegion> =
             skol_map
             .iter()
             .flat_map(|(&skol_br, &skol)| {
@@ -794,7 +799,7 @@ pub fn plug_leaks<T>(&self,
                     // (which ought not to escape the snapshot, but we
                     // don't check that) or itself
                     assert!(
-                        match r {
+                        match *r {
                             ty::ReVar(_) => true,
                             ty::ReSkolemized(_, ref br1) => br == br1,
                             _ => false,
@@ -802,7 +807,8 @@ pub fn plug_leaks<T>(&self,
                         "leak-check would have us replace {:?} with {:?}",
                         r, br);
 
-                    ty::ReLateBound(ty::DebruijnIndex::new(current_depth - 1), br.clone())
+                    self.tcx.mk_region(ty::ReLateBound(
+                        ty::DebruijnIndex::new(current_depth - 1), br.clone()))
                 }
             }
         });
@@ -826,7 +832,7 @@ pub fn plug_leaks<T>(&self,
     ///
     /// Note: popping also occurs implicitly as part of `leak_check`.
     pub fn pop_skolemized(&self,
-                          skol_map: SkolemizationMap,
+                          skol_map: SkolemizationMap<'tcx>,
                           snapshot: &CombinedSnapshot)
     {
         debug!("pop_skolemized({:?})", skol_map);
index ad1b32ffaeb320ac18159277ee07d34df3a016c7..7d352be67d32b9c2a1dd716df90b74cbbaaec689 100644 (file)
@@ -57,7 +57,8 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         lattice::super_lattice_tys(self, a, b)
     }
 
-    fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+    fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
+               -> RelateResult<'tcx, &'tcx ty::Region> {
         debug!("{}.regions({:?}, {:?})",
                self.tag(),
                a,
index 1b65b5dae074850ad2d74951d9102f73849f4921..b6114f293ad3a7e060d0d5766d9027a7447d071c 100644 (file)
@@ -136,13 +136,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // avoid reporting the same error twice.
     pub reported_trait_errors: RefCell<FnvHashSet<traits::TraitErrorKey<'tcx>>>,
 
-    // This is a temporary field used for toggling on normalization in the inference context,
-    // as we move towards the approach described here:
-    // https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293
-    // At a point sometime in the future normalization will be done by the typing context
-    // directly.
-    normalize: bool,
-
     // Sadly, the behavior of projection varies a bit depending on the
     // stage of compilation. The specifics are given in the
     // documentation for `Reveal`.
@@ -177,7 +170,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
 /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
 /// region that each late-bound region was replaced with.
-pub type SkolemizationMap = FnvHashMap<ty::BoundRegion, ty::Region>;
+pub type SkolemizationMap<'tcx> = FnvHashMap<ty::BoundRegion, &'tcx ty::Region>;
 
 /// Why did we require that the two types be related?
 ///
@@ -458,7 +451,6 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     tables: Option<RefCell<ty::Tables<'tcx>>>,
     param_env: Option<ty::ParameterEnvironment<'gcx>>,
     projection_mode: Reveal,
-    normalize: bool
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
@@ -473,19 +465,6 @@ pub fn infer_ctxt(self,
             tables: tables.map(RefCell::new),
             param_env: param_env,
             projection_mode: projection_mode,
-            normalize: false
-        }
-    }
-
-    pub fn normalizing_infer_ctxt(self, projection_mode: Reveal)
-                                  -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
-        InferCtxtBuilder {
-            global_tcx: self,
-            arenas: ty::CtxtArenas::new(),
-            tables: None,
-            param_env: None,
-            projection_mode: projection_mode,
-            normalize: false
         }
     }
 
@@ -506,7 +485,6 @@ pub fn borrowck_fake_infer_ctxt(self, param_env: ty::ParameterEnvironment<'gcx>)
             evaluation_cache: traits::EvaluationCache::new(),
             projection_cache: RefCell::new(traits::ProjectionCache::new()),
             reported_trait_errors: RefCell::new(FnvHashSet()),
-            normalize: false,
             projection_mode: Reveal::NotSpecializable,
             tainted_by_errors_flag: Cell::new(false),
             err_count_on_creation: self.sess.err_count(),
@@ -525,7 +503,6 @@ pub fn enter<F, R>(&'tcx mut self, f: F) -> R
             ref tables,
             ref mut param_env,
             projection_mode,
-            normalize
         } = *self;
         let tables = if let Some(ref tables) = *tables {
             InferTables::Local(tables)
@@ -547,7 +524,6 @@ pub fn enter<F, R>(&'tcx mut self, f: F) -> R
             selection_cache: traits::SelectionCache::new(),
             evaluation_cache: traits::EvaluationCache::new(),
             reported_trait_errors: RefCell::new(FnvHashSet()),
-            normalize: normalize,
             projection_mode: projection_mode,
             tainted_by_errors_flag: Cell::new(false),
             err_count_on_creation: tcx.sess.err_count(),
@@ -683,6 +659,15 @@ fn normalize_projections_in<T>(&self, value: &T) -> T::Lifted
         self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
     }
 
+    /// Finishes processes any obligations that remain in the
+    /// fulfillment context, and then returns the result with all type
+    /// variables removed and regions erased. Because this is intended
+    /// for use after type-check has completed, if any errors occur,
+    /// it will panic. It is used during normalization and other cases
+    /// where processing the obligations in `fulfill_cx` may cause
+    /// type inference variables that appear in `result` to be
+    /// unified, and hence we need to process those obligations to get
+    /// the complete picture of the type.
     pub fn drain_fulfillment_cx_or_panic<T>(&self,
                                             span: Span,
                                             fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
@@ -692,47 +677,28 @@ pub fn drain_fulfillment_cx_or_panic<T>(&self,
     {
         debug!("drain_fulfillment_cx_or_panic()");
 
-        let when = "resolving bounds after type-checking";
-        let v = match self.drain_fulfillment_cx(fulfill_cx, result) {
-            Ok(v) => v,
+        // In principle, we only need to do this so long as `result`
+        // contains unbound type parameters. It could be a slight
+        // optimization to stop iterating early.
+        match fulfill_cx.select_all_or_error(self) {
+            Ok(()) => { }
             Err(errors) => {
-                span_bug!(span, "Encountered errors `{:?}` {}", errors, when);
+                span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking",
+                          errors);
             }
-        };
+        }
+
+        let result = self.resolve_type_vars_if_possible(result);
+        let result = self.tcx.erase_regions(&result);
 
-        match self.tcx.lift_to_global(&v) {
-            Some(v) => v,
+        match self.tcx.lift_to_global(&result) {
+            Some(result) => result,
             None => {
-                span_bug!(span, "Uninferred types/regions in `{:?}` {}", v, when);
+                span_bug!(span, "Uninferred types/regions in `{:?}`", result);
             }
         }
     }
 
-    /// Finishes processes any obligations that remain in the fulfillment
-    /// context, and then "freshens" and returns `result`. This is
-    /// primarily used during normalization and other cases where
-    /// processing the obligations in `fulfill_cx` may cause type
-    /// inference variables that appear in `result` to be unified, and
-    /// hence we need to process those obligations to get the complete
-    /// picture of the type.
-    pub fn drain_fulfillment_cx<T>(&self,
-                                   fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
-                                   result: &T)
-                                   -> Result<T,Vec<traits::FulfillmentError<'tcx>>>
-        where T : TypeFoldable<'tcx>
-    {
-        debug!("drain_fulfillment_cx(result={:?})",
-               result);
-
-        // In principle, we only need to do this so long as `result`
-        // contains unbound type parameters. It could be a slight
-        // optimization to stop iterating early.
-        fulfill_cx.select_all_or_error(self)?;
-
-        let result = self.resolve_type_vars_if_possible(result);
-        Ok(self.tcx.erase_regions(&result))
-    }
-
     pub fn projection_mode(&self) -> Reveal {
         self.projection_mode
     }
@@ -1123,8 +1089,8 @@ pub fn sub_poly_trait_refs(&self,
 
     pub fn sub_regions(&self,
                        origin: SubregionOrigin<'tcx>,
-                       a: ty::Region,
-                       b: ty::Region) {
+                       a: &'tcx ty::Region,
+                       b: &'tcx ty::Region) {
         debug!("sub_regions({:?} <: {:?})", a, b);
         self.region_vars.make_subregion(origin, a, b);
     }
@@ -1147,7 +1113,7 @@ pub fn equality_predicate(&self,
 
     pub fn region_outlives_predicate(&self,
                                      span: Span,
-                                     predicate: &ty::PolyRegionOutlivesPredicate)
+                                     predicate: &ty::PolyRegionOutlivesPredicate<'tcx>)
         -> UnitResult<'tcx>
     {
         self.commit_if_ok(|snapshot| {
@@ -1190,8 +1156,9 @@ pub fn next_float_var_id(&self) -> FloatVid {
             .new_key(None)
     }
 
-    pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region {
-        ty::ReVar(self.region_vars.new_region_var(origin))
+    pub fn next_region_var(&self, origin: RegionVariableOrigin)
+                           -> &'tcx ty::Region {
+        self.tcx.mk_region(ty::ReVar(self.region_vars.new_region_var(origin)))
     }
 
     /// Create a region inference variable for the given
@@ -1199,7 +1166,7 @@ pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region {
     pub fn region_var_for_def(&self,
                               span: Span,
                               def: &ty::RegionParameterDef)
-                              -> ty::Region {
+                              -> &'tcx ty::Region {
         self.next_region_var(EarlyBoundRegion(span, def.name))
     }
 
@@ -1245,7 +1212,7 @@ pub fn fresh_substs_for_item(&self,
         })
     }
 
-    pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region {
+    pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> &'tcx ty::Region {
         self.region_vars.new_bound(debruijn)
     }
 
@@ -1530,7 +1497,7 @@ pub fn replace_late_bound_regions_with_fresh_var<T>(
         span: Span,
         lbrct: LateBoundRegionConversionTime,
         value: &ty::Binder<T>)
-        -> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
+        -> (T, FnvHashMap<ty::BoundRegion, &'tcx ty::Region>)
         where T : TypeFoldable<'tcx>
     {
         self.tcx.replace_late_bound_regions(
@@ -1576,8 +1543,8 @@ pub fn match_poly_projection_predicate(&self,
     pub fn verify_generic_bound(&self,
                                 origin: SubregionOrigin<'tcx>,
                                 kind: GenericKind<'tcx>,
-                                a: ty::Region,
-                                bound: VerifyBound) {
+                                a: &'tcx ty::Region,
+                                bound: VerifyBound<'tcx>) {
         debug!("verify_generic_bound({:?}, {:?} <: {:?})",
                kind,
                a,
@@ -1666,7 +1633,7 @@ pub fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<CodeExtent> {
         self.tcx.region_maps.temporary_scope(rvalue_id)
     }
 
-    pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
+    pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
         self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned()
     }
 
@@ -1701,17 +1668,7 @@ pub fn closure_type(&self,
         }
 
         let closure_ty = self.tcx.closure_type(def_id, substs);
-        if self.normalize {
-            let closure_ty = self.tcx.erase_regions(&closure_ty);
-
-            if !closure_ty.has_projection_types() {
-                return closure_ty;
-            }
-
-            self.normalize_projections_in(&closure_ty)
-        } else {
-            closure_ty
-        }
+        closure_ty
     }
 }
 
index 905ad7c0faa236c45e18c6eb5d03cc64e3663441..1c64ebc0537ae7455f774eb2a0245042199f208d 100644 (file)
@@ -123,7 +123,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>(
 struct ConstraintGraph<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     graph_name: String,
-    map: &'a FnvHashMap<Constraint, SubregionOrigin<'tcx>>,
+    map: &'a FnvHashMap<Constraint<'tcx>, SubregionOrigin<'tcx>>,
     node_ids: FnvHashMap<Node, usize>,
 }
 
@@ -135,8 +135,8 @@ enum Node {
 
 // type Edge = Constraint;
 #[derive(Clone, PartialEq, Eq, Debug, Copy)]
-enum Edge {
-    Constraint(Constraint),
+enum Edge<'tcx> {
+    Constraint(Constraint<'tcx>),
     EnclScope(CodeExtent, CodeExtent),
 }
 
@@ -177,7 +177,7 @@ fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 
 impl<'a, 'gcx, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
     type Node = Node;
-    type Edge = Edge;
+    type Edge = Edge<'tcx>;
     fn graph_id(&self) -> dot::Id {
         dot::Id::new(&*self.graph_name).unwrap()
     }
@@ -214,11 +214,11 @@ fn constraint_to_nodes(c: &Constraint) -> (Node, Node) {
         Constraint::ConstrainVarSubVar(rv_1, rv_2) =>
             (Node::RegionVid(rv_1), Node::RegionVid(rv_2)),
         Constraint::ConstrainRegSubVar(r_1, rv_2) =>
-            (Node::Region(r_1), Node::RegionVid(rv_2)),
+            (Node::Region(*r_1), Node::RegionVid(rv_2)),
         Constraint::ConstrainVarSubReg(rv_1, r_2) =>
-            (Node::RegionVid(rv_1), Node::Region(r_2)),
+            (Node::RegionVid(rv_1), Node::Region(*r_2)),
         Constraint::ConstrainRegSubReg(r_1, r_2) =>
-            (Node::Region(r_1), Node::Region(r_2)),
+            (Node::Region(*r_1), Node::Region(*r_2)),
     }
 }
 
@@ -234,7 +234,7 @@ fn edge_to_nodes(e: &Edge) -> (Node, Node) {
 
 impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
     type Node = Node;
-    type Edge = Edge;
+    type Edge = Edge<'tcx>;
     fn nodes(&self) -> dot::Nodes<Node> {
         let mut set = FnvHashSet();
         for node in self.node_ids.keys() {
@@ -243,26 +243,26 @@ fn nodes(&self) -> dot::Nodes<Node> {
         debug!("constraint graph has {} nodes", set.len());
         set.into_iter().collect()
     }
-    fn edges(&self) -> dot::Edges<Edge> {
+    fn edges(&self) -> dot::Edges<Edge<'tcx>> {
         debug!("constraint graph has {} edges", self.map.len());
         let mut v: Vec<_> = self.map.keys().map(|e| Edge::Constraint(*e)).collect();
         self.tcx.region_maps.each_encl_scope(|sub, sup| v.push(Edge::EnclScope(*sub, *sup)));
         debug!("region graph has {} edges", v.len());
         Cow::Owned(v)
     }
-    fn source(&self, edge: &Edge) -> Node {
+    fn source(&self, edge: &Edge<'tcx>) -> Node {
         let (n1, _) = edge_to_nodes(edge);
         debug!("edge {:?} has source {:?}", edge, n1);
         n1
     }
-    fn target(&self, edge: &Edge) -> Node {
+    fn target(&self, edge: &Edge<'tcx>) -> Node {
         let (_, n2) = edge_to_nodes(edge);
         debug!("edge {:?} has target {:?}", edge, n2);
         n2
     }
 }
 
-pub type ConstraintMap<'tcx> = FnvHashMap<Constraint, SubregionOrigin<'tcx>>;
+pub type ConstraintMap<'tcx> = FnvHashMap<Constraint<'tcx>, SubregionOrigin<'tcx>>;
 
 fn dump_region_constraints_to<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                               map: &ConstraintMap<'tcx>,
index d3b4afa2cee7915caa98b010a4b792d8713ea5df..b3693ae1e21ad86378859fa9fc92ce428de236f6 100644 (file)
 
 // A constraint that influences the inference process.
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
-pub enum Constraint {
+pub enum Constraint<'tcx> {
     // One region variable is subregion of another
     ConstrainVarSubVar(RegionVid, RegionVid),
 
     // Concrete region is subregion of region variable
-    ConstrainRegSubVar(Region, RegionVid),
+    ConstrainRegSubVar(&'tcx Region, RegionVid),
 
     // Region variable is subregion of concrete region. This does not
     // directly affect inference, but instead is checked after
     // inference is complete.
-    ConstrainVarSubReg(RegionVid, Region),
+    ConstrainVarSubReg(RegionVid, &'tcx Region),
 
     // A constraint where neither side is a variable. This does not
     // directly affect inference, but instead is checked after
     // inference is complete.
-    ConstrainRegSubReg(Region, Region),
+    ConstrainRegSubReg(&'tcx Region, &'tcx Region),
 }
 
 // VerifyGenericBound(T, _, R, RS): The parameter type `T` (or
@@ -66,8 +66,8 @@ pub enum Constraint {
 pub struct Verify<'tcx> {
     kind: GenericKind<'tcx>,
     origin: SubregionOrigin<'tcx>,
-    region: Region,
-    bound: VerifyBound,
+    region: &'tcx Region,
+    bound: VerifyBound<'tcx>,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq)]
@@ -80,36 +80,36 @@ pub enum GenericKind<'tcx> {
 // particular region (let's call it `'min`) meets some bound.
 // The bound is described the by the following grammar:
 #[derive(Debug)]
-pub enum VerifyBound {
+pub enum VerifyBound<'tcx> {
     // B = exists {R} --> some 'r in {R} must outlive 'min
     //
     // Put another way, the subject value is known to outlive all
     // regions in {R}, so if any of those outlives 'min, then the
     // bound is met.
-    AnyRegion(Vec<Region>),
+    AnyRegion(Vec<&'tcx Region>),
 
     // B = forall {R} --> all 'r in {R} must outlive 'min
     //
     // Put another way, the subject value is known to outlive some
     // region in {R}, so if all of those outlives 'min, then the bound
     // is met.
-    AllRegions(Vec<Region>),
+    AllRegions(Vec<&'tcx Region>),
 
     // B = exists {B} --> 'min must meet some bound b in {B}
-    AnyBound(Vec<VerifyBound>),
+    AnyBound(Vec<VerifyBound<'tcx>>),
 
     // B = forall {B} --> 'min must meet all bounds b in {B}
-    AllBounds(Vec<VerifyBound>),
+    AllBounds(Vec<VerifyBound<'tcx>>),
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub struct TwoRegions {
-    a: Region,
-    b: Region,
+pub struct TwoRegions<'tcx> {
+    a: &'tcx Region,
+    b: &'tcx Region,
 }
 
 #[derive(Copy, Clone, PartialEq)]
-pub enum UndoLogEntry {
+pub enum UndoLogEntry<'tcx> {
     /// Pushed when we start a snapshot.
     OpenSnapshot,
 
@@ -122,7 +122,7 @@ pub enum UndoLogEntry {
     AddVar(RegionVid),
 
     /// We added the given `constraint`
-    AddConstraint(Constraint),
+    AddConstraint(Constraint<'tcx>),
 
     /// We added the given `verify`
     AddVerify(usize),
@@ -131,7 +131,7 @@ pub enum UndoLogEntry {
     AddGiven(ty::FreeRegion, ty::RegionVid),
 
     /// We added a GLB/LUB "combinaton variable"
-    AddCombination(CombineMapType, TwoRegions),
+    AddCombination(CombineMapType, TwoRegions<'tcx>),
 
     /// During skolemization, we sometimes purge entries from the undo
     /// log in a kind of minisnapshot (unlike other snapshots, this
@@ -153,13 +153,13 @@ pub enum RegionResolutionError<'tcx> {
     /// `ConcreteFailure(o, a, b)`:
     ///
     /// `o` requires that `a <= b`, but this does not hold
-    ConcreteFailure(SubregionOrigin<'tcx>, Region, Region),
+    ConcreteFailure(SubregionOrigin<'tcx>, &'tcx Region, &'tcx Region),
 
     /// `GenericBoundFailure(p, s, a)
     ///
     /// The parameter/associated-type `p` must be known to outlive the lifetime
     /// `a` (but none of the known bounds are sufficient).
-    GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region),
+    GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, &'tcx Region),
 
     /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
     ///
@@ -168,9 +168,9 @@ pub enum RegionResolutionError<'tcx> {
     /// `sub_r <= sup_r` does not hold.
     SubSupConflict(RegionVariableOrigin,
                    SubregionOrigin<'tcx>,
-                   Region,
+                   &'tcx Region,
                    SubregionOrigin<'tcx>,
-                   Region),
+                   &'tcx Region),
 
     /// For subsets of `ConcreteFailure` and `SubSupConflict`, we can derive
     /// more specific errors message by suggesting to the user where they
@@ -182,7 +182,7 @@ pub enum RegionResolutionError<'tcx> {
 
 #[derive(Clone, Debug)]
 pub enum ProcessedErrorOrigin<'tcx> {
-    ConcreteFailure(SubregionOrigin<'tcx>, Region, Region),
+    ConcreteFailure(SubregionOrigin<'tcx>, &'tcx Region, &'tcx Region),
     VariableFailure(RegionVariableOrigin),
 }
 
@@ -213,7 +213,7 @@ pub fn push(&mut self, other: BoundRegion) {
     }
 }
 
-pub type CombineMap = FnvHashMap<TwoRegions, RegionVid>;
+pub type CombineMap<'tcx> = FnvHashMap<TwoRegions<'tcx>, RegionVid>;
 
 pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
@@ -222,7 +222,7 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // Constraints of the form `A <= B` introduced by the region
     // checker.  Here at least one of `A` and `B` must be a region
     // variable.
-    constraints: RefCell<FnvHashMap<Constraint, SubregionOrigin<'tcx>>>,
+    constraints: RefCell<FnvHashMap<Constraint<'tcx>, SubregionOrigin<'tcx>>>,
 
     // A "verify" is something that we need to verify after inference is
     // done, but which does not directly affect inference in any way.
@@ -250,8 +250,8 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // a bit of a hack but seems to work.
     givens: RefCell<FnvHashSet<(ty::FreeRegion, ty::RegionVid)>>,
 
-    lubs: RefCell<CombineMap>,
-    glbs: RefCell<CombineMap>,
+    lubs: RefCell<CombineMap<'tcx>>,
+    glbs: RefCell<CombineMap<'tcx>>,
     skolemization_count: Cell<u32>,
     bound_count: Cell<u32>,
 
@@ -264,12 +264,12 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // otherwise we end up adding entries for things like the lower
     // bound on a variable and so forth, which can never be rolled
     // back.
-    undo_log: RefCell<Vec<UndoLogEntry>>,
+    undo_log: RefCell<Vec<UndoLogEntry<'tcx>>>,
     unification_table: RefCell<UnificationTable<ty::RegionVid>>,
 
     // This contains the results of inference.  It begins as an empty
     // option and only acquires a value after inference is complete.
-    values: RefCell<Option<Vec<VarValue>>>,
+    values: RefCell<Option<Vec<VarValue<'tcx>>>>,
 }
 
 pub struct RegionSnapshot {
@@ -303,14 +303,14 @@ pub fn both() -> Self {
     }
 }
 
-struct TaintSet {
+struct TaintSet<'tcx> {
     directions: TaintDirections,
-    regions: FnvHashSet<ty::Region>
+    regions: FnvHashSet<&'tcx ty::Region>
 }
 
-impl TaintSet {
+impl<'a, 'gcx, 'tcx> TaintSet<'tcx> {
     fn new(directions: TaintDirections,
-           initial_region: ty::Region)
+           initial_region: &'tcx ty::Region)
            -> Self {
         let mut regions = FnvHashSet();
         regions.insert(initial_region);
@@ -318,8 +318,9 @@ fn new(directions: TaintDirections,
     }
 
     fn fixed_point(&mut self,
-                   undo_log: &[UndoLogEntry],
-                   verifys: &[Verify]) {
+                   tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                   undo_log: &[UndoLogEntry<'tcx>],
+                   verifys: &[Verify<'tcx>]) {
         let mut prev_len = 0;
         while prev_len < self.len() {
             debug!("tainted: prev_len = {:?} new_len = {:?}",
@@ -330,19 +331,21 @@ fn fixed_point(&mut self,
             for undo_entry in undo_log {
                 match undo_entry {
                     &AddConstraint(ConstrainVarSubVar(a, b)) => {
-                        self.add_edge(ReVar(a), ReVar(b));
+                        self.add_edge(tcx.mk_region(ReVar(a)),
+                                      tcx.mk_region(ReVar(b)));
                     }
                     &AddConstraint(ConstrainRegSubVar(a, b)) => {
-                        self.add_edge(a, ReVar(b));
+                        self.add_edge(a, tcx.mk_region(ReVar(b)));
                     }
                     &AddConstraint(ConstrainVarSubReg(a, b)) => {
-                        self.add_edge(ReVar(a), b);
+                        self.add_edge(tcx.mk_region(ReVar(a)), b);
                     }
                     &AddConstraint(ConstrainRegSubReg(a, b)) => {
                         self.add_edge(a, b);
                     }
                     &AddGiven(a, b) => {
-                        self.add_edge(ReFree(a), ReVar(b));
+                        self.add_edge(tcx.mk_region(ReFree(a)),
+                                      tcx.mk_region(ReVar(b)));
                     }
                     &AddVerify(i) => {
                         verifys[i].bound.for_each_region(&mut |b| {
@@ -359,7 +362,7 @@ fn fixed_point(&mut self,
         }
     }
 
-    fn into_set(self) -> FnvHashSet<ty::Region> {
+    fn into_set(self) -> FnvHashSet<&'tcx ty::Region> {
         self.regions
     }
 
@@ -368,8 +371,8 @@ fn len(&self) -> usize {
     }
 
     fn add_edge(&mut self,
-                source: ty::Region,
-                target: ty::Region) {
+                source: &'tcx ty::Region,
+                target: &'tcx ty::Region) {
         if self.directions.incoming {
             if self.regions.contains(&target) {
                 self.regions.insert(source);
@@ -450,7 +453,7 @@ pub fn rollback_to(&self, snapshot: RegionSnapshot) {
             .rollback_to(snapshot.region_snapshot);
     }
 
-    pub fn rollback_undo_entry(&self, undo_entry: UndoLogEntry) {
+    pub fn rollback_undo_entry(&self, undo_entry: UndoLogEntry<'tcx>) {
         match undo_entry {
             OpenSnapshot => {
                 panic!("Failure to observe stack discipline");
@@ -529,13 +532,14 @@ pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin {
     /// The `snapshot` argument to this function is not really used;
     /// it's just there to make it explicit which snapshot bounds the
     /// skolemized region that results. It should always be the top-most snapshot.
-    pub fn push_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot) -> Region {
+    pub fn push_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot)
+                           -> &'tcx Region {
         assert!(self.in_snapshot());
         assert!(self.undo_log.borrow()[snapshot.length] == OpenSnapshot);
 
         let sc = self.skolemization_count.get();
         self.skolemization_count.set(sc + 1);
-        ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br)
+        self.tcx.mk_region(ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br))
     }
 
     /// Removes all the edges to/from the skolemized regions that are
@@ -543,7 +547,7 @@ pub fn push_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot) ->
     /// completes to remove all trace of the skolemized regions
     /// created in that time.
     pub fn pop_skolemized(&self,
-                          skols: &FnvHashSet<ty::Region>,
+                          skols: &FnvHashSet<&'tcx ty::Region>,
                           snapshot: &RegionSnapshot) {
         debug!("pop_skolemized_regions(skols={:?})", skols);
 
@@ -566,7 +570,7 @@ pub fn pop_skolemized(&self,
                 skols.len());
         debug_assert! {
             skols.iter()
-                 .all(|k| match *k {
+                 .all(|&k| match *k {
                      ty::ReSkolemized(index, _) =>
                          index.index >= first_to_pop &&
                          index.index < last_to_pop,
@@ -597,9 +601,9 @@ pub fn pop_skolemized(&self,
         self.skolemization_count.set(snapshot.skolemization_count);
         return;
 
-        fn kill_constraint(skols: &FnvHashSet<ty::Region>,
-                           undo_entry: &UndoLogEntry)
-                           -> bool {
+        fn kill_constraint<'tcx>(skols: &FnvHashSet<&'tcx ty::Region>,
+                                 undo_entry: &UndoLogEntry<'tcx>)
+                                 -> bool {
             match undo_entry {
                 &AddConstraint(ConstrainVarSubVar(_, _)) =>
                     false,
@@ -626,7 +630,7 @@ fn kill_constraint(skols: &FnvHashSet<ty::Region>,
 
     }
 
-    pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region {
+    pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> &'tcx Region {
         // Creates a fresh bound variable for use in GLB computations.
         // See discussion of GLB computation in the large comment at
         // the top of this file for more details.
@@ -652,14 +656,14 @@ pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region {
             bug!("rollover in RegionInference new_bound()");
         }
 
-        ReLateBound(debruijn, BrFresh(sc))
+        self.tcx.mk_region(ReLateBound(debruijn, BrFresh(sc)))
     }
 
     fn values_are_none(&self) -> bool {
         self.values.borrow().is_none()
     }
 
-    fn add_constraint(&self, constraint: Constraint, origin: SubregionOrigin<'tcx>) {
+    fn add_constraint(&self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) {
         // cannot add constraints once regions are resolved
         assert!(self.values_are_none());
 
@@ -704,20 +708,26 @@ pub fn add_given(&self, sub: ty::FreeRegion, sup: ty::RegionVid) {
         }
     }
 
-    pub fn make_eqregion(&self, origin: SubregionOrigin<'tcx>, sub: Region, sup: Region) {
+    pub fn make_eqregion(&self,
+                         origin: SubregionOrigin<'tcx>,
+                         sub: &'tcx Region,
+                         sup: &'tcx Region) {
         if sub != sup {
             // Eventually, it would be nice to add direct support for
             // equating regions.
             self.make_subregion(origin.clone(), sub, sup);
             self.make_subregion(origin, sup, sub);
 
-            if let (ty::ReVar(sub), ty::ReVar(sup)) = (sub, sup) {
+            if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) {
                 self.unification_table.borrow_mut().union(sub, sup);
             }
         }
     }
 
-    pub fn make_subregion(&self, origin: SubregionOrigin<'tcx>, sub: Region, sup: Region) {
+    pub fn make_subregion(&self,
+                          origin: SubregionOrigin<'tcx>,
+                          sub: &'tcx Region,
+                          sup: &'tcx Region) {
         // cannot add constraints once regions are resolved
         assert!(self.values_are_none());
 
@@ -727,26 +737,26 @@ pub fn make_subregion(&self, origin: SubregionOrigin<'tcx>, sub: Region, sup: Re
                origin);
 
         match (sub, sup) {
-            (ReEarlyBound(..), _) |
-            (ReLateBound(..), _) |
-            (_, ReEarlyBound(..)) |
-            (_, ReLateBound(..)) => {
+            (&ReEarlyBound(..), _) |
+            (&ReLateBound(..), _) |
+            (_, &ReEarlyBound(..)) |
+            (_, &ReLateBound(..)) => {
                 span_bug!(origin.span(),
                           "cannot relate bound region: {:?} <= {:?}",
                           sub,
                           sup);
             }
-            (_, ReStatic) => {
+            (_, &ReStatic) => {
                 // all regions are subregions of static, so we can ignore this
             }
-            (ReVar(sub_id), ReVar(sup_id)) => {
+            (&ReVar(sub_id), &ReVar(sup_id)) => {
                 self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin);
             }
-            (r, ReVar(sup_id)) => {
-                self.add_constraint(ConstrainRegSubVar(r, sup_id), origin);
+            (_, &ReVar(sup_id)) => {
+                self.add_constraint(ConstrainRegSubVar(sub, sup_id), origin);
             }
-            (ReVar(sub_id), r) => {
-                self.add_constraint(ConstrainVarSubReg(sub_id, r), origin);
+            (&ReVar(sub_id), _) => {
+                self.add_constraint(ConstrainVarSubReg(sub_id, sup), origin);
             }
             _ => {
                 self.add_constraint(ConstrainRegSubReg(sub, sup), origin);
@@ -758,8 +768,8 @@ pub fn make_subregion(&self, origin: SubregionOrigin<'tcx>, sub: Region, sup: Re
     pub fn verify_generic_bound(&self,
                                 origin: SubregionOrigin<'tcx>,
                                 kind: GenericKind<'tcx>,
-                                sub: Region,
-                                bound: VerifyBound) {
+                                sub: &'tcx Region,
+                                bound: VerifyBound<'tcx>) {
         self.add_verify(Verify {
             kind: kind,
             origin: origin,
@@ -768,29 +778,43 @@ pub fn verify_generic_bound(&self,
         });
     }
 
-    pub fn lub_regions(&self, origin: SubregionOrigin<'tcx>, a: Region, b: Region) -> Region {
+    pub fn lub_regions(&self,
+                       origin: SubregionOrigin<'tcx>,
+                       a: &'tcx Region,
+                       b: &'tcx Region)
+                       -> &'tcx Region {
         // cannot add constraints once regions are resolved
         assert!(self.values_are_none());
 
         debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b);
-        if a == ty::ReStatic || b == ty::ReStatic {
-            ReStatic // nothing lives longer than static
-        } else if a == b {
-            a // LUB(a,a) = a
-        } else {
-            self.combine_vars(Lub, a, b, origin.clone(), |this, old_r, new_r| {
-                this.make_subregion(origin.clone(), old_r, new_r)
-            })
+        match (a, b) {
+            (r @ &ReStatic, _) | (_, r @ &ReStatic) => {
+                r // nothing lives longer than static
+            }
+
+            _ if a == b => {
+                a // LUB(a,a) = a
+            }
+
+            _ => {
+                self.combine_vars(Lub, a, b, origin.clone(), |this, old_r, new_r| {
+                    this.make_subregion(origin.clone(), old_r, new_r)
+                })
+            }
         }
     }
 
-    pub fn glb_regions(&self, origin: SubregionOrigin<'tcx>, a: Region, b: Region) -> Region {
+    pub fn glb_regions(&self,
+                       origin: SubregionOrigin<'tcx>,
+                       a: &'tcx Region,
+                       b: &'tcx Region)
+                       -> &'tcx Region {
         // cannot add constraints once regions are resolved
         assert!(self.values_are_none());
 
         debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b);
         match (a, b) {
-            (ReStatic, r) | (r, ReStatic) => {
+            (&ReStatic, r) | (r, &ReStatic) => {
                 r // static lives longer than everything else
             }
 
@@ -806,7 +830,7 @@ pub fn glb_regions(&self, origin: SubregionOrigin<'tcx>, a: Region, b: Region) -
         }
     }
 
-    pub fn resolve_var(&self, rid: RegionVid) -> ty::Region {
+    pub fn resolve_var(&self, rid: RegionVid) -> &'tcx ty::Region {
         match *self.values.borrow() {
             None => {
                 span_bug!((*self.var_origins.borrow())[rid.index as usize].span(),
@@ -814,18 +838,19 @@ pub fn resolve_var(&self, rid: RegionVid) -> ty::Region {
                            been computed!")
             }
             Some(ref values) => {
-                let r = lookup(values, rid);
+                let r = lookup(self.tcx, values, rid);
                 debug!("resolve_var({:?}) = {:?}", rid, r);
                 r
             }
         }
     }
 
-    pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> ty::Region {
-        ty::ReVar(self.unification_table.borrow_mut().find_value(rid).min_vid)
+    pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> &'tcx ty::Region {
+        let vid = self.unification_table.borrow_mut().find_value(rid).min_vid;
+        self.tcx.mk_region(ty::ReVar(vid))
     }
 
-    fn combine_map(&self, t: CombineMapType) -> &RefCell<CombineMap> {
+    fn combine_map(&self, t: CombineMapType) -> &RefCell<CombineMap<'tcx>> {
         match t {
             Glb => &self.glbs,
             Lub => &self.lubs,
@@ -834,26 +859,26 @@ fn combine_map(&self, t: CombineMapType) -> &RefCell<CombineMap> {
 
     pub fn combine_vars<F>(&self,
                            t: CombineMapType,
-                           a: Region,
-                           b: Region,
+                           a: &'tcx Region,
+                           b: &'tcx Region,
                            origin: SubregionOrigin<'tcx>,
                            mut relate: F)
-                           -> Region
-        where F: FnMut(&RegionVarBindings<'a, 'gcx, 'tcx>, Region, Region)
+                           -> &'tcx Region
+        where F: FnMut(&RegionVarBindings<'a, 'gcx, 'tcx>, &'tcx Region, &'tcx Region)
     {
         let vars = TwoRegions { a: a, b: b };
         if let Some(&c) = self.combine_map(t).borrow().get(&vars) {
-            return ReVar(c);
+            return self.tcx.mk_region(ReVar(c));
         }
         let c = self.new_region_var(MiscVariable(origin.span()));
         self.combine_map(t).borrow_mut().insert(vars, c);
         if self.in_snapshot() {
             self.undo_log.borrow_mut().push(AddCombination(t, vars));
         }
-        relate(self, a, ReVar(c));
-        relate(self, b, ReVar(c));
+        relate(self, a, self.tcx.mk_region(ReVar(c)));
+        relate(self, b, self.tcx.mk_region(ReVar(c)));
         debug!("combine_vars() c={:?}", c);
-        ReVar(c)
+        self.tcx.mk_region(ReVar(c))
     }
 
     pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot) -> Vec<RegionVid> {
@@ -878,9 +903,9 @@ pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot) -> Vec<RegionVi
     /// related to other regions.
     pub fn tainted(&self,
                    mark: &RegionSnapshot,
-                   r0: Region,
+                   r0: &'tcx Region,
                    directions: TaintDirections)
-                   -> FnvHashSet<ty::Region> {
+                   -> FnvHashSet<&'tcx ty::Region> {
         debug!("tainted(mark={:?}, r0={:?}, directions={:?})",
                mark, r0, directions);
 
@@ -888,7 +913,8 @@ pub fn tainted(&self,
         // edges and add any new regions we find to result_set.  This
         // is not a terribly efficient implementation.
         let mut taint_set = TaintSet::new(directions, r0);
-        taint_set.fixed_point(&self.undo_log.borrow()[mark.length..],
+        taint_set.fixed_point(self.tcx,
+                              &self.undo_log.borrow()[mark.length..],
                               &self.verifys.borrow());
         debug!("tainted: result={:?}", taint_set.regions);
         return taint_set.into_set();
@@ -910,26 +936,30 @@ pub fn resolve_regions(&self,
         errors
     }
 
-    fn lub_concrete_regions(&self, free_regions: &FreeRegionMap, a: Region, b: Region) -> Region {
+    fn lub_concrete_regions(&self,
+                            free_regions: &FreeRegionMap,
+                            a: &'tcx Region,
+                            b: &'tcx Region)
+                            -> &'tcx Region {
         match (a, b) {
-            (ReLateBound(..), _) |
-            (_, ReLateBound(..)) |
-            (ReEarlyBound(..), _) |
-            (_, ReEarlyBound(..)) |
-            (ReErased, _) |
-            (_, ReErased) => {
+            (&ReLateBound(..), _) |
+            (_, &ReLateBound(..)) |
+            (&ReEarlyBound(..), _) |
+            (_, &ReEarlyBound(..)) |
+            (&ReErased, _) |
+            (_, &ReErased) => {
                 bug!("cannot relate region: LUB({:?}, {:?})", a, b);
             }
 
-            (ReStatic, _) | (_, ReStatic) => {
-                ReStatic // nothing lives longer than static
+            (r @ &ReStatic, _) | (_, r @ &ReStatic) => {
+                r // nothing lives longer than static
             }
 
-            (ReEmpty, r) | (r, ReEmpty) => {
+            (&ReEmpty, r) | (r, &ReEmpty) => {
                 r // everything lives longer than empty
             }
 
-            (ReVar(v_id), _) | (_, ReVar(v_id)) => {
+            (&ReVar(v_id), _) | (_, &ReVar(v_id)) => {
                 span_bug!((*self.var_origins.borrow())[v_id.index as usize].span(),
                           "lub_concrete_regions invoked with non-concrete \
                            regions: {:?}, {:?}",
@@ -937,9 +967,8 @@ fn lub_concrete_regions(&self, free_regions: &FreeRegionMap, a: Region, b: Regio
                           b);
             }
 
-            (ReFree(ref fr), ReScope(s_id)) |
-            (ReScope(s_id), ReFree(ref fr)) => {
-                let f = ReFree(*fr);
+            (&ReFree(fr), &ReScope(s_id)) |
+            (&ReScope(s_id), &ReFree(fr)) => {
                 // A "free" region can be interpreted as "some region
                 // at least as big as the block fr.scope_id".  So, we can
                 // reasonably compare free regions and scopes:
@@ -949,33 +978,34 @@ fn lub_concrete_regions(&self, free_regions: &FreeRegionMap, a: Region, b: Regio
                     // if the free region's scope `fr.scope_id` is bigger than
                     // the scope region `s_id`, then the LUB is the free
                     // region itself:
-                    f
+                    self.tcx.mk_region(ReFree(fr))
                 } else {
                     // otherwise, we don't know what the free region is,
                     // so we must conservatively say the LUB is static:
-                    ReStatic
+                    self.tcx.mk_region(ReStatic)
                 }
             }
 
-            (ReScope(a_id), ReScope(b_id)) => {
+            (&ReScope(a_id), &ReScope(b_id)) => {
                 // The region corresponding to an outer block is a
                 // subtype of the region corresponding to an inner
                 // block.
-                ReScope(self.tcx.region_maps.nearest_common_ancestor(a_id, b_id))
+                self.tcx.mk_region(ReScope(
+                    self.tcx.region_maps.nearest_common_ancestor(a_id, b_id)))
             }
 
-            (ReFree(a_fr), ReFree(b_fr)) => {
-                free_regions.lub_free_regions(a_fr, b_fr)
+            (&ReFree(a_fr), &ReFree(b_fr)) => {
+                self.tcx.mk_region(free_regions.lub_free_regions(a_fr, b_fr))
             }
 
             // For these types, we cannot define any additional
             // relationship:
-            (ReSkolemized(..), _) |
-            (_, ReSkolemized(..)) => {
+            (&ReSkolemized(..), _) |
+            (_, &ReSkolemized(..)) => {
                 if a == b {
                     a
                 } else {
-                    ReStatic
+                    self.tcx.mk_region(ReStatic)
                 }
             }
         }
@@ -985,24 +1015,24 @@ fn lub_concrete_regions(&self, free_regions: &FreeRegionMap, a: Region, b: Regio
 // ______________________________________________________________________
 
 #[derive(Copy, Clone, Debug)]
-pub enum VarValue {
-    Value(Region),
+pub enum VarValue<'tcx> {
+    Value(&'tcx Region),
     ErrorValue,
 }
 
 struct RegionAndOrigin<'tcx> {
-    region: Region,
+    region: &'tcx Region,
     origin: SubregionOrigin<'tcx>,
 }
 
-type RegionGraph = graph::Graph<(), Constraint>;
+type RegionGraph<'tcx> = graph::Graph<(), Constraint<'tcx>>;
 
 impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
     fn infer_variable_values(&self,
                              free_regions: &FreeRegionMap,
                              errors: &mut Vec<RegionResolutionError<'tcx>>,
                              subject: ast::NodeId)
-                             -> Vec<VarValue> {
+                             -> Vec<VarValue<'tcx>> {
         let mut var_data = self.construct_var_data();
 
         // Dorky hack to cause `dump_constraints` to only get called
@@ -1020,9 +1050,9 @@ fn infer_variable_values(&self,
         var_data
     }
 
-    fn construct_var_data(&self) -> Vec<VarValue> {
+    fn construct_var_data(&self) -> Vec<VarValue<'tcx>> {
         (0..self.num_vars() as usize)
-            .map(|_| Value(ty::ReEmpty))
+            .map(|_| Value(self.tcx.mk_region(ty::ReEmpty)))
             .collect()
     }
 
@@ -1059,7 +1089,7 @@ fn expand_givens(&self, graph: &RegionGraph) {
         }
     }
 
-    fn expansion(&self, free_regions: &FreeRegionMap, var_values: &mut [VarValue]) {
+    fn expansion(&self, free_regions: &FreeRegionMap, var_values: &mut [VarValue<'tcx>]) {
         self.iterate_until_fixed_point("Expansion", |constraint, origin| {
             debug!("expansion: constraint={:?} origin={:?}",
                    constraint, origin);
@@ -1089,9 +1119,9 @@ fn expansion(&self, free_regions: &FreeRegionMap, var_values: &mut [VarValue]) {
 
     fn expand_node(&self,
                    free_regions: &FreeRegionMap,
-                   a_region: Region,
+                   a_region: &'tcx Region,
                    b_vid: RegionVid,
-                   b_data: &mut VarValue)
+                   b_data: &mut VarValue<'tcx>)
                    -> bool {
         debug!("expand_node({:?}, {:?} == {:?})",
                a_region,
@@ -1099,7 +1129,7 @@ fn expand_node(&self,
                b_data);
 
         // Check if this relationship is implied by a given.
-        match a_region {
+        match *a_region {
             ty::ReFree(fr) => {
                 if self.givens.borrow().contains(&(fr, b_vid)) {
                     debug!("given");
@@ -1136,7 +1166,7 @@ fn expand_node(&self,
     /// and check that they are satisfied.
     fn collect_errors(&self,
                       free_regions: &FreeRegionMap,
-                      var_data: &mut Vec<VarValue>,
+                      var_data: &mut Vec<VarValue<'tcx>>,
                       errors: &mut Vec<RegionResolutionError<'tcx>>) {
         let constraints = self.constraints.borrow();
         for (constraint, origin) in constraints.iter() {
@@ -1192,7 +1222,7 @@ fn collect_errors(&self,
 
         for verify in self.verifys.borrow().iter() {
             debug!("collect_errors: verify={:?}", verify);
-            let sub = normalize(var_data, verify.region);
+            let sub = normalize(self.tcx, var_data, verify.region);
             if verify.bound.is_met(self.tcx, free_regions, var_data, sub) {
                 continue;
             }
@@ -1213,8 +1243,8 @@ fn collect_errors(&self,
     /// and create a `RegionResolutionError` for each of them.
     fn collect_var_errors(&self,
                           free_regions: &FreeRegionMap,
-                          var_data: &[VarValue],
-                          graph: &RegionGraph,
+                          var_data: &[VarValue<'tcx>],
+                          graph: &RegionGraph<'tcx>,
                           errors: &mut Vec<RegionResolutionError<'tcx>>) {
         debug!("collect_var_errors");
 
@@ -1271,7 +1301,7 @@ fn collect_var_errors(&self,
         }
     }
 
-    fn construct_graph(&self) -> RegionGraph {
+    fn construct_graph(&self) -> RegionGraph<'tcx> {
         let num_vars = self.num_vars();
 
         let constraints = self.constraints.borrow();
@@ -1315,7 +1345,7 @@ fn construct_graph(&self) -> RegionGraph {
 
     fn collect_error_for_expanding_node(&self,
                                         free_regions: &FreeRegionMap,
-                                        graph: &RegionGraph,
+                                        graph: &RegionGraph<'tcx>,
                                         dup_vec: &mut [u32],
                                         node_idx: RegionVid,
                                         errors: &mut Vec<RegionResolutionError<'tcx>>) {
@@ -1339,9 +1369,9 @@ fn collect_error_for_expanding_node(&self,
         // the user will more likely get a specific suggestion.
         fn free_regions_first(a: &RegionAndOrigin, b: &RegionAndOrigin) -> Ordering {
             match (a.region, b.region) {
-                (ReFree(..), ReFree(..)) => Equal,
-                (ReFree(..), _) => Less,
-                (_, ReFree(..)) => Greater,
+                (&ReFree(..), &ReFree(..)) => Equal,
+                (&ReFree(..), _) => Less,
+                (_, &ReFree(..)) => Greater,
                 (_, _) => Equal,
             }
         }
@@ -1378,7 +1408,7 @@ fn free_regions_first(a: &RegionAndOrigin, b: &RegionAndOrigin) -> Ordering {
     }
 
     fn collect_concrete_regions(&self,
-                                graph: &RegionGraph,
+                                graph: &RegionGraph<'tcx>,
                                 orig_node_idx: RegionVid,
                                 dir: Direction,
                                 dup_vec: &mut [u32])
@@ -1423,7 +1453,7 @@ struct WalkState<'tcx> {
 
         fn process_edges<'a, 'gcx, 'tcx>(this: &RegionVarBindings<'a, 'gcx, 'tcx>,
                                          state: &mut WalkState<'tcx>,
-                                         graph: &RegionGraph,
+                                         graph: &RegionGraph<'tcx>,
                                          source_vid: RegionVid,
                                          dir: Direction) {
             debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
@@ -1460,7 +1490,7 @@ fn process_edges<'a, 'gcx, 'tcx>(this: &RegionVarBindings<'a, 'gcx, 'tcx>,
     }
 
     fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F)
-        where F: FnMut(&Constraint, &SubregionOrigin<'tcx>) -> bool
+        where F: FnMut(&Constraint<'tcx>, &SubregionOrigin<'tcx>) -> bool
     {
         let mut iteration = 0;
         let mut changed = true;
@@ -1481,17 +1511,23 @@ fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F)
 
 }
 
-fn normalize(values: &Vec<VarValue>, r: ty::Region) -> ty::Region {
-    match r {
-        ty::ReVar(rid) => lookup(values, rid),
+fn normalize<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                             values: &Vec<VarValue<'tcx>>,
+                             r: &'tcx ty::Region)
+                             -> &'tcx ty::Region {
+    match *r {
+        ty::ReVar(rid) => lookup(tcx, values, rid),
         _ => r,
     }
 }
 
-fn lookup(values: &Vec<VarValue>, rid: ty::RegionVid) -> ty::Region {
+fn lookup<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                          values: &Vec<VarValue<'tcx>>,
+                          rid: ty::RegionVid)
+                          -> &'tcx ty::Region {
     match values[rid.index as usize] {
         Value(r) => r,
-        ErrorValue => ReStatic, // Previously reported error.
+        ErrorValue => tcx.mk_region(ReStatic), // Previously reported error.
     }
 }
 
@@ -1535,8 +1571,8 @@ pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx> VerifyBound {
-    fn for_each_region(&self, f: &mut FnMut(ty::Region)) {
+impl<'a, 'gcx, 'tcx> VerifyBound<'tcx> {
+    fn for_each_region(&self, f: &mut FnMut(&'tcx ty::Region)) {
         match self {
             &VerifyBound::AnyRegion(ref rs) |
             &VerifyBound::AllRegions(ref rs) => for &r in rs {
@@ -1552,7 +1588,7 @@ fn for_each_region(&self, f: &mut FnMut(ty::Region)) {
 
     pub fn must_hold(&self) -> bool {
         match self {
-            &VerifyBound::AnyRegion(ref bs) => bs.contains(&ty::ReStatic),
+            &VerifyBound::AnyRegion(ref bs) => bs.contains(&&ty::ReStatic),
             &VerifyBound::AllRegions(ref bs) => bs.is_empty(),
             &VerifyBound::AnyBound(ref bs) => bs.iter().any(|b| b.must_hold()),
             &VerifyBound::AllBounds(ref bs) => bs.iter().all(|b| b.must_hold()),
@@ -1562,13 +1598,13 @@ pub fn must_hold(&self) -> bool {
     pub fn cannot_hold(&self) -> bool {
         match self {
             &VerifyBound::AnyRegion(ref bs) => bs.is_empty(),
-            &VerifyBound::AllRegions(ref bs) => bs.contains(&ty::ReEmpty),
+            &VerifyBound::AllRegions(ref bs) => bs.contains(&&ty::ReEmpty),
             &VerifyBound::AnyBound(ref bs) => bs.iter().all(|b| b.cannot_hold()),
             &VerifyBound::AllBounds(ref bs) => bs.iter().any(|b| b.cannot_hold()),
         }
     }
 
-    pub fn or(self, vb: VerifyBound) -> VerifyBound {
+    pub fn or(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> {
         if self.must_hold() || vb.cannot_hold() {
             self
         } else if self.cannot_hold() || vb.must_hold() {
@@ -1578,7 +1614,7 @@ pub fn or(self, vb: VerifyBound) -> VerifyBound {
         }
     }
 
-    pub fn and(self, vb: VerifyBound) -> VerifyBound {
+    pub fn and(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> {
         if self.must_hold() && vb.must_hold() {
             self
         } else if self.cannot_hold() && vb.cannot_hold() {
@@ -1590,18 +1626,18 @@ pub fn and(self, vb: VerifyBound) -> VerifyBound {
 
     fn is_met(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
               free_regions: &FreeRegionMap,
-              var_values: &Vec<VarValue>,
-              min: ty::Region)
+              var_values: &Vec<VarValue<'tcx>>,
+              min: &'tcx ty::Region)
               -> bool {
         match self {
             &VerifyBound::AnyRegion(ref rs) =>
                 rs.iter()
-                  .map(|&r| normalize(var_values, r))
+                  .map(|&r| normalize(tcx, var_values, r))
                   .any(|r| free_regions.is_subregion_of(tcx, min, r)),
 
             &VerifyBound::AllRegions(ref rs) =>
                 rs.iter()
-                  .map(|&r| normalize(var_values, r))
+                  .map(|&r| normalize(tcx, var_values, r))
                   .all(|r| free_regions.is_subregion_of(tcx, min, r)),
 
             &VerifyBound::AnyBound(ref bs) =>
index 5f550b427e21aed275e47d59357bbfdb9de613d8..357a03a2ffd7c214d4919169e76a363620fd2f46 100644 (file)
@@ -72,10 +72,10 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
 
-    fn fold_region(&mut self, r: ty::Region) -> ty::Region {
-        match r {
-          ty::ReVar(rid) => self.infcx.region_vars.opportunistic_resolve_var(rid),
-          _ => r,
+    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+        match *r {
+            ty::ReVar(rid) => self.infcx.region_vars.opportunistic_resolve_var(rid),
+            _ => r,
         }
     }
 }
@@ -138,10 +138,10 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
 
-    fn fold_region(&mut self, r: ty::Region) -> ty::Region {
-        match r {
-          ty::ReVar(rid) => self.infcx.region_vars.resolve_var(rid),
-          _ => r,
+    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+        match *r {
+            ty::ReVar(rid) => self.infcx.region_vars.resolve_var(rid),
+            _ => r,
         }
     }
 }
index 2f7f5254727db15d1f245be227498b046bc307fc..159de2faced574e5fb9817f6e03223768fc1233d 100644 (file)
@@ -107,7 +107,8 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         }
     }
 
-    fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+    fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
+               -> RelateResult<'tcx, &'tcx ty::Region> {
         debug!("{}.regions({:?}, {:?}) self.cause={:?}",
                self.tag(), a, b, self.fields.cause);
         // FIXME -- we have more fine-grained information available
index 48ea953cc1e8b05a137d32659ab11caa20bde3a8..1e4b2e9116fd27f67e5b344e947e683e9700c568 100644 (file)
@@ -27,6 +27,7 @@
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(collections)]
+#![feature(conservative_impl_trait)]
 #![feature(const_fn)]
 #![feature(core_intrinsics)]
 #![feature(enumset)]
index f0ddcdc07e1206beb5746685b0f7897d833cbb83..ed94e5fe377c495165a21de8a6949c4458fe4b29 100644 (file)
 
 declare_lint! {
     pub TRANSMUTE_FROM_FN_ITEM_TYPES,
-    Warn,
+    Deny,
     "transmute from function item type to pointer-sized type erroneously allowed"
 }
 
     "detects super or self keywords at the beginning of global path"
 }
 
-declare_lint! {
-    pub UNSIZED_IN_TUPLE,
-    Warn,
-    "unsized types in the interior of a tuple were erroneously allowed"
-}
-
-declare_lint! {
-    pub OBJECT_UNSAFE_FRAGMENT,
-    Warn,
-    "object-unsafe non-principal fragments in object types were erroneously allowed"
-}
-
 declare_lint! {
     pub LIFETIME_UNDERSCORE,
     Warn,
@@ -239,8 +227,6 @@ fn get_lints(&self) -> LintArray {
             OVERLAPPING_INHERENT_IMPLS,
             RENAMED_AND_REMOVED_LINTS,
             SUPER_OR_SELF_IN_GLOBAL_PATH,
-            UNSIZED_IN_TUPLE,
-            OBJECT_UNSAFE_FRAGMENT,
             HR_LIFETIME_IN_ASSOC_TYPE,
             LIFETIME_UNDERSCORE
         )
index daac315e14def73aed895377000e610242272a72..81d3d440b566f8f3edccac5da6a20d3a65b1931a 100644 (file)
@@ -38,7 +38,7 @@
 use std::cmp;
 use std::default::Default as StdDefault;
 use std::mem;
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::attr;
 use syntax::parse::token::InternedString;
 use syntax::ast;
 use syntax_pos::Span;
@@ -372,12 +372,10 @@ pub fn gather_attr(attr: &ast::Attribute)
         return out;
     };
 
-    for meta in metas {
-        out.push(if meta.is_word() {
-            Ok((meta.name().clone(), level, meta.span))
-        } else {
-            Err(meta.span)
-        });
+    for li in metas {
+        out.push(li.word().map_or(Err(li.span), |word| {
+            Ok((word.name().clone(), level, word.span))
+        }));
     }
 
     out
@@ -601,16 +599,17 @@ fn with_lint_attrs<F>(&mut self,
             for (lint_id, level, span) in v {
                 let (now, now_source) = self.lints().get_level_source(lint_id);
                 if now == Forbid && level != Forbid {
-                    let lint_name = lint_id.as_str();
+                    let lint_name = lint_id.to_string();
                     let mut diag_builder = struct_span_err!(self.sess(), span, E0453,
                                                             "{}({}) overruled by outer forbid({})",
                                                             level.as_str(), lint_name,
                                                             lint_name);
+                    diag_builder.span_label(span, &format!("overruled by previous forbid"));
                     match now_source {
                         LintSource::Default => &mut diag_builder,
                         LintSource::Node(forbid_source_span) => {
-                            diag_builder.span_note(forbid_source_span,
-                                                   "`forbid` lint level set here")
+                            diag_builder.span_label(forbid_source_span,
+                                                    &format!("`forbid` level set here"))
                         },
                         LintSource::CommandLine => {
                             diag_builder.note("`forbid` lint level was set on command line")
@@ -1216,7 +1215,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         for &(lint, span, ref msg) in v {
             span_bug!(span,
                       "unprocessed lint {} at {}: {}",
-                      lint.as_str(), tcx.map.node_to_string(*id), *msg)
+                      lint.to_string(), tcx.map.node_to_string(*id), *msg)
         }
     }
 
@@ -1252,7 +1251,7 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
     // in the iteration code.
     for (_, v) in sess.lints.borrow().iter() {
         for &(lint, span, ref msg) in v {
-            span_bug!(span, "unprocessed lint {}: {}", lint.as_str(), *msg)
+            span_bug!(span, "unprocessed lint {}: {}", lint.to_string(), *msg)
         }
     }
 }
index f34b14224f7797f0ad798cd4e045e294fdb5104c..0938086b000c037b1c22ac592ceb12deb8390c37 100644 (file)
@@ -263,7 +263,7 @@ pub fn of(lint: &'static Lint) -> LintId {
     }
 
     /// Get the name of the lint.
-    pub fn as_str(&self) -> String {
+    pub fn to_string(&self) -> String {
         self.lint.name_lower()
     }
 }
index abb22783ddc84a72badc40212a5c69e24f8dd16d..b33bc520fe21622407561beccea2dab9e662dc30 100644 (file)
@@ -96,8 +96,7 @@ pub enum DefLike {
 pub enum InlinedItem {
     Item(DefId /* def-id in source crate */, P<hir::Item>),
     TraitItem(DefId /* impl id */, P<hir::TraitItem>),
-    ImplItem(DefId /* impl id */, P<hir::ImplItem>),
-    Foreign(DefId /* extern item */, P<hir::ForeignItem>),
+    ImplItem(DefId /* impl id */, P<hir::ImplItem>)
 }
 
 /// A borrowed version of `hir::InlinedItem`.
@@ -105,8 +104,7 @@ pub enum InlinedItem {
 pub enum InlinedItemRef<'a> {
     Item(DefId, &'a hir::Item),
     TraitItem(DefId, &'a hir::TraitItem),
-    ImplItem(DefId, &'a hir::ImplItem),
-    Foreign(DefId, &'a hir::ForeignItem)
+    ImplItem(DefId, &'a hir::ImplItem)
 }
 
 /// Item definitions in the currently-compiled crate would have the CrateNum
@@ -151,7 +149,7 @@ pub trait CrateStore<'tcx> {
     fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind;
     fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
                       -> ty::ClosureTy<'tcx>;
-    fn item_variances(&self, def: DefId) -> ty::ItemVariances;
+    fn item_variances(&self, def: DefId) -> Vec<ty::Variance>;
     fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr>;
     fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                      -> Ty<'tcx>;
@@ -200,7 +198,6 @@ fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
     fn is_default_impl(&self, impl_did: DefId) -> bool;
     fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool;
     fn is_foreign_item(&self, did: DefId) -> bool;
-    fn is_static_method(&self, did: DefId) -> bool;
     fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool;
     fn is_typedef(&self, did: DefId) -> bool;
 
@@ -286,7 +283,6 @@ pub fn visit<'ast,V>(&'ast self, visitor: &mut V)
     {
         match *self {
             InlinedItem::Item(_, ref i) => visitor.visit_item(&i),
-            InlinedItem::Foreign(_, ref i) => visitor.visit_foreign_item(&i),
             InlinedItem::TraitItem(_, ref ti) => visitor.visit_trait_item(ti),
             InlinedItem::ImplItem(_, ref ii) => visitor.visit_impl_item(ii),
         }
@@ -332,7 +328,7 @@ fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") }
     fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind  { bug!("closure_kind") }
     fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
                       -> ty::ClosureTy<'tcx>  { bug!("closure_ty") }
-    fn item_variances(&self, def: DefId) -> ty::ItemVariances { bug!("item_variances") }
+    fn item_variances(&self, def: DefId) -> Vec<ty::Variance> { bug!("item_variances") }
     fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr> { bug!("repr_attrs") }
     fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                      -> Ty<'tcx> { bug!("item_type") }
@@ -394,7 +390,6 @@ fn is_default_impl(&self, impl_did: DefId) -> bool { bug!("is_default_impl") }
     fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool
         { bug!("is_extern_item") }
     fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") }
-    fn is_static_method(&self, did: DefId) -> bool { bug!("is_static_method") }
     fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { false }
     fn is_typedef(&self, did: DefId) -> bool { bug!("is_typedef") }
 
index 2a8594c59a83764c727862b7f3ff38684154d7e4..824383b11afcb5a4a0c560a42ab59445ccd3dbd0 100644 (file)
@@ -22,8 +22,8 @@
 use hir::def::Def;
 use hir::def_id::{DefId};
 use lint;
+use util::nodemap::FnvHashSet;
 
-use std::collections::HashSet;
 use syntax::{ast, codemap};
 use syntax::attr;
 use syntax_pos;
@@ -48,7 +48,7 @@ fn should_explore<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 struct MarkSymbolVisitor<'a, 'tcx: 'a> {
     worklist: Vec<ast::NodeId>,
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    live_symbols: Box<HashSet<ast::NodeId>>,
+    live_symbols: Box<FnvHashSet<ast::NodeId>>,
     struct_has_extern_repr: bool,
     ignore_non_const_paths: bool,
     inherited_pub_visibility: bool,
@@ -61,7 +61,7 @@ fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         MarkSymbolVisitor {
             worklist: worklist,
             tcx: tcx,
-            live_symbols: box HashSet::new(),
+            live_symbols: box FnvHashSet(),
             struct_has_extern_repr: false,
             ignore_non_const_paths: false,
             inherited_pub_visibility: false,
@@ -95,7 +95,7 @@ fn lookup_and_handle_definition(&mut self, id: ast::NodeId) {
             Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_)
             if self.tcx.trait_of_item(def.def_id()).is_some() => {
                 if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) {
-                    match substs.substs.types[0].sty {
+                    match substs.substs.type_at(0).sty {
                         TyEnum(tyid, _) | TyStruct(tyid, _) => {
                             self.check_def_id(tyid.did)
                         }
@@ -162,7 +162,7 @@ fn handle_field_pattern_match(&mut self, lhs: &hir::Pat,
     }
 
     fn mark_live_symbols(&mut self) {
-        let mut scanned = HashSet::new();
+        let mut scanned = FnvHashSet();
         while !self.worklist.is_empty() {
             let id = self.worklist.pop().unwrap();
             if scanned.contains(&id) {
@@ -294,7 +294,7 @@ fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) {
     }
 
     fn visit_path_list_item(&mut self, path: &hir::Path, item: &hir::PathListItem) {
-        self.lookup_and_handle_definition(item.node.id());
+        self.lookup_and_handle_definition(item.node.id);
         intravisit::walk_path_list_item(self, path, item);
     }
 }
@@ -395,7 +395,7 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                        access_levels: &privacy::AccessLevels,
                        krate: &hir::Crate)
-                       -> Box<HashSet<ast::NodeId>> {
+                       -> Box<FnvHashSet<ast::NodeId>> {
     let worklist = create_and_seed_worklist(tcx, access_levels, krate);
     let mut symbol_visitor = MarkSymbolVisitor::new(tcx, worklist);
     symbol_visitor.mark_live_symbols();
@@ -413,7 +413,7 @@ fn get_struct_ctor_id(item: &hir::Item) -> Option<ast::NodeId> {
 
 struct DeadVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    live_symbols: Box<HashSet<ast::NodeId>>,
+    live_symbols: Box<FnvHashSet<ast::NodeId>>,
 }
 
 impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
index 3ca6cf039979705cc09477902e3912c270daf7d2..250ad80f5af6c98b738cf28c3aa0f3da7c6562c9 100644 (file)
@@ -66,7 +66,7 @@ fn require_unsafe(&mut self, span: Span, description: &str) {
                 struct_span_err!(
                     self.tcx.sess, span, E0133,
                     "{} requires unsafe function or block", description)
-                    .span_label(span, &format!("unsafe call requires unsafe function or block"))
+                    .span_label(span, &description)
                     .emit();
             }
             UnsafeBlock(block_id) => {
index 87463055a276a76748f939b8d59e2aaa51c6f50f..798702e6fd6571b5f70269576e641c335dbc4e1c 100644 (file)
@@ -76,7 +76,7 @@ fn borrow(&mut self,
               borrow_id: ast::NodeId,
               borrow_span: Span,
               cmt: mc::cmt<'tcx>,
-              loan_region: ty::Region,
+              loan_region: &'tcx ty::Region,
               bk: ty::BorrowKind,
               loan_cause: LoanCause);
 
@@ -301,11 +301,11 @@ fn walk_arg_patterns(&mut self,
         for arg in &decl.inputs {
             let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id));
 
-            let fn_body_scope = self.tcx().region_maps.node_extent(body.id);
+            let fn_body_scope_r = self.tcx().node_scope_region(body.id);
             let arg_cmt = self.mc.cat_rvalue(
                 arg.id,
                 arg.pat.span,
-                ty::ReScope(fn_body_scope), // Args live only as long as the fn body.
+                fn_body_scope_r, // Args live only as long as the fn body.
                 arg_ty);
 
             self.walk_irrefutable_pat(arg_cmt, &arg.pat);
@@ -352,7 +352,7 @@ fn mutate_expr(&mut self,
 
     fn borrow_expr(&mut self,
                    expr: &hir::Expr,
-                   r: ty::Region,
+                   r: &'tcx ty::Region,
                    bk: ty::BorrowKind,
                    cause: LoanCause) {
         debug!("borrow_expr(expr={:?}, r={:?}, bk={:?})",
@@ -431,7 +431,8 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
 
             hir::ExprMatch(ref discr, ref arms, _) => {
                 let discr_cmt = return_if_err!(self.mc.cat_expr(&discr));
-                self.borrow_expr(&discr, ty::ReEmpty, ty::ImmBorrow, MatchDiscriminant);
+                let r = self.tcx().mk_region(ty::ReEmpty);
+                self.borrow_expr(&discr, r, ty::ImmBorrow, MatchDiscriminant);
 
                 // treatment of the discriminant is handled while walking the arms.
                 for arm in arms {
@@ -449,7 +450,7 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
                 // make sure that the thing we are pointing out stays valid
                 // for the lifetime `scope_r` of the resulting ptr:
                 let expr_ty = return_if_err!(self.mc.infcx.node_ty(expr.id));
-                if let ty::TyRef(&r, _) = expr_ty.sty {
+                if let ty::TyRef(r, _) = expr_ty.sty {
                     let bk = ty::BorrowKind::from_mutbl(m);
                     self.borrow_expr(&base, r, bk, AddrOf);
                 }
@@ -557,7 +558,6 @@ fn walk_callee(&mut self, call: &hir::Expr, callee: &hir::Expr) {
         let callee_ty = return_if_err!(self.mc.infcx.expr_ty_adjusted(callee));
         debug!("walk_callee: callee={:?} callee_ty={:?}",
                callee, callee_ty);
-        let call_scope = self.tcx().region_maps.node_extent(call.id);
         match callee_ty.sty {
             ty::TyFnDef(..) | ty::TyFnPtr(_) => {
                 self.consume_expr(callee);
@@ -578,14 +578,16 @@ fn walk_callee(&mut self, call: &hir::Expr, callee: &hir::Expr) {
                     };
                 match overloaded_call_type {
                     FnMutOverloadedCall => {
+                        let call_scope_r = self.tcx().node_scope_region(call.id);
                         self.borrow_expr(callee,
-                                         ty::ReScope(call_scope),
+                                         call_scope_r,
                                          ty::MutBorrow,
                                          ClosureInvocation);
                     }
                     FnOverloadedCall => {
+                        let call_scope_r = self.tcx().node_scope_region(call.id);
                         self.borrow_expr(callee,
-                                         ty::ReScope(call_scope),
+                                         call_scope_r,
                                          ty::ImmBorrow,
                                          ClosureInvocation);
                     }
@@ -761,7 +763,7 @@ fn walk_autoderefs(&mut self,
                 };
                 let bk = ty::BorrowKind::from_mutbl(m);
                 self.delegate.borrow(expr.id, expr.span, cmt,
-                                     *r, bk, AutoRef);
+                                     r, bk, AutoRef);
             }
         }
     }
@@ -822,7 +824,7 @@ fn walk_autoref(&mut self,
                 self.delegate.borrow(expr.id,
                                      expr.span,
                                      cmt_base,
-                                     *r,
+                                     r,
                                      ty::BorrowKind::from_mutbl(m),
                                      AutoRef);
             }
@@ -835,7 +837,7 @@ fn walk_autoref(&mut self,
                 // Converting from a &T to *T (or &mut T to *mut T) is
                 // treated as borrowing it for the enclosing temporary
                 // scope.
-                let r = ty::ReScope(self.tcx().region_maps.node_extent(expr.id));
+                let r = self.tcx().node_scope_region(expr.id);
 
                 self.delegate.borrow(expr.id,
                                      expr.span,
@@ -890,7 +892,7 @@ fn walk_overloaded_operator(&mut self,
         // methods are implicitly autoref'd which sadly does not use
         // adjustments, so we must hardcode the borrow here.
 
-        let r = ty::ReScope(self.tcx().region_maps.node_extent(expr.id));
+        let r = self.tcx().node_scope_region(expr.id);
         let bk = ty::ImmBorrow;
 
         for &arg in &rhs {
@@ -979,7 +981,7 @@ fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: Mat
                 // It is also a borrow or copy/move of the value being matched.
                 match bmode {
                     hir::BindByRef(m) => {
-                        if let ty::TyRef(&r, _) = pat_ty.sty {
+                        if let ty::TyRef(r, _) = pat_ty.sty {
                             let bk = ty::BorrowKind::from_mutbl(m);
                             delegate.borrow(pat.id, pat.span, cmt_pat, r, bk, RefBinding);
                         }
index e4ce89767139a23157a2f29543d288f4ae0dd724..bd35bfc9829a5c08541a83d35585a706f7f873ce 100644 (file)
@@ -37,7 +37,7 @@ pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self,
         for implied_bound in implied_bounds {
             debug!("implied bound: {:?}", implied_bound);
             match *implied_bound {
-                ImpliedBound::RegionSubRegion(ty::ReFree(free_a), ty::ReFree(free_b)) => {
+                ImpliedBound::RegionSubRegion(&ty::ReFree(free_a), &ty::ReFree(free_b)) => {
                     self.relate_free_regions(free_a, free_b);
                 }
                 ImpliedBound::RegionSubRegion(..) |
@@ -55,7 +55,6 @@ pub fn relate_free_regions_from_predicates(&mut self,
             match *predicate {
                 ty::Predicate::Projection(..) |
                 ty::Predicate::Trait(..) |
-                ty::Predicate::Rfc1592(..) |
                 ty::Predicate::Equate(..) |
                 ty::Predicate::WellFormed(..) |
                 ty::Predicate::ObjectSafe(..) |
@@ -65,9 +64,9 @@ pub fn relate_free_regions_from_predicates(&mut self,
                 }
                 ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
                     match (r_a, r_b) {
-                        (ty::ReStatic, ty::ReFree(_)) => {},
-                        (ty::ReFree(fr_a), ty::ReStatic) => self.relate_to_static(fr_a),
-                        (ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
+                        (&ty::ReStatic, &ty::ReFree(_)) => {},
+                        (&ty::ReFree(fr_a), &ty::ReStatic) => self.relate_to_static(fr_a),
+                        (&ty::ReFree(fr_a), &ty::ReFree(fr_b)) => {
                             // Record that `'a:'b`. Or, put another way, `'b <= 'a`.
                             self.relate_free_regions(fr_b, fr_a);
                         }
@@ -122,26 +121,26 @@ pub fn lub_free_regions(&self, fr_a: FreeRegion, fr_b: FreeRegion) -> Region {
     /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
     pub fn is_subregion_of(&self,
                            tcx: TyCtxt,
-                           sub_region: ty::Region,
-                           super_region: ty::Region)
+                           sub_region: &ty::Region,
+                           super_region: &ty::Region)
                            -> bool {
         let result = sub_region == super_region || {
             match (sub_region, super_region) {
-                (ty::ReEmpty, _) |
-                (_, ty::ReStatic) =>
+                (&ty::ReEmpty, _) |
+                (_, &ty::ReStatic) =>
                     true,
 
-                (ty::ReScope(sub_scope), ty::ReScope(super_scope)) =>
+                (&ty::ReScope(sub_scope), &ty::ReScope(super_scope)) =>
                     tcx.region_maps.is_subscope_of(sub_scope, super_scope),
 
-                (ty::ReScope(sub_scope), ty::ReFree(fr)) =>
+                (&ty::ReScope(sub_scope), &ty::ReFree(fr)) =>
                     tcx.region_maps.is_subscope_of(sub_scope, fr.scope) ||
                     self.is_static(fr),
 
-                (ty::ReFree(sub_fr), ty::ReFree(super_fr)) =>
+                (&ty::ReFree(sub_fr), &ty::ReFree(super_fr)) =>
                     self.sub_free_region(sub_fr, super_fr),
 
-                (ty::ReStatic, ty::ReFree(sup_fr)) =>
+                (&ty::ReStatic, &ty::ReFree(sup_fr)) =>
                     self.is_static(sup_fr),
 
                 _ =>
index a209b1d1abd7c6e320fbf0e129a59a2f992f4bce..d1769d5cbc51bd90011c529b4ba845840014d704 100644 (file)
@@ -30,7 +30,6 @@
 use util::nodemap::FnvHashMap;
 
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax::parse::token::InternedString;
 use hir::intravisit::Visitor;
 use hir;
index 74d29b273ff2b40c9d619275a163aadbddfd4978..b83826de26dd68b60b9936c86302bdcbca6ba1b2 100644 (file)
@@ -1479,7 +1479,13 @@ fn check_ret(&self,
                 self.ir.tcx.region_maps.call_site_extent(id, body.id),
                 &self.fn_ret(id));
 
-        if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
+        if fn_ret.is_never() {
+            // FIXME(durka) this rejects code like `fn foo(x: !) -> ! { x }`
+            if self.live_on_entry(entry_ln, self.s.clean_exit_var).is_some() {
+                span_err!(self.ir.tcx.sess, sp, E0270,
+                          "computation may converge in a function marked as diverging");
+            }
+        } else if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
             let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
             let t_ret_subst = fn_ret.subst(self.ir.tcx, &param_env.free_substs);
             let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env),
index 676e456dcea94e2ecaf96fe984b50d1dec27dd47..a74bdb02044dee92127b18420480469de2b241d6 100644 (file)
 
 #[derive(Clone, PartialEq)]
 pub enum Categorization<'tcx> {
-    Rvalue(ty::Region),                    // temporary val, argument is its scope
+    Rvalue(&'tcx ty::Region),                    // temporary val, argument is its scope
     StaticItem,
     Upvar(Upvar),                          // upvar referenced by closure env
     Local(ast::NodeId),                    // local variable
-    Deref(cmt<'tcx>, usize, PointerKind),  // deref of a ptr
+    Deref(cmt<'tcx>, usize, PointerKind<'tcx>),  // deref of a ptr
     Interior(cmt<'tcx>, InteriorKind),     // something interior: field, tuple, etc
     Downcast(cmt<'tcx>, DefId),            // selects a particular enum variant (*1)
 
@@ -110,18 +110,18 @@ pub struct Upvar {
 
 // different kinds of pointers:
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub enum PointerKind {
+pub enum PointerKind<'tcx> {
     /// `Box<T>`
     Unique,
 
     /// `&T`
-    BorrowedPtr(ty::BorrowKind, ty::Region),
+    BorrowedPtr(ty::BorrowKind, &'tcx ty::Region),
 
     /// `*T`
     UnsafePtr(hir::Mutability),
 
     /// Implicit deref of the `&T` that results from an overloaded index `[]`.
-    Implicit(ty::BorrowKind, ty::Region),
+    Implicit(ty::BorrowKind, &'tcx ty::Region),
 }
 
 // We use the term "interior" to mean "something reachable from the
@@ -198,8 +198,8 @@ pub struct cmt_<'tcx> {
 // We pun on *T to mean both actual deref of a ptr as well
 // as accessing of components:
 #[derive(Copy, Clone)]
-pub enum deref_kind {
-    deref_ptr(PointerKind),
+pub enum deref_kind<'tcx> {
+    deref_ptr(PointerKind<'tcx>),
     deref_interior(InteriorKind),
 }
 
@@ -216,7 +216,7 @@ fn deref_kind(t: Ty, context: DerefKindContext) -> McResult<deref_kind> {
 
         ty::TyRef(r, mt) => {
             let kind = ty::BorrowKind::from_mutbl(mt.mutbl);
-            Ok(deref_ptr(BorrowedPtr(kind, *r)))
+            Ok(deref_ptr(BorrowedPtr(kind, r)))
         }
 
         ty::TyRawPtr(ref mt) => {
@@ -767,13 +767,13 @@ fn env_deref(&self,
         };
 
         // Region of environment pointer
-        let env_region = ty::ReFree(ty::FreeRegion {
+        let env_region = self.tcx().mk_region(ty::ReFree(ty::FreeRegion {
             // The environment of a closure is guaranteed to
             // outlive any bindings introduced in the body of the
             // closure itself.
             scope: self.tcx().region_maps.item_extent(fn_body_id),
             bound_region: ty::BrEnv
-        });
+        }));
 
         let env_ptr = BorrowedPtr(env_borrow_kind, env_region);
 
@@ -817,11 +817,11 @@ fn env_deref(&self,
 
     /// Returns the lifetime of a temporary created by expr with id `id`.
     /// This could be `'static` if `id` is part of a constant expression.
-    pub fn temporary_scope(&self, id: ast::NodeId) -> ty::Region {
-        match self.infcx.temporary_scope(id) {
+    pub fn temporary_scope(&self, id: ast::NodeId) -> &'tcx ty::Region {
+        self.tcx().mk_region(match self.infcx.temporary_scope(id) {
             Some(scope) => ty::ReScope(scope),
             None => ty::ReStatic
-        }
+        })
     }
 
     pub fn cat_rvalue_node(&self,
@@ -845,7 +845,7 @@ pub fn cat_rvalue_node(&self,
         let re = if qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
             self.temporary_scope(id)
         } else {
-            ty::ReStatic
+            self.tcx().mk_region(ty::ReStatic)
         };
         let ret = self.cat_rvalue(id, span, re, expr_ty);
         debug!("cat_rvalue_node ret {:?}", ret);
@@ -855,7 +855,7 @@ pub fn cat_rvalue_node(&self,
     pub fn cat_rvalue(&self,
                       cmt_id: ast::NodeId,
                       span: Span,
-                      temp_scope: ty::Region,
+                      temp_scope: &'tcx ty::Region,
                       expr_ty: Ty<'tcx>) -> cmt<'tcx> {
         let ret = Rc::new(cmt_ {
             id:cmt_id,
@@ -1480,7 +1480,7 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
     }
 }
 
-impl fmt::Debug for PointerKind {
+impl<'tcx> fmt::Debug for PointerKind<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             Unique => write!(f, "Box"),
index 478f662d0962a4646a9ae555f2bcca15abb7acb7..189150d426463f4835af37c86cde53e43245dfbf 100644 (file)
@@ -23,9 +23,8 @@
 pub enum AccessLevel {
     // Exported items + items participating in various kinds of public interfaces,
     // but not directly nameable. For example, if function `fn f() -> T {...}` is
-    // public, then type `T` is exported. Its values can be obtained by other crates
-    // even if the type itseld is not nameable.
-    // FIXME: Mostly unimplemented. Only `type` aliases export items currently.
+    // public, then type `T` is reachable. Its values can be obtained by other crates
+    // even if the type itself is not nameable.
     Reachable,
     // Public items + items accessible to other crates with help of `pub use` reexports
     Exported,
index 6ea0fa20c572689c00b6804c74c1818e077dd04c..e29a7cf9d68467a332147ee06ccf853825231ff6 100644 (file)
@@ -22,9 +22,8 @@
 use ty::{self, TyCtxt};
 use middle::privacy;
 use session::config;
-use util::nodemap::NodeSet;
+use util::nodemap::{NodeSet, FnvHashSet};
 
-use std::collections::HashSet;
 use syntax::abi::Abi;
 use syntax::ast;
 use syntax::attr;
@@ -204,7 +203,7 @@ fn def_id_represents_local_inlined_item(&self, def_id: DefId) -> bool {
 
     // Step 2: Mark all symbols that the symbols on the worklist touch.
     fn propagate(&mut self) {
-        let mut scanned = HashSet::new();
+        let mut scanned = FnvHashSet();
         loop {
             let search_item = match self.worklist.pop() {
                 Some(item) => item,
index 7dcd358165c9248d88c7dbe3238b4797906465b4..0764e817f4307be588e51c8da31f67864b288cf4 100644 (file)
@@ -17,7 +17,6 @@
 
 use session::Session;
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 
 pub fn update_recursion_limit(sess: &Session, krate: &ast::Crate) {
     for attr in &krate.attrs {
index 6f0ad087dc5898ad72b259f267274654ac5c467a..ef905b51edfb2982db89492d8634f795740fd493 100644 (file)
@@ -237,7 +237,7 @@ pub fn span(&self, region_maps: &RegionMaps, ast_map: &ast_map::Map) -> Option<S
                         // (This is the special case aluded to in the
                         // doc-comment for this method)
                         let stmt_span = blk.stmts[r.first_statement_index as usize].span;
-                        Some(Span { lo: stmt_span.hi, ..blk.span })
+                        Some(Span { lo: stmt_span.hi, hi: blk.span.hi, expn_id: stmt_span.expn_id })
                     }
                 }
             }
@@ -803,7 +803,8 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &hir::Expr) {
                 terminating(r.id);
             }
 
-            hir::ExprIf(_, ref then, Some(ref otherwise)) => {
+            hir::ExprIf(ref expr, ref then, Some(ref otherwise)) => {
+                terminating(expr.id);
                 terminating(then.id);
                 terminating(otherwise.id);
             }
index 8369a6c39d54d658a825aaa2eb4842e5c9aa06f2..ebe4050022153bee2cb2db306778f25eee1bd967 100644 (file)
@@ -89,9 +89,12 @@ struct LifetimeContext<'a, 'tcx: 'a> {
 
 #[derive(PartialEq, Debug)]
 enum ScopeChain<'a> {
-    /// EarlyScope(['a, 'b, ...], s) extends s with early-bound
-    /// lifetimes.
-    EarlyScope(&'a [hir::LifetimeDef], Scope<'a>),
+    /// EarlyScope(['a, 'b, ...], start, s) extends s with early-bound
+    /// lifetimes, with consecutive parameter indices from `start`.
+    /// That is, 'a has index `start`, 'b has index `start + 1`, etc.
+    /// Indices before `start` correspond to other generic parameters
+    /// of a parent item (trait/impl of a method), or `Self` in traits.
+    EarlyScope(&'a [hir::LifetimeDef], u32, Scope<'a>),
     /// LateScope(['a, 'b, ...], s) extends s with late-bound
     /// lifetimes introduced by the declaration binder_id.
     LateScope(&'a [hir::LifetimeDef], Scope<'a>),
@@ -157,7 +160,12 @@ fn visit_item(&mut self, item: &hir::Item) {
                 hir::ItemImpl(_, _, ref generics, _, _, _) => {
                     // These kinds of items have only early bound lifetime parameters.
                     let lifetimes = &generics.lifetimes;
-                    this.with(EarlyScope(lifetimes, &ROOT_SCOPE), |old_scope, this| {
+                    let start = if let hir::ItemTrait(..) = item.node {
+                        1 // Self comes before lifetimes
+                    } else {
+                        0
+                    };
+                    this.with(EarlyScope(lifetimes, start, &ROOT_SCOPE), |old_scope, this| {
                         this.check_lifetime_defs(old_scope, lifetimes);
                         intravisit::walk_item(this, item);
                     });
@@ -461,7 +469,7 @@ fn check_if_label_shadows_lifetime<'a>(sess: &'a Session,
                 FnScope { s, .. } => { scope = s; }
                 RootScope => { return; }
 
-                EarlyScope(lifetimes, s) |
+                EarlyScope(lifetimes, _, s) |
                 LateScope(lifetimes, s) => {
                     for lifetime_def in lifetimes {
                         // FIXME (#24278): non-hygienic comparison
@@ -566,8 +574,24 @@ fn visit_early_late<F>(&mut self,
                     .cloned()
                     .partition(|l| self.map.late_bound.contains_key(&l.lifetime.id));
 
+        // Find the start of nested early scopes, e.g. in methods.
+        let mut start = 0;
+        if let EarlyScope(..) = *self.scope {
+            let parent = self.hir_map.expect_item(self.hir_map.get_parent(fn_id));
+            if let hir::ItemTrait(..) = parent.node {
+                start += 1; // Self comes first.
+            }
+            match parent.node {
+                hir::ItemTrait(_, ref generics, _, _) |
+                hir::ItemImpl(_, _, ref generics, _, _, _) => {
+                    start += generics.lifetimes.len() + generics.ty_params.len();
+                }
+                _ => {}
+            }
+        }
+
         let this = self;
-        this.with(EarlyScope(&early, this.scope), move |old_scope, this| {
+        this.with(EarlyScope(&early, start as u32, this.scope), move |old_scope, this| {
             this.with(LateScope(&late, this.scope), move |_, this| {
                 this.check_lifetime_defs(old_scope, &generics.lifetimes);
                 walk(this);
@@ -597,19 +621,11 @@ fn resolve_lifetime_ref(&mut self, lifetime_ref: &hir::Lifetime) {
                     break;
                 }
 
-                EarlyScope(lifetimes, s) => {
+                EarlyScope(lifetimes, start, s) => {
                     match search_lifetimes(lifetimes, lifetime_ref) {
-                        Some((mut index, lifetime_def)) => {
-                            // Adjust for nested early scopes, e.g. in methods.
-                            let mut parent = s;
-                            while let EarlyScope(lifetimes, s) = *parent {
-                                index += lifetimes.len() as u32;
-                                parent = s;
-                            }
-                            assert_eq!(*parent, RootScope);
-
+                        Some((index, lifetime_def)) => {
                             let decl_id = lifetime_def.id;
-                            let def = DefEarlyBoundRegion(index, decl_id);
+                            let def = DefEarlyBoundRegion(start + index, decl_id);
                             self.insert_lifetime(lifetime_ref, def);
                             return;
                         }
@@ -671,7 +687,7 @@ fn resolve_free_lifetime_ref(&mut self,
                     break;
                 }
 
-                EarlyScope(lifetimes, s) |
+                EarlyScope(lifetimes, _, s) |
                 LateScope(lifetimes, s) => {
                     search_result = search_lifetimes(lifetimes, lifetime_ref);
                     if search_result.is_some() {
@@ -767,7 +783,7 @@ fn check_lifetime_def_for_shadowing(&self,
                     return;
                 }
 
-                EarlyScope(lifetimes, s) |
+                EarlyScope(lifetimes, _, s) |
                 LateScope(lifetimes, s) => {
                     if let Some((_, lifetime_def)) = search_lifetimes(lifetimes, lifetime) {
                         signal_shadowing_problem(
index cbbc2c4f98f5e09b025f59756289a153805b0f7d..c20fcc3fe1dc6205631eaf8b460f2208a6b84221 100644 (file)
@@ -27,7 +27,7 @@
 use syntax::ast;
 use syntax::ast::{NodeId, Attribute};
 use syntax::feature_gate::{GateIssue, emit_feature_err, find_lang_feature_accepted_version};
-use syntax::attr::{self, Stability, Deprecation, AttrMetaMethods};
+use syntax::attr::{self, Stability, Deprecation};
 use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};
 
 use hir;
@@ -631,7 +631,7 @@ pub fn check_path_list_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                       cb: &mut FnMut(DefId, Span,
                                                      &Option<&Stability>,
                                                      &Option<DeprecationEntry>)) {
-    match tcx.expect_def(item.node.id()) {
+    match tcx.expect_def(item.node.id) {
         Def::PrimTy(..) => {}
         def => {
             maybe_do_stability_check(tcx, def.def_id(), item.span, cb);
index f511d820fac5878f5f05ee51e79b4b0efb491d36..8145c0aae3f74cb344303a5084468f455897943c 100644 (file)
@@ -911,7 +911,7 @@ pub enum Rvalue<'tcx> {
     Repeat(Operand<'tcx>, TypedConstVal<'tcx>),
 
     /// &x or &mut x
-    Ref(Region, BorrowKind, Lvalue<'tcx>),
+    Ref(&'tcx Region, BorrowKind, Lvalue<'tcx>),
 
     /// length of a [X] or [X;n] value
     Len(Lvalue<'tcx>),
@@ -1239,3 +1239,14 @@ impl<'a, 'b>  GraphSuccessors<'b> for Mir<'a> {
     type Item = BasicBlock;
     type Iter = IntoIter<BasicBlock>;
 }
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Ord, PartialOrd)]
+pub struct Location {
+    /// the location is within this block
+    pub block: BasicBlock,
+
+    /// the location is the start of the this statement; or, if `statement_index`
+    /// == num-statements, then the start of the terminator.
+    pub statement_index: usize,
+}
+
index cf91229f1c713afa07c4baf714e51d161baa4df7..76e5f8598c1c549c6da3843e7275d293aa9a1eae 100644 (file)
@@ -145,8 +145,7 @@ pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Opti
             }
             &Rvalue::Ref(reg, bk, ref lv) => {
                 let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
-                Some(tcx.mk_ref(
-                    tcx.mk_region(reg),
+                Some(tcx.mk_ref(reg,
                     ty::TypeAndMut {
                         ty: lv_ty,
                         mutbl: bk.to_mutbl_lossy()
index ead8de86dbae4094f555d09068fde43057d6a0cf..2771880735c27a71866ba304563c910d99fef0c0 100644 (file)
@@ -103,60 +103,70 @@ fn visit_visibility_scope_data(&mut self,
 
             fn visit_statement(&mut self,
                                block: BasicBlock,
-                               statement: & $($mutability)* Statement<'tcx>) {
-                self.super_statement(block, statement);
+                               statement: & $($mutability)* Statement<'tcx>,
+                               location: Location) {
+                self.super_statement(block, statement, location);
             }
 
             fn visit_assign(&mut self,
                             block: BasicBlock,
                             lvalue: & $($mutability)* Lvalue<'tcx>,
-                            rvalue: & $($mutability)* Rvalue<'tcx>) {
-                self.super_assign(block, lvalue, rvalue);
+                            rvalue: & $($mutability)* Rvalue<'tcx>,
+                            location: Location) {
+                self.super_assign(block, lvalue, rvalue, location);
             }
 
             fn visit_terminator(&mut self,
                                 block: BasicBlock,
-                                terminator: & $($mutability)* Terminator<'tcx>) {
-                self.super_terminator(block, terminator);
+                                terminator: & $($mutability)* Terminator<'tcx>,
+                                location: Location) {
+                self.super_terminator(block, terminator, location);
             }
 
             fn visit_terminator_kind(&mut self,
                                      block: BasicBlock,
-                                     kind: & $($mutability)* TerminatorKind<'tcx>) {
-                self.super_terminator_kind(block, kind);
+                                     kind: & $($mutability)* TerminatorKind<'tcx>,
+                                     location: Location) {
+                self.super_terminator_kind(block, kind, location);
             }
 
             fn visit_assert_message(&mut self,
-                                    msg: & $($mutability)* AssertMessage<'tcx>) {
-                self.super_assert_message(msg);
+                                    msg: & $($mutability)* AssertMessage<'tcx>,
+                                    location: Location) {
+                self.super_assert_message(msg, location);
             }
 
             fn visit_rvalue(&mut self,
-                            rvalue: & $($mutability)* Rvalue<'tcx>) {
-                self.super_rvalue(rvalue);
+                            rvalue: & $($mutability)* Rvalue<'tcx>,
+                            location: Location) {
+                self.super_rvalue(rvalue, location);
             }
 
             fn visit_operand(&mut self,
-                             operand: & $($mutability)* Operand<'tcx>) {
-                self.super_operand(operand);
+                             operand: & $($mutability)* Operand<'tcx>,
+                             location: Location) {
+                self.super_operand(operand, location);
             }
 
             fn visit_lvalue(&mut self,
                             lvalue: & $($mutability)* Lvalue<'tcx>,
-                            context: LvalueContext) {
-                self.super_lvalue(lvalue, context);
+                            context: LvalueContext,
+                            location: Location) {
+                self.super_lvalue(lvalue, context, location);
             }
 
             fn visit_projection(&mut self,
                                 lvalue: & $($mutability)* LvalueProjection<'tcx>,
-                                context: LvalueContext) {
-                self.super_projection(lvalue, context);
+                                context: LvalueContext,
+                                location: Location) {
+                self.super_projection(lvalue, context, location);
             }
 
             fn visit_projection_elem(&mut self,
                                      lvalue: & $($mutability)* LvalueElem<'tcx>,
-                                     context: LvalueContext) {
-                self.super_projection_elem(lvalue, context);
+                                     context: LvalueContext,
+                                     location: Location) {
+                self.super_projection_elem(lvalue, context, location);
             }
 
             fn visit_branch(&mut self,
@@ -166,17 +176,20 @@ fn visit_branch(&mut self,
             }
 
             fn visit_constant(&mut self,
-                              constant: & $($mutability)* Constant<'tcx>) {
-                self.super_constant(constant);
+                              constant: & $($mutability)* Constant<'tcx>,
+                              location: Location) {
+                self.super_constant(constant, location);
             }
 
             fn visit_literal(&mut self,
-                             literal: & $($mutability)* Literal<'tcx>) {
-                self.super_literal(literal);
+                             literal: & $($mutability)* Literal<'tcx>,
+                             location: Location) {
+                self.super_literal(literal, location);
             }
 
             fn visit_def_id(&mut self,
-                            def_id: & $($mutability)* DefId) {
+                            def_id: & $($mutability)* DefId,
+                            _: Location) {
                 self.super_def_id(def_id);
             }
 
@@ -206,18 +219,21 @@ fn visit_closure_substs(&mut self,
             }
 
             fn visit_const_val(&mut self,
-                               const_val: & $($mutability)* ConstVal) {
+                               const_val: & $($mutability)* ConstVal,
+                               _: Location) {
                 self.super_const_val(const_val);
             }
 
             fn visit_const_usize(&mut self,
-                                 const_usize: & $($mutability)* ConstUsize) {
+                                 const_usize: & $($mutability)* ConstUsize,
+                                 _: Location) {
                 self.super_const_usize(const_usize);
             }
 
             fn visit_typed_const_val(&mut self,
-                                     val: & $($mutability)* TypedConstVal<'tcx>) {
-                self.super_typed_const_val(val);
+                                     val: & $($mutability)* TypedConstVal<'tcx>,
+                                     location: Location) {
+                self.super_typed_const_val(val, location);
             }
 
             fn visit_var_decl(&mut self,
@@ -280,12 +296,16 @@ fn super_basic_block_data(&mut self,
                     is_cleanup: _
                 } = *data;
 
+                let mut index = 0;
                 for statement in statements {
-                    self.visit_statement(block, statement);
+                    let location = Location { block: block, statement_index: index };
+                    self.visit_statement(block, statement, location);
+                    index += 1;
                 }
 
                 if let Some(ref $($mutability)* terminator) = *terminator {
-                    self.visit_terminator(block, terminator);
+                    let location = Location { block: block, statement_index: index };
+                    self.visit_terminator(block, terminator, location);
                 }
             }
 
@@ -304,7 +324,8 @@ fn super_visibility_scope_data(&mut self,
 
             fn super_statement(&mut self,
                                block: BasicBlock,
-                               statement: & $($mutability)* Statement<'tcx>) {
+                               statement: & $($mutability)* Statement<'tcx>,
+                               location: Location) {
                 let Statement {
                     ref $($mutability)* source_info,
                     ref $($mutability)* kind,
@@ -314,16 +335,16 @@ fn super_statement(&mut self,
                 match *kind {
                     StatementKind::Assign(ref $($mutability)* lvalue,
                                           ref $($mutability)* rvalue) => {
-                        self.visit_assign(block, lvalue, rvalue);
+                        self.visit_assign(block, lvalue, rvalue, location);
                     }
                     StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
-                        self.visit_lvalue(lvalue, LvalueContext::Store);
+                        self.visit_lvalue(lvalue, LvalueContext::Store, location);
                     }
                     StatementKind::StorageLive(ref $($mutability)* lvalue) => {
-                        self.visit_lvalue(lvalue, LvalueContext::StorageLive);
+                        self.visit_lvalue(lvalue, LvalueContext::StorageLive, location);
                     }
                     StatementKind::StorageDead(ref $($mutability)* lvalue) => {
-                        self.visit_lvalue(lvalue, LvalueContext::StorageDead);
+                        self.visit_lvalue(lvalue, LvalueContext::StorageDead, location);
                     }
                 }
             }
@@ -331,26 +352,29 @@ fn super_statement(&mut self,
             fn super_assign(&mut self,
                             _block: BasicBlock,
                             lvalue: &$($mutability)* Lvalue<'tcx>,
-                            rvalue: &$($mutability)* Rvalue<'tcx>) {
-                self.visit_lvalue(lvalue, LvalueContext::Store);
-                self.visit_rvalue(rvalue);
+                            rvalue: &$($mutability)* Rvalue<'tcx>,
+                            location: Location) {
+                self.visit_lvalue(lvalue, LvalueContext::Store, location);
+                self.visit_rvalue(rvalue, location);
             }
 
             fn super_terminator(&mut self,
                                 block: BasicBlock,
-                                terminator: &$($mutability)* Terminator<'tcx>) {
+                                terminator: &$($mutability)* Terminator<'tcx>,
+                                location: Location) {
                 let Terminator {
                     ref $($mutability)* source_info,
                     ref $($mutability)* kind,
                 } = *terminator;
 
                 self.visit_source_info(source_info);
-                self.visit_terminator_kind(block, kind);
+                self.visit_terminator_kind(block, kind, location);
             }
 
             fn super_terminator_kind(&mut self,
                                      block: BasicBlock,
-                                     kind: & $($mutability)* TerminatorKind<'tcx>) {
+                                     kind: & $($mutability)* TerminatorKind<'tcx>,
+                                     source_location: Location) {
                 match *kind {
                     TerminatorKind::Goto { target } => {
                         self.visit_branch(block, target);
@@ -358,7 +382,7 @@ fn super_terminator_kind(&mut self,
 
                     TerminatorKind::If { ref $($mutability)* cond,
                                          ref $($mutability)* targets } => {
-                        self.visit_operand(cond);
+                        self.visit_operand(cond, source_location);
                         for &target in targets.as_slice() {
                             self.visit_branch(block, target);
                         }
@@ -367,7 +391,7 @@ fn super_terminator_kind(&mut self,
                     TerminatorKind::Switch { ref $($mutability)* discr,
                                              adt_def: _,
                                              ref targets } => {
-                        self.visit_lvalue(discr, LvalueContext::Inspect);
+                        self.visit_lvalue(discr, LvalueContext::Inspect, source_location);
                         for &target in targets {
                             self.visit_branch(block, target);
                         }
@@ -377,10 +401,10 @@ fn super_terminator_kind(&mut self,
                                                 ref $($mutability)* switch_ty,
                                                 ref $($mutability)* values,
                                                 ref targets } => {
-                        self.visit_lvalue(discr, LvalueContext::Inspect);
+                        self.visit_lvalue(discr, LvalueContext::Inspect, source_location);
                         self.visit_ty(switch_ty);
                         for value in values {
-                            self.visit_const_val(value);
+                            self.visit_const_val(value, source_location);
                         }
                         for &target in targets {
                             self.visit_branch(block, target);
@@ -395,7 +419,7 @@ fn super_terminator_kind(&mut self,
                     TerminatorKind::Drop { ref $($mutability)* location,
                                            target,
                                            unwind } => {
-                        self.visit_lvalue(location, LvalueContext::Drop);
+                        self.visit_lvalue(location, LvalueContext::Drop, source_location);
                         self.visit_branch(block, target);
                         unwind.map(|t| self.visit_branch(block, t));
                     }
@@ -404,8 +428,8 @@ fn super_terminator_kind(&mut self,
                                                      ref $($mutability)* value,
                                                      target,
                                                      unwind } => {
-                        self.visit_lvalue(location, LvalueContext::Drop);
-                        self.visit_operand(value);
+                        self.visit_lvalue(location, LvalueContext::Drop, source_location);
+                        self.visit_operand(value, source_location);
                         self.visit_branch(block, target);
                         unwind.map(|t| self.visit_branch(block, t));
                     }
@@ -414,12 +438,12 @@ fn super_terminator_kind(&mut self,
                                            ref $($mutability)* args,
                                            ref $($mutability)* destination,
                                            cleanup } => {
-                        self.visit_operand(func);
+                        self.visit_operand(func, source_location);
                         for arg in args {
-                            self.visit_operand(arg);
+                            self.visit_operand(arg, source_location);
                         }
                         if let Some((ref $($mutability)* destination, target)) = *destination {
-                            self.visit_lvalue(destination, LvalueContext::Call);
+                            self.visit_lvalue(destination, LvalueContext::Call, source_location);
                             self.visit_branch(block, target);
                         }
                         cleanup.map(|t| self.visit_branch(block, t));
@@ -430,8 +454,8 @@ fn super_terminator_kind(&mut self,
                                              ref $($mutability)* msg,
                                              target,
                                              cleanup } => {
-                        self.visit_operand(cond);
-                        self.visit_assert_message(msg);
+                        self.visit_operand(cond, source_location);
+                        self.visit_assert_message(msg, source_location);
                         self.visit_branch(block, target);
                         cleanup.map(|t| self.visit_branch(block, t));
                     }
@@ -439,47 +463,49 @@ fn super_terminator_kind(&mut self,
             }
 
             fn super_assert_message(&mut self,
-                                    msg: & $($mutability)* AssertMessage<'tcx>) {
+                                    msg: & $($mutability)* AssertMessage<'tcx>,
+                                    location: Location) {
                 match *msg {
                     AssertMessage::BoundsCheck {
                         ref $($mutability)* len,
                         ref $($mutability)* index
                     } => {
-                        self.visit_operand(len);
-                        self.visit_operand(index);
+                        self.visit_operand(len, location);
+                        self.visit_operand(index, location);
                     }
                     AssertMessage::Math(_) => {}
                 }
             }
 
             fn super_rvalue(&mut self,
-                            rvalue: & $($mutability)* Rvalue<'tcx>) {
+                            rvalue: & $($mutability)* Rvalue<'tcx>,
+                            location: Location) {
                 match *rvalue {
                     Rvalue::Use(ref $($mutability)* operand) => {
-                        self.visit_operand(operand);
+                        self.visit_operand(operand, location);
                     }
 
                     Rvalue::Repeat(ref $($mutability)* value,
                                    ref $($mutability)* typed_const_val) => {
-                        self.visit_operand(value);
-                        self.visit_typed_const_val(typed_const_val);
+                        self.visit_operand(value, location);
+                        self.visit_typed_const_val(typed_const_val, location);
                     }
 
                     Rvalue::Ref(r, bk, ref $($mutability)* path) => {
                         self.visit_lvalue(path, LvalueContext::Borrow {
                             region: r,
                             kind: bk
-                        });
+                        }, location);
                     }
 
                     Rvalue::Len(ref $($mutability)* path) => {
-                        self.visit_lvalue(path, LvalueContext::Inspect);
+                        self.visit_lvalue(path, LvalueContext::Inspect, location);
                     }
 
                     Rvalue::Cast(_cast_kind,
                                  ref $($mutability)* operand,
                                  ref $($mutability)* ty) => {
-                        self.visit_operand(operand);
+                        self.visit_operand(operand, location);
                         self.visit_ty(ty);
                     }
 
@@ -489,12 +515,12 @@ fn super_rvalue(&mut self,
                     Rvalue::CheckedBinaryOp(_bin_op,
                                      ref $($mutability)* lhs,
                                      ref $($mutability)* rhs) => {
-                        self.visit_operand(lhs);
-                        self.visit_operand(rhs);
+                        self.visit_operand(lhs, location);
+                        self.visit_operand(rhs, location);
                     }
 
                     Rvalue::UnaryOp(_un_op, ref $($mutability)* op) => {
-                        self.visit_operand(op);
+                        self.visit_operand(op, location);
                     }
 
                     Rvalue::Box(ref $($mutability)* ty) => {
@@ -515,13 +541,13 @@ fn super_rvalue(&mut self,
                             }
                             AggregateKind::Closure(ref $($mutability)* def_id,
                                                    ref $($mutability)* closure_substs) => {
-                                self.visit_def_id(def_id);
+                                self.visit_def_id(def_id, location);
                                 self.visit_closure_substs(closure_substs);
                             }
                         }
 
                         for operand in operands {
-                            self.visit_operand(operand);
+                            self.visit_operand(operand, location);
                         }
                     }
 
@@ -529,30 +555,32 @@ fn super_rvalue(&mut self,
                                         ref $($mutability)* inputs,
                                         asm: _ } => {
                         for output in & $($mutability)* outputs[..] {
-                            self.visit_lvalue(output, LvalueContext::Store);
+                            self.visit_lvalue(output, LvalueContext::Store, location);
                         }
                         for input in & $($mutability)* inputs[..] {
-                            self.visit_operand(input);
+                            self.visit_operand(input, location);
                         }
                     }
                 }
             }
 
             fn super_operand(&mut self,
-                             operand: & $($mutability)* Operand<'tcx>) {
+                             operand: & $($mutability)* Operand<'tcx>,
+                             location: Location) {
                 match *operand {
                     Operand::Consume(ref $($mutability)* lvalue) => {
-                        self.visit_lvalue(lvalue, LvalueContext::Consume);
+                        self.visit_lvalue(lvalue, LvalueContext::Consume, location);
                     }
                     Operand::Constant(ref $($mutability)* constant) => {
-                        self.visit_constant(constant);
+                        self.visit_constant(constant, location);
                     }
                 }
             }
 
             fn super_lvalue(&mut self,
                             lvalue: & $($mutability)* Lvalue<'tcx>,
-                            context: LvalueContext) {
+                            context: LvalueContext,
+                            location: Location) {
                 match *lvalue {
                     Lvalue::Var(_) |
                     Lvalue::Temp(_) |
@@ -560,28 +588,30 @@ fn super_lvalue(&mut self,
                     Lvalue::ReturnPointer => {
                     }
                     Lvalue::Static(ref $($mutability)* def_id) => {
-                        self.visit_def_id(def_id);
+                        self.visit_def_id(def_id, location);
                     }
                     Lvalue::Projection(ref $($mutability)* proj) => {
-                        self.visit_projection(proj, context);
+                        self.visit_projection(proj, context, location);
                     }
                 }
             }
 
             fn super_projection(&mut self,
                                 proj: & $($mutability)* LvalueProjection<'tcx>,
-                                context: LvalueContext) {
+                                context: LvalueContext,
+                                location: Location) {
                 let Projection {
                     ref $($mutability)* base,
                     ref $($mutability)* elem,
                 } = *proj;
-                self.visit_lvalue(base, LvalueContext::Projection);
-                self.visit_projection_elem(elem, context);
+                self.visit_lvalue(base, LvalueContext::Projection, location);
+                self.visit_projection_elem(elem, context, location);
             }
 
             fn super_projection_elem(&mut self,
                                      proj: & $($mutability)* LvalueElem<'tcx>,
-                                     _context: LvalueContext) {
+                                     _context: LvalueContext,
+                                     location: Location) {
                 match *proj {
                     ProjectionElem::Deref => {
                     }
@@ -591,7 +621,7 @@ fn super_projection_elem(&mut self,
                         self.visit_ty(ty);
                     }
                     ProjectionElem::Index(ref $($mutability)* operand) => {
-                        self.visit_operand(operand);
+                        self.visit_operand(operand, location);
                     }
                     ProjectionElem::ConstantIndex { offset: _,
                                                     min_length: _,
@@ -645,7 +675,8 @@ fn super_branch(&mut self,
             }
 
             fn super_constant(&mut self,
-                              constant: & $($mutability)* Constant<'tcx>) {
+                              constant: & $($mutability)* Constant<'tcx>,
+                              location: Location) {
                 let Constant {
                     ref $($mutability)* span,
                     ref $($mutability)* ty,
@@ -654,11 +685,12 @@ fn super_constant(&mut self,
 
                 self.visit_span(span);
                 self.visit_ty(ty);
-                self.visit_literal(literal);
+                self.visit_literal(literal, location);
             }
 
             fn super_typed_const_val(&mut self,
-                                     constant: & $($mutability)* TypedConstVal<'tcx>) {
+                                     constant: & $($mutability)* TypedConstVal<'tcx>,
+                                     location: Location) {
                 let TypedConstVal {
                     ref $($mutability)* span,
                     ref $($mutability)* ty,
@@ -667,19 +699,20 @@ fn super_typed_const_val(&mut self,
 
                 self.visit_span(span);
                 self.visit_ty(ty);
-                self.visit_const_usize(value);
+                self.visit_const_usize(value, location);
             }
 
             fn super_literal(&mut self,
-                             literal: & $($mutability)* Literal<'tcx>) {
+                             literal: & $($mutability)* Literal<'tcx>,
+                             location: Location) {
                 match *literal {
                     Literal::Item { ref $($mutability)* def_id,
                                     ref $($mutability)* substs } => {
-                        self.visit_def_id(def_id);
+                        self.visit_def_id(def_id, location);
                         self.visit_substs(substs);
                     }
                     Literal::Value { ref $($mutability)* value } => {
-                        self.visit_const_val(value);
+                        self.visit_const_val(value, location);
                     }
                     Literal::Promoted { index: _ } => {}
                 }
@@ -724,7 +757,7 @@ fn super_const_usize(&mut self, _substs: & $($mutability)* ConstUsize) {
 make_mir_visitor!(MutVisitor,mut);
 
 #[derive(Copy, Clone, Debug)]
-pub enum LvalueContext {
+pub enum LvalueContext<'tcx> {
     // Appears as LHS of an assignment
     Store,
 
@@ -738,7 +771,7 @@ pub enum LvalueContext {
     Inspect,
 
     // Being borrowed
-    Borrow { region: Region, kind: BorrowKind },
+    Borrow { region: &'tcx Region, kind: BorrowKind },
 
     // Being sliced -- this should be same as being borrowed, probably
     Slice { from_start: usize, from_end: usize },
index e988ddcd97b1518e34adde4771ca071903db99d6..562dce6a1b129d9403f7552b24a9c9b08718725b 100644 (file)
@@ -25,7 +25,6 @@
 
 use syntax::ast::{self, IntTy, UintTy};
 use syntax::attr;
-use syntax::attr::AttrMetaMethods;
 use syntax::parse;
 use syntax::parse::token::InternedString;
 use syntax::feature_gate::UnstableFeatures;
@@ -605,8 +604,6 @@ mod $mod_desc {
         pub const parse_bool: Option<&'static str> = None;
         pub const parse_opt_bool: Option<&'static str> =
             Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
-        pub const parse_all_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_opt_string: Option<&'static str> = Some("a string");
         pub const parse_list: Option<&'static str> = Some("a space-separated list of strings");
@@ -656,25 +653,6 @@ fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
             }
         }
 
-        fn parse_all_bool(slot: &mut bool, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => {
-                    match s {
-                        "n" | "no" | "off" => {
-                            *slot = false;
-                        }
-                        "y" | "yes" | "on" => {
-                            *slot = true;
-                        }
-                        _ => { return false; }
-                    }
-
-                    true
-                },
-                None => { *slot = true; true }
-            }
-        }
-
         fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
             match v {
                 Some(s) => { *slot = Some(s.to_string()); true },
@@ -910,10 +888,10 @@ fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
           "adds unstable command line options to rustc interface"),
     force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
           "force overflow checks on or off"),
-    force_dropflag_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
-          "force drop flag checks on or off"),
     trace_macros: bool = (false, parse_bool, [UNTRACKED],
           "for every macro invocation, print its name and arguments"),
+    debug_macros: bool = (false, parse_bool, [TRACKED],
+          "emit line numbers debug info inside macros"),
     enable_nonzeroing_move_hints: bool = (false, parse_bool, [TRACKED],
           "force nonzeroing move optimization on"),
     keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
@@ -930,8 +908,6 @@ fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
           "dump MIR state at various points in translation"),
     dump_mir_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
           "the directory the MIR is dumped into"),
-    orbit: bool = (true, parse_all_bool, [UNTRACKED],
-          "get MIR where it belongs - everywhere; most importantly, in orbit"),
 }
 
 pub fn default_lib_output() -> CrateType {
@@ -1324,15 +1300,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
         })
     });
 
-    let mut debugging_opts = build_debugging_options(matches, error_format);
-
-    // Incremental compilation only works reliably when translation is done via
-    // MIR, so let's enable -Z orbit if necessary (see #34973).
-    if debugging_opts.incremental.is_some() && !debugging_opts.orbit {
-        early_warn(error_format, "Automatically enabling `-Z orbit` because \
-                                  `-Z incremental` was specified");
-        debugging_opts.orbit = true;
-    }
+    let debugging_opts = build_debugging_options(matches, error_format);
 
     let mir_opt_level = debugging_opts.mir_opt_level.unwrap_or(1);
 
@@ -1804,8 +1772,9 @@ mod tests {
     use std::path::PathBuf;
     use std::rc::Rc;
     use super::{OutputType, OutputTypes, Externs, PanicStrategy};
-    use syntax::attr;
-    use syntax::attr::AttrMetaMethods;
+    use syntax::{ast, attr};
+    use syntax::parse::token::InternedString;
+    use syntax::codemap::dummy_spanned;
 
     fn optgroups() -> Vec<OptGroup> {
         super::rustc_optgroups().into_iter()
@@ -1834,7 +1803,9 @@ fn test_switch_implies_cfg_test() {
         let (sessopts, cfg) = build_session_options_and_crate_config(matches);
         let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore));
         let cfg = build_configuration(&sess, cfg);
-        assert!((attr::contains_name(&cfg[..], "test")));
+        assert!(attr::contains(&cfg, &dummy_spanned(ast::MetaItemKind::Word({
+            InternedString::new("test")
+        }))));
     }
 
     // When the user supplies --test and --cfg test, don't implicitly add
@@ -2424,8 +2395,6 @@ fn test_debugging_options_tracking_hash() {
         assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
         opts.debugging_opts.dump_mir_dir = Some(String::from("abc"));
         assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.orbit = false;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
 
         // Make sure changing a [TRACKED] option changes the hash
         opts = reference.clone();
@@ -2460,10 +2429,6 @@ fn test_debugging_options_tracking_hash() {
         opts.debugging_opts.force_overflow_checks = Some(true);
         assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
 
-        opts = reference.clone();
-        opts.debugging_opts.force_dropflag_checks = Some(true);
-        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
         opts = reference.clone();
         opts.debugging_opts.enable_nonzeroing_move_hints = true;
         assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
index c71253aee568f9a1e0cd8dcc905557cd7fa7bb20..338c65637995919216cd0bb5148e091fe4452cd2 100644 (file)
 use syntax_pos::{Span, MultiSpan};
 
 use rustc_back::target::Target;
+use rustc_data_structures::flock;
 use llvm;
 
 use std::path::{Path, PathBuf};
-use std::cell::{Cell, RefCell};
+use std::cell::{self, Cell, RefCell};
 use std::collections::{HashMap, HashSet};
 use std::env;
 use std::ffi::CString;
@@ -101,6 +102,8 @@ pub struct Session {
     /// macro name and defintion span in the source crate.
     pub imported_macro_spans: RefCell<HashMap<Span, (String, Span)>>,
 
+    incr_comp_session: RefCell<IncrCompSession>,
+
     next_node_id: Cell<ast::NodeId>,
 }
 
@@ -331,6 +334,76 @@ pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch {
             &self.opts.search_paths,
             kind)
     }
+
+    pub fn init_incr_comp_session(&self,
+                                  session_dir: PathBuf,
+                                  lock_file: flock::Lock) {
+        let mut incr_comp_session = self.incr_comp_session.borrow_mut();
+
+        if let IncrCompSession::NotInitialized = *incr_comp_session { } else {
+            bug!("Trying to initialize IncrCompSession `{:?}`", *incr_comp_session)
+        }
+
+        *incr_comp_session = IncrCompSession::Active {
+            session_directory: session_dir,
+            lock_file: lock_file,
+        };
+    }
+
+    pub fn finalize_incr_comp_session(&self, new_directory_path: PathBuf) {
+        let mut incr_comp_session = self.incr_comp_session.borrow_mut();
+
+        if let IncrCompSession::Active { .. } = *incr_comp_session { } else {
+            bug!("Trying to finalize IncrCompSession `{:?}`", *incr_comp_session)
+        }
+
+        // Note: This will also drop the lock file, thus unlocking the directory
+        *incr_comp_session = IncrCompSession::Finalized {
+            session_directory: new_directory_path,
+        };
+    }
+
+    pub fn mark_incr_comp_session_as_invalid(&self) {
+        let mut incr_comp_session = self.incr_comp_session.borrow_mut();
+
+        let session_directory = match *incr_comp_session {
+            IncrCompSession::Active { ref session_directory, .. } => {
+                session_directory.clone()
+            }
+            _ => bug!("Trying to invalidate IncrCompSession `{:?}`",
+                      *incr_comp_session),
+        };
+
+        // Note: This will also drop the lock file, thus unlocking the directory
+        *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors {
+            session_directory: session_directory
+        };
+    }
+
+    pub fn incr_comp_session_dir(&self) -> cell::Ref<PathBuf> {
+        let incr_comp_session = self.incr_comp_session.borrow();
+        cell::Ref::map(incr_comp_session, |incr_comp_session| {
+            match *incr_comp_session {
+                IncrCompSession::NotInitialized => {
+                    bug!("Trying to get session directory from IncrCompSession `{:?}`",
+                        *incr_comp_session)
+                }
+                IncrCompSession::Active { ref session_directory, .. } |
+                IncrCompSession::Finalized { ref session_directory } |
+                IncrCompSession::InvalidBecauseOfErrors { ref session_directory } => {
+                    session_directory
+                }
+            }
+        })
+    }
+
+    pub fn incr_comp_session_dir_opt(&self) -> Option<cell::Ref<PathBuf>> {
+        if self.opts.incremental.is_some() {
+            Some(self.incr_comp_session_dir())
+        } else {
+            None
+        }
+    }
 }
 
 pub fn build_session(sopts: config::Options,
@@ -446,6 +519,7 @@ pub fn build_session_(sopts: config::Options,
         injected_panic_runtime: Cell::new(None),
         available_macros: RefCell::new(HashSet::new()),
         imported_macro_spans: RefCell::new(HashMap::new()),
+        incr_comp_session: RefCell::new(IncrCompSession::NotInitialized),
     };
 
     init_llvm(&sess);
@@ -453,6 +527,31 @@ pub fn build_session_(sopts: config::Options,
     sess
 }
 
+/// Holds data on the current incremental compilation session, if there is one.
+#[derive(Debug)]
+pub enum IncrCompSession {
+    // This is the state the session will be in until the incr. comp. dir is
+    // needed.
+    NotInitialized,
+    // This is the state during which the session directory is private and can
+    // be modified.
+    Active {
+        session_directory: PathBuf,
+        lock_file: flock::Lock,
+    },
+    // This is the state after the session directory has been finalized. In this
+    // state, the contents of the directory must not be modified any more.
+    Finalized {
+        session_directory: PathBuf,
+    },
+    // This is an error state that is reached when some compilation error has
+    // occurred. It indicates that the contents of the session directory must
+    // not be used, since they might be invalid.
+    InvalidBecauseOfErrors {
+        session_directory: PathBuf,
+    }
+}
+
 fn init_llvm(sess: &Session) {
     unsafe {
         // Before we touch LLVM, make sure that multithreading is enabled.
index 33db0053cda13547a9b33dd3a71cac10f6f958ad..6d6d7c2b3ba0a830e0237e6e44a9c41d1aeeeba5 100644 (file)
 
 use std::cmp;
 use std::fmt;
-use syntax::ast;
-use syntax::attr::{AttributeMethods, AttrMetaMethods};
 use syntax_pos::Span;
 use errors::DiagnosticBuilder;
 
 #[derive(Debug, PartialEq, Eq, Hash)]
 pub struct TraitErrorKey<'tcx> {
     span: Span,
-    warning_node_id: Option<ast::NodeId>,
     predicate: ty::Predicate<'tcx>
 }
 
 impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> {
     fn from_error(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                  e: &FulfillmentError<'tcx>,
-                  warning_node_id: Option<ast::NodeId>) -> Self {
+                  e: &FulfillmentError<'tcx>) -> Self {
         let predicate =
             infcx.resolve_type_vars_if_possible(&e.obligation.predicate);
         TraitErrorKey {
             span: e.obligation.cause.span,
-            predicate: infcx.tcx.erase_regions(&predicate),
-            warning_node_id: warning_node_id
+            predicate: infcx.tcx.erase_regions(&predicate)
         }
     }
 }
@@ -65,22 +60,13 @@ fn from_error(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     pub fn report_fulfillment_errors(&self, errors: &Vec<FulfillmentError<'tcx>>) {
         for error in errors {
-            self.report_fulfillment_error(error, None);
-        }
-    }
-
-    pub fn report_fulfillment_errors_as_warnings(&self,
-                                                 errors: &Vec<FulfillmentError<'tcx>>,
-                                                 node_id: ast::NodeId) {
-        for error in errors {
-            self.report_fulfillment_error(error, Some(node_id));
+            self.report_fulfillment_error(error);
         }
     }
 
     fn report_fulfillment_error(&self,
-                                error: &FulfillmentError<'tcx>,
-                                warning_node_id: Option<ast::NodeId>) {
-        let error_key = TraitErrorKey::from_error(self, error, warning_node_id);
+                                error: &FulfillmentError<'tcx>) {
+        let error_key = TraitErrorKey::from_error(self, error);
         debug!("report_fulfillment_errors({:?}) - key={:?}",
                error, error_key);
         if !self.reported_trait_errors.borrow_mut().insert(error_key) {
@@ -89,10 +75,10 @@ fn report_fulfillment_error(&self,
         }
         match error.code {
             FulfillmentErrorCode::CodeSelectionError(ref e) => {
-                self.report_selection_error(&error.obligation, e, warning_node_id);
+                self.report_selection_error(&error.obligation, e);
             }
             FulfillmentErrorCode::CodeProjectionError(ref e) => {
-                self.report_projection_error(&error.obligation, e, warning_node_id);
+                self.report_projection_error(&error.obligation, e);
             }
             FulfillmentErrorCode::CodeAmbiguity => {
                 self.maybe_report_ambiguity(&error.obligation);
@@ -102,8 +88,7 @@ fn report_fulfillment_error(&self,
 
     fn report_projection_error(&self,
                                obligation: &PredicateObligation<'tcx>,
-                               error: &MismatchedProjectionTypes<'tcx>,
-                               warning_node_id: Option<ast::NodeId>)
+                               error: &MismatchedProjectionTypes<'tcx>)
     {
         let predicate =
             self.resolve_type_vars_if_possible(&obligation.predicate);
@@ -111,16 +96,7 @@ fn report_projection_error(&self,
         if predicate.references_error() {
             return
         }
-        if let Some(warning_node_id) = warning_node_id {
-            self.tcx.sess.add_lint(
-                ::lint::builtin::UNSIZED_IN_TUPLE,
-                warning_node_id,
-                obligation.cause.span,
-                format!("type mismatch resolving `{}`: {}",
-                        predicate,
-                        error.err));
-            return
-        }
+
         self.probe(|_| {
             let origin = TypeOrigin::Misc(obligation.cause.span);
             let err_buf;
@@ -161,7 +137,7 @@ fn report_projection_error(&self,
                 self.tcx.sess, origin.span(), E0271,
                 "type mismatch resolving `{}`", predicate
             );
-            self.note_type_err(&mut diag, origin, values, err);
+            self.note_type_err(&mut diag, origin, None, values, err);
             self.note_obligation_cause(&mut diag, obligation);
             diag.emit();
         });
@@ -232,8 +208,8 @@ fn impl_similar_to(&self,
                 if let Ok(..) = self.can_equate(&trait_self_ty, &impl_self_ty) {
                     self_match_impls.push(def_id);
 
-                    if trait_ref.substs.types[1..].iter()
-                        .zip(&impl_trait_ref.substs.types[1..])
+                    if trait_ref.substs.types().skip(1)
+                        .zip(impl_trait_ref.substs.types().skip(1))
                         .all(|(u,v)| self.fuzzy_match_tys(u, v))
                     {
                         fuzzy_match_impls.push(def_id);
@@ -443,8 +419,7 @@ pub fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -
 
     pub fn report_selection_error(&self,
                                   obligation: &PredicateObligation<'tcx>,
-                                  error: &SelectionError<'tcx>,
-                                  warning_node_id: Option<ast::NodeId>)
+                                  error: &SelectionError<'tcx>)
     {
         let span = obligation.cause.span;
         let mut err = match *error {
@@ -467,20 +442,11 @@ pub fn report_selection_error(&self,
                             } else {
                                 let trait_ref = trait_predicate.to_poly_trait_ref();
 
-                                if let Some(warning_node_id) = warning_node_id {
-                                    self.tcx.sess.add_lint(
-                                        ::lint::builtin::UNSIZED_IN_TUPLE,
-                                        warning_node_id,
-                                        obligation.cause.span,
-                                        format!("the trait bound `{}` is not satisfied",
-                                                trait_ref.to_predicate()));
-                                    return;
-                                }
-
-                                let mut err = struct_span_err!(
-                                    self.tcx.sess, span, E0277,
+                                let mut err = struct_span_err!(self.tcx.sess, span, E0277,
                                     "the trait bound `{}` is not satisfied",
                                     trait_ref.to_predicate());
+                                err.span_label(span, &format!("trait `{}` not satisfied",
+                                                              trait_ref.to_predicate()));
 
                                 // Try to report a help message
 
@@ -541,15 +507,9 @@ pub fn report_selection_error(&self,
 
                         ty::Predicate::ObjectSafe(trait_def_id) => {
                             let violations = self.tcx.object_safety_violations(trait_def_id);
-                            let err = self.tcx.report_object_safety_error(span,
-                                                                          trait_def_id,
-                                                                          warning_node_id,
-                                                                          violations);
-                            if let Some(err) = err {
-                                err
-                            } else {
-                                return;
-                            }
+                            self.tcx.report_object_safety_error(span,
+                                                                trait_def_id,
+                                                                violations)
                         }
 
                         ty::Predicate::ClosureKind(closure_def_id, kind) => {
@@ -577,13 +537,6 @@ pub fn report_selection_error(&self,
                             // (which may fail).
                             span_bug!(span, "WF predicate not satisfied for {:?}", ty);
                         }
-
-                        ty::Predicate::Rfc1592(ref data) => {
-                            span_bug!(
-                                obligation.cause.span,
-                                "RFC1592 predicate not satisfied for {:?}",
-                                data);
-                        }
                     }
                 }
             }
@@ -605,14 +558,8 @@ pub fn report_selection_error(&self,
 
             TraitNotObjectSafe(did) => {
                 let violations = self.tcx.object_safety_violations(did);
-                let err = self.tcx.report_object_safety_error(span, did,
-                                                              warning_node_id,
-                                                              violations);
-                if let Some(err) = err {
-                    err
-                } else {
-                    return;
-                }
+                self.tcx.report_object_safety_error(span, did,
+                                                    violations)
             }
         };
         self.note_obligation_cause(&mut err, obligation);
@@ -640,24 +587,17 @@ pub fn recursive_type_with_infinite_size_error(self,
     pub fn report_object_safety_error(self,
                                       span: Span,
                                       trait_def_id: DefId,
-                                      warning_node_id: Option<ast::NodeId>,
                                       violations: Vec<ObjectSafetyViolation>)
-                                      -> Option<DiagnosticBuilder<'tcx>>
+                                      -> DiagnosticBuilder<'tcx>
     {
-        let mut err = match warning_node_id {
-            Some(_) => None,
-            None => {
-                let trait_str = self.item_path_str(trait_def_id);
-                let mut db = struct_span_err!(
-                            self.sess, span, E0038,
-                            "the trait `{}` cannot be made into an object",
-                            trait_str);
-                db.span_label(span,
-                              &format!("the trait `{}` cannot be made \
-                              into an object", trait_str));
-                Some(db)
-            }
-        };
+        let trait_str = self.item_path_str(trait_def_id);
+        let mut err = struct_span_err!(
+            self.sess, span, E0038,
+            "the trait `{}` cannot be made into an object",
+            trait_str);
+        err.span_label(span, &format!(
+            "the trait `{}` cannot be made into an object", trait_str
+        ));
 
         let mut reported_violations = FnvHashSet();
         for violation in violations {
@@ -697,19 +637,7 @@ pub fn report_object_safety_error(self,
                     &buf
                 }
             };
-            match (warning_node_id, &mut err) {
-                (Some(node_id), &mut None) => {
-                    self.sess.add_lint(
-                        ::lint::builtin::OBJECT_UNSAFE_FRAGMENT,
-                        node_id,
-                        span,
-                        note.to_string());
-                }
-                (None, &mut Some(ref mut err)) => {
-                    err.note(note);
-                }
-                _ => unreachable!()
-            }
+            err.note(note);
         }
         err
     }
@@ -738,8 +666,7 @@ fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) {
             ty::Predicate::Trait(ref data) => {
                 let trait_ref = data.to_poly_trait_ref();
                 let self_ty = trait_ref.self_ty();
-                let all_types = &trait_ref.substs().types;
-                if all_types.references_error() {
+                if predicate.references_error() {
                 } else {
                     // Typically, this ambiguity should only happen if
                     // there are unresolved type inference variables
index 837e33b3e7fc2798e2c27af83265ef52845afa17..65860671c4c636c331fd87d56525a9489966b60a 100644 (file)
@@ -57,9 +57,6 @@ pub struct FulfillmentContext<'tcx> {
     // fulfillment context.
     predicates: ObligationForest<PendingPredicateObligation<'tcx>>,
 
-    // A list of new obligations due to RFC1592.
-    rfc1592_obligations: Vec<PredicateObligation<'tcx>>,
-
     // A set of constraints that regionck must validate. Each
     // constraint has the form `T:'a`, meaning "some type `T` must
     // outlive the lifetime 'a". These constraints derive from
@@ -93,7 +90,7 @@ pub struct FulfillmentContext<'tcx> {
 
 #[derive(Clone)]
 pub struct RegionObligation<'tcx> {
-    pub sub_region: ty::Region,
+    pub sub_region: &'tcx ty::Region,
     pub sup_type: Ty<'tcx>,
     pub cause: ObligationCause<'tcx>,
 }
@@ -142,7 +139,7 @@ pub fn must_defer(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         // Auto trait obligations on `impl Trait`.
         if tcx.trait_has_default_impl(predicate.def_id()) {
             let substs = predicate.skip_binder().trait_ref.substs;
-            if substs.types.len() == 1 && substs.regions.is_empty() {
+            if substs.types().count() == 1 && substs.regions().next().is_none() {
                 if let ty::TyAnon(..) = predicate.skip_binder().self_ty().sty {
                     return true;
                 }
@@ -162,7 +159,7 @@ pub fn try_select(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
                 let concrete_ty = ty_scheme.ty.subst(tcx, substs);
                 let predicate = ty::TraitRef {
                     def_id: self.predicate.def_id(),
-                    substs: Substs::new_trait(tcx, vec![], vec![], concrete_ty)
+                    substs: Substs::new_trait(tcx, concrete_ty, &[])
                 }.to_predicate();
 
                 let original_obligation = Obligation::new(self.cause.clone(),
@@ -192,7 +189,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
     pub fn new() -> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
-            rfc1592_obligations: Vec::new(),
             region_obligations: NodeMap(),
             deferred_obligations: vec![],
         }
@@ -246,7 +242,7 @@ pub fn register_builtin_bound(&mut self,
 
     pub fn register_region_obligation(&mut self,
                                       t_a: Ty<'tcx>,
-                                      r_b: ty::Region,
+                                      r_b: &'tcx ty::Region,
                                       cause: ObligationCause<'tcx>)
     {
         register_region_obligation(t_a, r_b, cause, &mut self.region_obligations);
@@ -275,13 +271,6 @@ pub fn register_predicate_obligation(&mut self,
         });
     }
 
-    pub fn register_rfc1592_obligation(&mut self,
-                                       _infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                       obligation: PredicateObligation<'tcx>)
-    {
-        self.rfc1592_obligations.push(obligation);
-    }
-
     pub fn region_obligations(&self,
                               body_id: ast::NodeId)
                               -> &[RegionObligation<'tcx>]
@@ -292,21 +281,6 @@ pub fn region_obligations(&self,
         }
     }
 
-    pub fn select_rfc1592_obligations(&mut self,
-                                      infcx: &InferCtxt<'a, 'gcx, 'tcx>)
-                                      -> Result<(),Vec<FulfillmentError<'tcx>>>
-    {
-        while !self.rfc1592_obligations.is_empty() {
-            for obligation in mem::replace(&mut self.rfc1592_obligations, Vec::new()) {
-                self.register_predicate_obligation(infcx, obligation);
-            }
-
-            self.select_all_or_error(infcx)?;
-        }
-
-        Ok(())
-    }
-
     pub fn select_all_or_error(&mut self,
                                infcx: &InferCtxt<'a, 'gcx, 'tcx>)
                                -> Result<(),Vec<FulfillmentError<'tcx>>>
@@ -362,7 +336,6 @@ fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>)
             let outcome = self.predicates.process_obligations(&mut FulfillProcessor {
                 selcx: selcx,
                 region_obligations: &mut self.region_obligations,
-                rfc1592_obligations: &mut self.rfc1592_obligations,
                 deferred_obligations: &mut self.deferred_obligations
             });
             debug!("select: outcome={:?}", outcome);
@@ -398,7 +371,6 @@ fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>)
 struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> {
     selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
     region_obligations: &'a mut NodeMap<Vec<RegionObligation<'tcx>>>,
-    rfc1592_obligations: &'a mut Vec<PredicateObligation<'tcx>>,
     deferred_obligations: &'a mut Vec<DeferredObligation<'tcx>>
 }
 
@@ -413,7 +385,6 @@ fn process_obligation(&mut self,
         process_predicate(self.selcx,
                           obligation,
                           self.region_obligations,
-                          self.rfc1592_obligations,
                           self.deferred_obligations)
             .map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation {
                 obligation: o,
@@ -440,8 +411,7 @@ fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 't
 {
     t.skip_binder() // ok b/c this check doesn't care about regions
      .input_types()
-     .iter()
-     .map(|t| selcx.infcx().resolve_type_vars_if_possible(t))
+     .map(|t| selcx.infcx().resolve_type_vars_if_possible(&t))
      .filter(|t| t.has_infer_types())
      .flat_map(|t| t.walk())
      .filter(|t| match t.sty { ty::TyInfer(_) => true, _ => false })
@@ -456,7 +426,6 @@ fn process_predicate<'a, 'gcx, 'tcx>(
     selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
     pending_obligation: &mut PendingPredicateObligation<'tcx>,
     region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>,
-    rfc1592_obligations: &mut Vec<PredicateObligation<'tcx>>,
     deferred_obligations: &mut Vec<DeferredObligation<'tcx>>)
     -> Result<Option<Vec<PredicateObligation<'tcx>>>,
               FulfillmentErrorCode<'tcx>>
@@ -581,7 +550,8 @@ fn process_predicate<'a, 'gcx, 'tcx>(
                         // Otherwise, we have something of the form
                         // `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`.
                         Some(t_a) => {
-                            register_region_obligation(t_a, ty::ReStatic,
+                            let r_static = selcx.tcx().mk_region(ty::ReStatic);
+                            register_region_obligation(t_a, r_static,
                                                        obligation.cause.clone(),
                                                        region_obligations);
                             Ok(Some(vec![]))
@@ -644,14 +614,6 @@ fn process_predicate<'a, 'gcx, 'tcx>(
                 s => Ok(s)
             }
         }
-
-        ty::Predicate::Rfc1592(ref inner) => {
-            rfc1592_obligations.push(PredicateObligation {
-                predicate: ty::Predicate::clone(inner),
-                ..obligation.clone()
-            });
-            Ok(Some(vec![]))
-        }
     }
 }
 
@@ -691,7 +653,7 @@ fn coinductive_obligation<'a,'gcx,'tcx>(selcx: &SelectionContext<'a,'gcx,'tcx>,
 }
 
 fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
-                                    r_b: ty::Region,
+                                    r_b: &'tcx ty::Region,
                                     cause: ObligationCause<'tcx>,
                                     region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
 {
index 25d2df8fdedb39a0a260703315e9fee84cc4bcc1..5f7b71518291a1f932729f690d1975ea9c4c5a37 100644 (file)
@@ -145,7 +145,7 @@ fn supertraits_reference_self(self, trait_def_id: DefId) -> bool {
                 match predicate {
                     ty::Predicate::Trait(ref data) => {
                         // In the case of a trait predicate, we can skip the "self" type.
-                        data.0.trait_ref.input_types()[1..].iter().any(|t| t.has_self_ty())
+                        data.skip_binder().input_types().skip(1).any(|t| t.has_self_ty())
                     }
                     ty::Predicate::Projection(..) |
                     ty::Predicate::WellFormed(..) |
@@ -153,7 +153,6 @@ fn supertraits_reference_self(self, trait_def_id: DefId) -> bool {
                     ty::Predicate::TypeOutlives(..) |
                     ty::Predicate::RegionOutlives(..) |
                     ty::Predicate::ClosureKind(..) |
-                    ty::Predicate::Rfc1592(..) |
                     ty::Predicate::Equate(..) => {
                         false
                     }
@@ -184,7 +183,6 @@ fn generics_require_sized_self(self, def_id: DefId) -> bool {
                     }
                     ty::Predicate::Projection(..) |
                     ty::Predicate::Trait(..) |
-                    ty::Predicate::Rfc1592(..) |
                     ty::Predicate::Equate(..) |
                     ty::Predicate::RegionOutlives(..) |
                     ty::Predicate::WellFormed(..) |
index 9ea738bd326eb7f18bf75d468433e935cc2c3989..0573f0c5bbaa0b144b49ce6ad7b2e1f0a4e090fc 100644 (file)
@@ -36,7 +36,7 @@
 use hir::def_id::DefId;
 use infer;
 use infer::{InferCtxt, InferOk, TypeFreshener, TypeOrigin};
-use ty::subst::{Subst, Substs};
+use ty::subst::{Kind, Subst, Substs};
 use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
 use traits;
 use ty::fast_reject;
@@ -513,8 +513,6 @@ fn evaluate_predicate_recursively<'o>(&mut self,
         }
 
         match obligation.predicate {
-            ty::Predicate::Rfc1592(..) => EvaluatedToOk,
-
             ty::Predicate::Trait(ref t) => {
                 assert!(!t.has_escaping_regions());
                 let obligation = obligation.with(t.clone());
@@ -644,8 +642,7 @@ fn evaluate_stack<'o>(&mut self,
         // This suffices to allow chains like `FnMut` implemented in
         // terms of `Fn` etc, but we could probably make this more
         // precise still.
-        let input_types = stack.fresh_trait_ref.0.input_types();
-        let unbound_input_types = input_types.iter().any(|ty| ty.is_fresh());
+        let unbound_input_types = stack.fresh_trait_ref.input_types().any(|ty| ty.is_fresh());
         if unbound_input_types && self.intercrate {
             debug!("evaluate_stack({:?}) --> unbound argument, intercrate -->  ambiguous",
                    stack.fresh_trait_ref);
@@ -1064,9 +1061,7 @@ fn should_update_candidate_cache(&mut self,
 
         match *candidate {
             Ok(Some(_)) | Err(_) => true,
-            Ok(None) => {
-                cache_fresh_trait_pred.0.trait_ref.substs.types.has_infer_types()
-            }
+            Ok(None) => cache_fresh_trait_pred.has_infer_types()
         }
     }
 
@@ -1250,7 +1245,7 @@ fn match_projection(&mut self,
                         obligation: &TraitObligation<'tcx>,
                         trait_bound: ty::PolyTraitRef<'tcx>,
                         skol_trait_ref: ty::TraitRef<'tcx>,
-                        skol_map: &infer::SkolemizationMap,
+                        skol_map: &infer::SkolemizationMap<'tcx>,
                         snapshot: &infer::CombinedSnapshot)
                         -> bool
     {
@@ -1603,7 +1598,7 @@ fn assemble_candidates_for_unsizing(&mut self,
                 return;
             }
         };
-        let target = obligation.predicate.skip_binder().input_types()[1];
+        let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
 
         debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})",
                source, target);
@@ -1782,8 +1777,7 @@ fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
             ty::TyStr | ty::TySlice(_) | ty::TyTrait(..) => Never,
 
             ty::TyTuple(tys) => {
-                // FIXME(#33242) we only need to constrain the last field
-                Where(ty::Binder(tys.to_vec()))
+                Where(ty::Binder(tys.last().into_iter().cloned().collect()))
             }
 
             ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
@@ -1936,7 +1930,7 @@ fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> {
 
             // for `PhantomData<T>`, we pass `T`
             ty::TyStruct(def, substs) if def.is_phantom_data() => {
-                substs.types.to_vec()
+                substs.types().collect()
             }
 
             ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
@@ -1985,7 +1979,7 @@ fn collect_predicates_for_types(&mut self,
                                                   trait_def_id,
                                                   recursion_depth,
                                                   normalized_ty,
-                                                  vec![]);
+                                                  &[]);
                 obligations.push(skol_obligation);
                 this.infcx().plug_leaks(skol_map, snapshot, &obligations)
             })
@@ -2180,12 +2174,11 @@ fn confirm_default_impl_object_candidate(&mut self,
         match self_ty.sty {
             ty::TyTrait(ref data) => {
                 // OK to skip the binder, it is reintroduced below
-                let input_types = data.principal.skip_binder().input_types();
+                let input_types = data.principal.input_types();
                 let assoc_types = data.projection_bounds.iter()
                                       .map(|pb| pb.skip_binder().ty);
-                let all_types: Vec<_> = input_types.iter().cloned()
-                                                          .chain(assoc_types)
-                                                          .collect();
+                let all_types: Vec<_> = input_types.chain(assoc_types)
+                                                   .collect();
 
                 // reintroduce the two binding levels we skipped, then flatten into one
                 let all_types = ty::Binder(ty::Binder(all_types));
@@ -2267,7 +2260,7 @@ fn vtable_impl(&mut self,
                    mut substs: Normalized<'tcx, &'tcx Substs<'tcx>>,
                    cause: ObligationCause<'tcx>,
                    recursion_depth: usize,
-                   skol_map: infer::SkolemizationMap,
+                   skol_map: infer::SkolemizationMap<'tcx>,
                    snapshot: &infer::CombinedSnapshot)
                    -> VtableImplData<'tcx, PredicateObligation<'tcx>>
     {
@@ -2476,7 +2469,7 @@ fn confirm_builtin_unsize_candidate(&mut self,
         // regions here. See the comment there for more details.
         let source = self.infcx.shallow_resolve(
             tcx.no_late_bound_regions(&obligation.self_ty()).unwrap());
-        let target = obligation.predicate.skip_binder().input_types()[1];
+        let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
         let target = self.infcx.shallow_resolve(target);
 
         debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})",
@@ -2512,12 +2505,11 @@ fn confirm_builtin_unsize_candidate(&mut self,
 
             // T -> Trait.
             (_, &ty::TyTrait(ref data)) => {
-                let mut object_dids = Some(data.principal.def_id()).into_iter();
-                // FIXME(#33243)
-//                    data.builtin_bounds.iter().flat_map(|bound| {
-//                        tcx.lang_items.from_builtin_kind(bound).ok()
-//                    })
-//                    .chain(Some(data.principal.def_id()));
+                let mut object_dids =
+                    data.builtin_bounds.iter().flat_map(|bound| {
+                        tcx.lang_items.from_builtin_kind(bound).ok()
+                    })
+                    .chain(Some(data.principal.def_id()));
                 if let Some(did) = object_dids.find(|did| {
                     !tcx.is_object_safe(*did)
                 }) {
@@ -2585,7 +2577,7 @@ fn confirm_builtin_unsize_candidate(&mut self,
                 } else {
                     return Err(Unimplemented);
                 };
-                let mut ty_params = BitVector::new(substs_a.types.len());
+                let mut ty_params = BitVector::new(substs_a.types().count());
                 let mut found = false;
                 for ty in field.walk() {
                     if let ty::TyParam(p) = ty.sty {
@@ -2601,14 +2593,14 @@ fn confirm_builtin_unsize_candidate(&mut self,
                 // TyError and ensure they do not affect any other fields.
                 // This could be checked after type collection for any struct
                 // with a potentially unsized trailing field.
-                let types = substs_a.types.iter().enumerate().map(|(i, ty)| {
+                let params = substs_a.params().iter().enumerate().map(|(i, &k)| {
                     if ty_params.contains(i) {
-                        tcx.types.err
+                        Kind::from(tcx.types.err)
                     } else {
-                        ty
+                        k
                     }
-                }).collect();
-                let substs = Substs::new(tcx, types, substs_a.regions.clone());
+                });
+                let substs = Substs::new(tcx, params);
                 for &ty in fields.split_last().unwrap().1 {
                     if ty.subst(tcx, substs).references_error() {
                         return Err(Unimplemented);
@@ -2621,15 +2613,14 @@ fn confirm_builtin_unsize_candidate(&mut self,
 
                 // Check that the source structure with the target's
                 // type parameters is a subtype of the target.
-                let types = substs_a.types.iter().enumerate().map(|(i, ty)| {
+                let params = substs_a.params().iter().enumerate().map(|(i, &k)| {
                     if ty_params.contains(i) {
-                        substs_b.types[i]
+                        Kind::from(substs_b.type_at(i))
                     } else {
-                        ty
+                        k
                     }
-                }).collect();
-                let substs = Substs::new(tcx, types, substs_a.regions.clone());
-                let new_struct = tcx.mk_struct(def, substs);
+                });
+                let new_struct = tcx.mk_struct(def, Substs::new(tcx, params));
                 let origin = TypeOrigin::Misc(obligation.cause.span);
                 let InferOk { obligations, .. } =
                     self.infcx.sub_types(false, origin, new_struct, target)
@@ -2642,7 +2633,7 @@ fn confirm_builtin_unsize_candidate(&mut self,
                     obligation.predicate.def_id(),
                     obligation.recursion_depth + 1,
                     inner_source,
-                    vec![inner_target]));
+                    &[inner_target]));
             }
 
             _ => bug!()
@@ -2665,7 +2656,8 @@ fn rematch_impl(&mut self,
                     impl_def_id: DefId,
                     obligation: &TraitObligation<'tcx>,
                     snapshot: &infer::CombinedSnapshot)
-                    -> (Normalized<'tcx, &'tcx Substs<'tcx>>, infer::SkolemizationMap)
+                    -> (Normalized<'tcx, &'tcx Substs<'tcx>>,
+                        infer::SkolemizationMap<'tcx>)
     {
         match self.match_impl(impl_def_id, obligation, snapshot) {
             Ok((substs, skol_map)) => (substs, skol_map),
@@ -2682,7 +2674,7 @@ fn match_impl(&mut self,
                   obligation: &TraitObligation<'tcx>,
                   snapshot: &infer::CombinedSnapshot)
                   -> Result<(Normalized<'tcx, &'tcx Substs<'tcx>>,
-                             infer::SkolemizationMap), ()>
+                             infer::SkolemizationMap<'tcx>), ()>
     {
         let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
 
@@ -2753,9 +2745,9 @@ fn fast_reject_trait_refs(&mut self,
         // substitution if we find that any of the input types, when
         // simplified, do not match.
 
-        obligation.predicate.0.input_types().iter()
+        obligation.predicate.skip_binder().input_types()
             .zip(impl_trait_ref.input_types())
-            .any(|(&obligation_ty, &impl_ty)| {
+            .any(|(obligation_ty, impl_ty)| {
                 let simplified_obligation_ty =
                     fast_reject::simplify_type(self.tcx(), obligation_ty, true);
                 let simplified_impl_ty =
@@ -2875,7 +2867,7 @@ fn impl_or_trait_obligations(&mut self,
                                  recursion_depth: usize,
                                  def_id: DefId, // of impl or trait
                                  substs: &Substs<'tcx>, // for impl or trait
-                                 skol_map: infer::SkolemizationMap,
+                                 skol_map: infer::SkolemizationMap<'tcx>,
                                  snapshot: &infer::CombinedSnapshot)
                                  -> Vec<PredicateObligation<'tcx>>
     {
index 9acfe2754820c9bea7f6988149bd1821d0261f61..f3ba4d16eb0b2f2f72914a06ca1b5484d041dd90 100644 (file)
@@ -147,7 +147,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              .unwrap()
                              .subst(tcx, &penv.free_substs);
 
-    let result = tcx.normalizing_infer_ctxt(Reveal::ExactMatch).enter(|mut infcx| {
+    let result = tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|mut infcx| {
         // Normalize the trait reference, adding any obligations
         // that arise into the impl1 assumptions.
         let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
@@ -207,24 +207,27 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
     for oblig in obligations.into_iter() {
         fulfill_cx.register_predicate_obligation(&infcx, oblig);
     }
+    match fulfill_cx.select_all_or_error(infcx) {
+        Err(errors) => {
+            // no dice!
+            debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \
+                    {:?}",
+                   source_trait_ref,
+                   target_trait_ref,
+                   errors,
+                   infcx.parameter_environment.caller_bounds);
+            Err(())
+        }
 
-    if let Err(errors) = infcx.drain_fulfillment_cx(&mut fulfill_cx, &()) {
-        // no dice!
-        debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \
-                {:?}",
-               source_trait_ref,
-               target_trait_ref,
-               errors,
-               infcx.parameter_environment.caller_bounds);
-        Err(())
-    } else {
-        debug!("fulfill_implication: an impl for {:?} specializes {:?}",
-               source_trait_ref,
-               target_trait_ref);
+        Ok(()) => {
+            debug!("fulfill_implication: an impl for {:?} specializes {:?}",
+                   source_trait_ref,
+                   target_trait_ref);
 
-        // Now resolve the *substitution* we built for the target earlier, replacing
-        // the inference variables inside with whatever we got from fulfillment.
-        Ok(infcx.resolve_type_vars_if_possible(&target_substs))
+            // Now resolve the *substitution* we built for the target earlier, replacing
+            // the inference variables inside with whatever we got from fulfillment.
+            Ok(infcx.resolve_type_vars_if_possible(&target_substs))
+        }
     }
 }
 
index 1954ce1993c5e0d71eeb5e604ed6606c68c9f204..2cefc2ad79646730cc9b9e07e3cc7be784fc6680 100644 (file)
@@ -23,9 +23,6 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         ty::Predicate::Trait(ref data) =>
             ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)),
 
-        ty::Predicate::Rfc1592(ref data) =>
-            ty::Predicate::Rfc1592(Box::new(anonymize_predicate(tcx, data))),
-
         ty::Predicate::Equate(ref data) =>
             ty::Predicate::Equate(tcx.anonymize_late_bound_regions(data)),
 
@@ -150,9 +147,6 @@ fn push(&mut self, predicate: &ty::Predicate<'tcx>) {
 
                 self.stack.extend(predicates);
             }
-            ty::Predicate::Rfc1592(..) => {
-                // Nothing to elaborate.
-            }
             ty::Predicate::WellFormed(..) => {
                 // Currently, we do not elaborate WF predicates,
                 // although we easily could.
@@ -386,7 +380,7 @@ pub fn trait_ref_for_builtin_bound(self,
             Ok(def_id) => {
                 Ok(ty::TraitRef {
                     def_id: def_id,
-                    substs: Substs::new_trait(self, vec![], vec![], param_ty)
+                    substs: Substs::new_trait(self, param_ty, &[])
                 })
             }
             Err(e) => {
@@ -401,12 +395,12 @@ pub fn predicate_for_trait_def(self,
         trait_def_id: DefId,
         recursion_depth: usize,
         param_ty: Ty<'tcx>,
-        ty_params: Vec<Ty<'tcx>>)
+        ty_params: &[Ty<'tcx>])
         -> PredicateObligation<'tcx>
     {
         let trait_ref = ty::TraitRef {
             def_id: trait_def_id,
-            substs: Substs::new_trait(self, ty_params, vec![], param_ty)
+            substs: Substs::new_trait(self, param_ty, ty_params)
         };
         predicate_for_trait_ref(cause, trait_ref, recursion_depth)
     }
@@ -496,7 +490,7 @@ pub fn closure_trait_ref_and_return_type(self,
         };
         let trait_ref = ty::TraitRef {
             def_id: fn_trait_def_id,
-            substs: Substs::new_trait(self, vec![arguments_tuple], vec![], self_ty),
+            substs: Substs::new_trait(self, self_ty, &[arguments_tuple]),
         };
         ty::Binder((trait_ref, sig.0.output))
     }
index 39dba57c47b7c855fe1bf6cad60dc778dad0aa6c..b1846e03941489cafc665f586ccb687d39a458d9 100644 (file)
@@ -52,7 +52,8 @@ fn relate_with_variance<T: Relate<'tcx>>(&mut self,
         self.relate(a, b)
     }
 
-    fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+    fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
+               -> RelateResult<'tcx, &'tcx ty::Region> {
         debug!("{}.regions({:?}, {:?})",
                self.tag(),
                a,
index 3501dd484608786b7a7a3403eae02852a0e9ca18..e048e618e84d66951cd38467f3b9b0c0d2037f2c 100644 (file)
@@ -213,7 +213,7 @@ pub struct Tables<'tcx> {
     pub method_map: ty::MethodMap<'tcx>,
 
     /// Borrows
-    pub upvar_capture_map: ty::UpvarCaptureMap,
+    pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
 
     /// Records the type of each closure. The def ID is the ID of the
     /// expression defining the closure.
@@ -1152,12 +1152,17 @@ fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool {
 impl_interners!('tcx,
     type_list: mk_type_list(Vec<Ty<'tcx>>, keep_local) -> [Ty<'tcx>],
     substs: mk_substs(Substs<'tcx>, |substs: &Substs| {
-        keep_local(&substs.types) || keep_local(&substs.regions)
+        substs.params().iter().any(keep_local)
     }) -> Substs<'tcx>,
     bare_fn: mk_bare_fn(BareFnTy<'tcx>, |fty: &BareFnTy| {
         keep_local(&fty.sig)
     }) -> BareFnTy<'tcx>,
-    region: mk_region(Region, keep_local) -> Region
+    region: mk_region(Region, |r| {
+        match r {
+            &ty::ReVar(_) | &ty::ReSkolemized(..) => true,
+            _ => false
+        }
+    }) -> Region
 );
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
index 17f9b6c25995c48bc1d6f4e72677dd8068debcd2..3d60d326b2b0f640f477f4436a60a6b50cf18ea0 100644 (file)
@@ -41,11 +41,11 @@ pub enum TypeError<'tcx> {
     FixedArraySize(ExpectedFound<usize>),
     TyParamSize(ExpectedFound<usize>),
     ArgCount,
-    RegionsDoesNotOutlive(Region, Region),
-    RegionsNotSame(Region, Region),
-    RegionsNoOverlap(Region, Region),
-    RegionsInsufficientlyPolymorphic(BoundRegion, Region),
-    RegionsOverlyPolymorphic(BoundRegion, Region),
+    RegionsDoesNotOutlive(&'tcx Region, &'tcx Region),
+    RegionsNotSame(&'tcx Region, &'tcx Region),
+    RegionsNoOverlap(&'tcx Region, &'tcx Region),
+    RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region),
+    RegionsOverlyPolymorphic(BoundRegion, &'tcx Region),
     Sorts(ExpectedFound<Ty<'tcx>>),
     IntegerAsChar,
     IntMismatch(ExpectedFound<ty::IntVarValue>),
@@ -98,9 +98,9 @@ fn report_maybe_different(f: &mut fmt::Formatter,
                        values.expected,
                        values.found)
             }
-            Mutability => write!(f, "values differ in mutability"),
+            Mutability => write!(f, "types differ in mutability"),
             BoxMutability => {
-                write!(f, "boxed values differ in mutability")
+                write!(f, "boxed types differ in mutability")
             }
             VecMutability => write!(f, "vectors differ in mutability"),
             PtrMutability => write!(f, "pointers differ in mutability"),
@@ -296,7 +296,7 @@ pub fn note_and_explain_type_err(self,
                 self.note_and_explain_region(db, "concrete lifetime that was found is ",
                                            conc_region, "");
             }
-            RegionsOverlyPolymorphic(_, ty::ReVar(_)) => {
+            RegionsOverlyPolymorphic(_, &ty::ReVar(_)) => {
                 // don't bother to print out the message below for
                 // inference variables, it's not very illuminating.
             }
index c6c37296e9e1242f82ace140e67d388dd8992e9d..1afd49ab47fbfeb686252bb807173bac5fc2a248 100644 (file)
@@ -137,7 +137,7 @@ fn add_sty(&mut self, st: &ty::TypeVariants) {
             }
 
             &ty::TyRef(r, ref m) => {
-                self.add_region(*r);
+                self.add_region(r);
                 self.add_ty(m.ty);
             }
 
@@ -176,8 +176,8 @@ fn add_fn_sig(&mut self, fn_sig: &ty::PolyFnSig) {
         self.add_bound_computation(&computation);
     }
 
-    fn add_region(&mut self, r: ty::Region) {
-        match r {
+    fn add_region(&mut self, r: &ty::Region) {
+        match *r {
             ty::ReVar(..) => {
                 self.add_flags(TypeFlags::HAS_RE_INFER);
                 self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX);
@@ -208,8 +208,11 @@ fn add_projection_ty(&mut self, projection_ty: &ty::ProjectionTy) {
     }
 
     fn add_substs(&mut self, substs: &Substs) {
-        self.add_tys(&substs.types);
-        for &r in &substs.regions {
+        for ty in substs.types() {
+            self.add_ty(ty);
+        }
+
+        for r in substs.regions() {
             self.add_region(r);
         }
     }
index 2e114a801d6ed4a86de846ab4c286ef6bd93e416..2c18d1d52547f2acd0e0fb10ce6330c51c7f320f 100644 (file)
@@ -169,7 +169,7 @@ fn fold_closure_ty(&mut self,
         fty.super_fold_with(self)
     }
 
-    fn fold_region(&mut self, r: ty::Region) -> ty::Region {
+    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
         r.super_fold_with(self)
     }
 
@@ -188,7 +188,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
         t.super_visit_with(self)
     }
 
-    fn visit_region(&mut self, r: ty::Region) -> bool {
+    fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
         r.super_visit_with(self)
     }
 }
@@ -222,13 +222,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// whether any late-bound regions were skipped
     pub fn collect_regions<T>(self,
         value: &T,
-        region_set: &mut FnvHashSet<ty::Region>)
+        region_set: &mut FnvHashSet<&'tcx ty::Region>)
         -> bool
         where T : TypeFoldable<'tcx>
     {
         let mut have_bound_regions = false;
-        self.fold_regions(value, &mut have_bound_regions,
-                          |r, d| { region_set.insert(r.from_depth(d)); r });
+        self.fold_regions(value, &mut have_bound_regions, |r, d| {
+            region_set.insert(self.mk_region(r.from_depth(d)));
+            r
+        });
         have_bound_regions
     }
 
@@ -240,7 +242,7 @@ pub fn fold_regions<T,F>(self,
         skipped_regions: &mut bool,
         mut f: F)
         -> T
-        where F : FnMut(ty::Region, u32) -> ty::Region,
+        where F : FnMut(&'tcx ty::Region, u32) -> &'tcx ty::Region,
               T : TypeFoldable<'tcx>,
     {
         value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f))
@@ -260,14 +262,14 @@ pub struct RegionFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     skipped_regions: &'a mut bool,
     current_depth: u32,
-    fld_r: &'a mut (FnMut(ty::Region, u32) -> ty::Region + 'a),
+    fld_r: &'a mut (FnMut(&'tcx ty::Region, u32) -> &'tcx ty::Region + 'a),
 }
 
 impl<'a, 'gcx, 'tcx> RegionFolder<'a, 'gcx, 'tcx> {
     pub fn new<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                   skipped_regions: &'a mut bool,
                   fld_r: &'a mut F) -> RegionFolder<'a, 'gcx, 'tcx>
-        where F : FnMut(ty::Region, u32) -> ty::Region
+        where F : FnMut(&'tcx ty::Region, u32) -> &'tcx ty::Region
     {
         RegionFolder {
             tcx: tcx,
@@ -288,8 +290,8 @@ fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binde
         t
     }
 
-    fn fold_region(&mut self, r: ty::Region) -> ty::Region {
-        match r {
+    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+        match *r {
             ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => {
                 debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})",
                        r, self.current_depth);
@@ -313,16 +315,16 @@ fn fold_region(&mut self, r: ty::Region) -> ty::Region {
 struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     current_depth: u32,
-    fld_r: &'a mut (FnMut(ty::BoundRegion) -> ty::Region + 'a),
-    map: FnvHashMap<ty::BoundRegion, ty::Region>
+    fld_r: &'a mut (FnMut(ty::BoundRegion) -> &'tcx ty::Region + 'a),
+    map: FnvHashMap<ty::BoundRegion, &'tcx ty::Region>
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn replace_late_bound_regions<T,F>(self,
         value: &Binder<T>,
         mut f: F)
-        -> (T, FnvHashMap<ty::BoundRegion, ty::Region>)
-        where F : FnMut(ty::BoundRegion) -> ty::Region,
+        -> (T, FnvHashMap<ty::BoundRegion, &'tcx ty::Region>)
+        where F : FnMut(ty::BoundRegion) -> &'tcx ty::Region,
               T : TypeFoldable<'tcx>,
     {
         let mut replacer = RegionReplacer::new(self, &mut f);
@@ -340,7 +342,10 @@ pub fn liberate_late_bound_regions<T>(self,
         where T : TypeFoldable<'tcx>
     {
         self.replace_late_bound_regions(value, |br| {
-            ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})
+            self.mk_region(ty::ReFree(ty::FreeRegion {
+                scope: all_outlive_scope,
+                bound_region: br
+            }))
         }).0
     }
 
@@ -353,11 +358,11 @@ pub fn flatten_late_bound_regions<T>(self, bound2_value: &Binder<Binder<T>>)
         let bound0_value = bound2_value.skip_binder().skip_binder();
         let value = self.fold_regions(bound0_value, &mut false,
                                       |region, current_depth| {
-            match region {
+            match *region {
                 ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => {
                     // should be true if no escaping regions from bound2_value
                     assert!(debruijn.depth - current_depth <= 1);
-                    ty::ReLateBound(ty::DebruijnIndex::new(current_depth), br)
+                    self.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(current_depth), br))
                 }
                 _ => {
                     region
@@ -411,7 +416,7 @@ fn collect_late_bound_regions<T>(&self, value: &Binder<T>, just_constraint: bool
     pub fn erase_late_bound_regions<T>(self, value: &Binder<T>) -> T
         where T : TypeFoldable<'tcx>
     {
-        self.replace_late_bound_regions(value, |_| ty::ReErased).0
+        self.replace_late_bound_regions(value, |_| self.mk_region(ty::ReErased)).0
     }
 
     /// Rewrite any late-bound regions so that they are anonymous.  Region numbers are
@@ -428,7 +433,7 @@ pub fn anonymize_late_bound_regions<T>(self, sig: &Binder<T>) -> Binder<T>
         let mut counter = 0;
         Binder(self.replace_late_bound_regions(sig, |_| {
             counter += 1;
-            ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(counter))
+            self.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(counter)))
         }).0)
     }
 }
@@ -436,7 +441,7 @@ pub fn anonymize_late_bound_regions<T>(self, sig: &Binder<T>) -> Binder<T>
 impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> {
     fn new<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, fld_r: &'a mut F)
               -> RegionReplacer<'a, 'gcx, 'tcx>
-        where F : FnMut(ty::BoundRegion) -> ty::Region
+        where F : FnMut(ty::BoundRegion) -> &'tcx ty::Region
     {
         RegionReplacer {
             tcx: tcx,
@@ -465,22 +470,22 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         t.super_fold_with(self)
     }
 
-    fn fold_region(&mut self, r: ty::Region) -> ty::Region {
-        match r {
+    fn fold_region(&mut self, r:&'tcx  ty::Region) -> &'tcx ty::Region {
+        match *r {
             ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
                 let fld_r = &mut self.fld_r;
                 let region = *self.map.entry(br).or_insert_with(|| fld_r(br));
-                if let ty::ReLateBound(debruijn1, br) = region {
+                if let ty::ReLateBound(debruijn1, br) = *region {
                     // If the callback returns a late-bound region,
                     // that region should always use depth 1. Then we
                     // adjust it to the correct depth.
                     assert_eq!(debruijn1.depth, 1);
-                    ty::ReLateBound(debruijn, br)
+                    self.tcx.mk_region(ty::ReLateBound(debruijn, br))
                 } else {
                     region
                 }
             }
-            r => r
+            _ => r
         }
     }
 }
@@ -528,7 +533,7 @@ fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
                 u.super_fold_with(self)
             }
 
-            fn fold_region(&mut self, r: ty::Region) -> ty::Region {
+            fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
                 // because late-bound regions affect subtyping, we can't
                 // erase the bound/free distinction, but we can replace
                 // all free regions with 'erased.
@@ -537,9 +542,9 @@ fn fold_region(&mut self, r: ty::Region) -> ty::Region {
                 // type system never "sees" those, they get substituted
                 // away. In trans, they will always be erased to 'erased
                 // whenever a substitution occurs.
-                match r {
+                match *r {
                     ty::ReLateBound(..) => r,
-                    _ => ty::ReErased
+                    _ => self.tcx().mk_region(ty::ReErased)
                 }
             }
         }
@@ -574,7 +579,7 @@ pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
            value, amount);
 
     value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| {
-        shift_region(region, amount)
+        tcx.mk_region(shift_region(*region, amount))
     }))
 }
 
@@ -616,7 +621,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
         t.region_depth > self.depth
     }
 
-    fn visit_region(&mut self, r: ty::Region) -> bool {
+    fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
         r.escapes_depth(self.depth)
     }
 }
@@ -630,17 +635,18 @@ fn visit_ty(&mut self, t: Ty) -> bool {
         t.flags.get().intersects(self.flags)
     }
 
-    fn visit_region(&mut self, r: ty::Region) -> bool {
+    fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
         if self.flags.intersects(ty::TypeFlags::HAS_LOCAL_NAMES) {
             // does this represent a region that cannot be named
             // in a global way? used in fulfillment caching.
-            match r {
+            match *r {
                 ty::ReStatic | ty::ReEmpty | ty::ReErased => {}
                 _ => return true,
             }
         }
-        if self.flags.intersects(ty::TypeFlags::HAS_RE_INFER) {
-            match r {
+        if self.flags.intersects(ty::TypeFlags::HAS_RE_INFER |
+                                 ty::TypeFlags::KEEP_IN_LOCAL_TCX) {
+            match *r {
                 ty::ReVar(_) | ty::ReSkolemized(..) => { return true }
                 _ => {}
             }
@@ -688,8 +694,8 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
         t.super_visit_with(self)
     }
 
-    fn visit_region(&mut self, r: ty::Region) -> bool {
-        match r {
+    fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
+        match *r {
             ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
                 self.regions.insert(br);
             }
index 1dcc623d3655868cf931b3538b6bfb6ca2faa524..62bd30e2555921b029f69df921ac07254320ff24 100644 (file)
@@ -264,7 +264,7 @@ fn push_impl_path<T>(self,
         match self_ty.sty {
             ty::TyStruct(adt_def, substs) |
             ty::TyEnum(adt_def, substs) => {
-                if substs.types.is_empty() { // ignore regions
+                if substs.types().next().is_none() { // ignore regions
                     self.push_item_path(buffer, adt_def.did);
                 } else {
                     buffer.push(&format!("<{}>", self_ty));
index 195cece6bc4e008eb125087a9bc94d063cad0844..1ede8545e08e873a5ffa95dd9c236f097e67d8ba 100644 (file)
@@ -891,17 +891,6 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                 let mut st = Struct::new(dl, packed);
                 st.extend(dl, fields, ty)?;
 
-                // FIXME(16758) don't add a drop flag to unsized structs, as it
-                // won't actually be in the location we say it is because it'll be after
-                // the unsized field. Several other pieces of code assume that the unsized
-                // field is definitely the last one.
-                if def.dtor_kind().has_drop_flag() &&
-                   ty.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) {
-                    st.extend(dl, Some(Ok(&Scalar {
-                        value: Int(I8),
-                        non_zero: false
-                    })).into_iter(), ty)?;
-                }
                 Univariant {
                     variant: st,
                     non_zero: Some(def.did) == tcx.lang_items.non_zero()
@@ -911,24 +900,18 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                 let hint = *tcx.lookup_repr_hints(def.did).get(0)
                     .unwrap_or(&attr::ReprAny);
 
-                let dtor = def.dtor_kind().has_drop_flag();
-                let drop_flag = if dtor {
-                    Some(Scalar { value: Int(I8), non_zero: false })
-                } else {
-                    None
-                };
-
                 if def.variants.is_empty() {
                     // Uninhabitable; represent as unit
                     // (Typechecking will reject discriminant-sizing attrs.)
                     assert_eq!(hint, attr::ReprAny);
 
-                    let mut st = Struct::new(dl, false);
-                    st.extend(dl, drop_flag.iter().map(Ok), ty)?;
-                    return success(Univariant { variant: st, non_zero: false });
+                    return success(Univariant {
+                        variant: Struct::new(dl, false),
+                        non_zero: false
+                    });
                 }
 
-                if !dtor && def.variants.iter().all(|v| v.fields.is_empty()) {
+                if def.variants.iter().all(|v| v.fields.is_empty()) {
                     // All bodies empty -> intlike
                     let (mut min, mut max) = (i64::MAX, i64::MIN);
                     for v in &def.variants {
@@ -964,7 +947,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                         field.ty(tcx, substs).layout(infcx)
                     });
                     let mut st = Struct::new(dl, false);
-                    st.extend(dl, fields.chain(drop_flag.iter().map(Ok)), ty)?;
+                    st.extend(dl, fields, ty)?;
                     return success(Univariant { variant: st, non_zero: false });
                 }
 
@@ -973,7 +956,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                     v.fields.iter().map(|field| field.ty(tcx, substs)).collect::<Vec<_>>()
                 }).collect::<Vec<_>>();
 
-                if !dtor && variants.len() == 2 && hint == attr::ReprAny {
+                if variants.len() == 2 && hint == attr::ReprAny {
                     // Nullable pointer optimization
                     for discr in 0..2 {
                         let other_fields = variants[1 - discr].iter().map(|ty| {
@@ -1045,8 +1028,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                         Ok(field)
                     });
                     let mut st = Struct::new(dl, false);
-                    st.extend(dl, discr.iter().map(Ok).chain(fields)
-                                              .chain(drop_flag.iter().map(Ok)), ty)?;
+                    st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?;
                     size = cmp::max(size, st.min_size());
                     align = align.max(st.align);
                     Ok(st)
@@ -1277,11 +1259,6 @@ pub fn compute(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
                     return Err(err);
                 }
 
-                // If there's a drop flag, it can't be just a pointer.
-                if def.dtor_kind().has_drop_flag() {
-                    return Err(err);
-                }
-
                 // Get a zero-sized variant or a pointer newtype.
                 let zero_or_ptr_variant = |i: usize| {
                     let fields = def.variants[i].fields.iter().map(|field| {
index d5686906e6a7b7c467d99894b4f80a85aa6d5ab0..0e8bea86178f3097bc4021d656c592d6659a3e57 100644 (file)
@@ -38,7 +38,7 @@ fn to_dep_node(key: &$key) -> DepNode<DefId> { DepNode::$node_name(*key) }
 dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>> }
 dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef<'tcx> }
 dep_map_ty! { AdtDefs: ItemSignature(DefId) -> ty::AdtDefMaster<'tcx> }
-dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc<ty::ItemVariances> }
+dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc<Vec<ty::Variance>> }
 dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Rc<Vec<DefId>> }
 dep_map_ty! { ImplItems: ImplItems(DefId) -> Vec<ty::ImplOrTraitItemId> }
 dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc<Vec<ty::ImplOrTraitItem<'tcx>>> }
index 1f747ddfb295971c13e4a57de31e1fd1ce93ad31..e9c01f5bad66ecab0273b09683dd971033d360c4 100644 (file)
@@ -43,7 +43,7 @@
 use std::slice;
 use std::vec::IntoIter;
 use syntax::ast::{self, CrateNum, Name, NodeId};
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::attr;
 use syntax::parse::token::InternedString;
 use syntax_pos::{DUMMY_SP, Span};
 
@@ -122,23 +122,16 @@ pub struct CrateAnalysis<'a> {
 #[derive(Copy, Clone)]
 pub enum DtorKind {
     NoDtor,
-    TraitDtor(bool)
+    TraitDtor
 }
 
 impl DtorKind {
     pub fn is_present(&self) -> bool {
         match *self {
-            TraitDtor(..) => true,
+            TraitDtor => true,
             _ => false
         }
     }
-
-    pub fn has_drop_flag(&self) -> bool {
-        match self {
-            &NoDtor => false,
-            &TraitDtor(flag) => flag
-        }
-    }
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
@@ -350,7 +343,7 @@ pub struct Method<'tcx> {
     pub generics: &'tcx Generics<'tcx>,
     pub predicates: GenericPredicates<'tcx>,
     pub fty: &'tcx BareFnTy<'tcx>,
-    pub explicit_self: ExplicitSelfCategory,
+    pub explicit_self: ExplicitSelfCategory<'tcx>,
     pub vis: Visibility,
     pub defaultness: hir::Defaultness,
     pub def_id: DefId,
@@ -362,7 +355,7 @@ pub fn new(name: Name,
                generics: &'tcx ty::Generics<'tcx>,
                predicates: GenericPredicates<'tcx>,
                fty: &'tcx BareFnTy<'tcx>,
-               explicit_self: ExplicitSelfCategory,
+               explicit_self: ExplicitSelfCategory<'tcx>,
                vis: Visibility,
                defaultness: hir::Defaultness,
                def_id: DefId,
@@ -424,21 +417,6 @@ pub struct AssociatedType<'tcx> {
     pub container: ImplOrTraitItemContainer,
 }
 
-#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
-pub struct ItemVariances {
-    pub types: Vec<Variance>,
-    pub regions: Vec<Variance>,
-}
-
-impl ItemVariances {
-    pub fn empty() -> ItemVariances {
-        ItemVariances {
-            types: vec![],
-            regions: vec![],
-        }
-    }
-}
-
 #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)]
 pub enum Variance {
     Covariant,      // T<A> <: T<B> iff A <: B -- e.g., function return type
@@ -665,28 +643,28 @@ pub enum BorrowKind {
 /// Information describing the capture of an upvar. This is computed
 /// during `typeck`, specifically by `regionck`.
 #[derive(PartialEq, Clone, Debug, Copy)]
-pub enum UpvarCapture {
+pub enum UpvarCapture<'tcx> {
     /// Upvar is captured by value. This is always true when the
     /// closure is labeled `move`, but can also be true in other cases
     /// depending on inference.
     ByValue,
 
     /// Upvar is captured by reference.
-    ByRef(UpvarBorrow),
+    ByRef(UpvarBorrow<'tcx>),
 }
 
 #[derive(PartialEq, Clone, Copy)]
-pub struct UpvarBorrow {
+pub struct UpvarBorrow<'tcx> {
     /// The kind of borrow: by-ref upvars have access to shared
     /// immutable borrows, which are not part of the normal language
     /// syntax.
     pub kind: BorrowKind,
 
     /// Region of the resulting reference.
-    pub region: ty::Region,
+    pub region: &'tcx ty::Region,
 }
 
-pub type UpvarCaptureMap = FnvHashMap<UpvarId, UpvarCapture>;
+pub type UpvarCaptureMap<'tcx> = FnvHashMap<UpvarId, UpvarCapture<'tcx>>;
 
 #[derive(Copy, Clone)]
 pub struct ClosureUpvar<'tcx> {
@@ -707,7 +685,7 @@ pub enum IntVarValue {
 /// this is `None`, then the default is inherited from the
 /// surrounding context. See RFC #599 for details.
 #[derive(Copy, Clone)]
-pub enum ObjectLifetimeDefault {
+pub enum ObjectLifetimeDefault<'tcx> {
     /// Require an explicit annotation. Occurs when multiple
     /// `T:'a` constraints are found.
     Ambiguous,
@@ -716,7 +694,7 @@ pub enum ObjectLifetimeDefault {
     BaseDefault,
 
     /// Use the given region as the default.
-    Specific(Region),
+    Specific(&'tcx Region),
 }
 
 #[derive(Clone)]
@@ -726,18 +704,18 @@ pub struct TypeParameterDef<'tcx> {
     pub index: u32,
     pub default_def_id: DefId, // for use in error reporing about defaults
     pub default: Option<Ty<'tcx>>,
-    pub object_lifetime_default: ObjectLifetimeDefault,
+    pub object_lifetime_default: ObjectLifetimeDefault<'tcx>,
 }
 
 #[derive(Clone)]
-pub struct RegionParameterDef {
+pub struct RegionParameterDef<'tcx> {
     pub name: Name,
     pub def_id: DefId,
     pub index: u32,
-    pub bounds: Vec<ty::Region>,
+    pub bounds: Vec<&'tcx ty::Region>,
 }
 
-impl RegionParameterDef {
+impl<'tcx> RegionParameterDef<'tcx> {
     pub fn to_early_bound_region(&self) -> ty::Region {
         ty::ReEarlyBound(ty::EarlyBoundRegion {
             index: self.index,
@@ -757,11 +735,25 @@ pub struct Generics<'tcx> {
     pub parent: Option<DefId>,
     pub parent_regions: u32,
     pub parent_types: u32,
-    pub regions: Vec<RegionParameterDef>,
+    pub regions: Vec<RegionParameterDef<'tcx>>,
     pub types: Vec<TypeParameterDef<'tcx>>,
     pub has_self: bool,
 }
 
+impl<'tcx> Generics<'tcx> {
+    pub fn parent_count(&self) -> usize {
+        self.parent_regions as usize + self.parent_types as usize
+    }
+
+    pub fn own_count(&self) -> usize {
+        self.regions.len() + self.types.len()
+    }
+
+    pub fn count(&self) -> usize {
+        self.parent_count() + self.own_count()
+    }
+}
+
 /// Bounds on generics.
 #[derive(Clone)]
 pub struct GenericPredicates<'tcx> {
@@ -812,14 +804,11 @@ pub enum Predicate<'tcx> {
     /// would be the type parameters.
     Trait(PolyTraitPredicate<'tcx>),
 
-    /// A predicate created by RFC1592
-    Rfc1592(Box<Predicate<'tcx>>),
-
     /// where `T1 == T2`.
     Equate(PolyEquatePredicate<'tcx>),
 
     /// where 'a : 'b
-    RegionOutlives(PolyRegionOutlivesPredicate),
+    RegionOutlives(PolyRegionOutlivesPredicate<'tcx>),
 
     /// where T : 'a
     TypeOutlives(PolyTypeOutlivesPredicate<'tcx>),
@@ -914,8 +903,6 @@ pub fn subst_supertrait(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
         match *self {
             Predicate::Trait(ty::Binder(ref data)) =>
                 Predicate::Trait(ty::Binder(data.subst(tcx, substs))),
-            Predicate::Rfc1592(ref pi) =>
-                Predicate::Rfc1592(Box::new(pi.subst_supertrait(tcx, trait_ref))),
             Predicate::Equate(ty::Binder(ref data)) =>
                 Predicate::Equate(ty::Binder(data.subst(tcx, substs))),
             Predicate::RegionOutlives(ty::Binder(ref data)) =>
@@ -958,7 +945,6 @@ fn dep_node(&self) -> DepNode<DefId> {
         // leads to more recompilation.
         let def_ids: Vec<_> =
             self.input_types()
-                .iter()
                 .flat_map(|t| t.walk())
                 .filter_map(|t| match t.sty {
                     ty::TyStruct(adt_def, _) |
@@ -967,12 +953,13 @@ fn dep_node(&self) -> DepNode<DefId> {
                     _ =>
                         None
                 })
+                .chain(iter::once(self.def_id()))
                 .collect();
-        DepNode::TraitSelect(self.def_id(), def_ids)
+        DepNode::TraitSelect(def_ids)
     }
 
-    pub fn input_types(&self) -> &[Ty<'tcx>] {
-        &self.trait_ref.substs.types
+    pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
+        self.trait_ref.input_types()
     }
 
     pub fn self_ty(&self) -> Ty<'tcx> {
@@ -999,8 +986,9 @@ pub fn dep_node(&self) -> DepNode<DefId> {
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A : B`
 pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>;
-pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate<ty::Region, ty::Region>;
-pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, ty::Region>;
+pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate<&'tcx ty::Region,
+                                                                   &'tcx ty::Region>;
+pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, &'tcx ty::Region>;
 
 /// This kind of predicate has no *direct* correspondent in the
 /// syntax, but it roughly corresponds to the syntactic forms:
@@ -1089,7 +1077,7 @@ fn to_predicate(&self) -> Predicate<'tcx> {
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate {
+impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
     fn to_predicate(&self) -> Predicate<'tcx> {
         Predicate::RegionOutlives(self.clone())
     }
@@ -1114,10 +1102,7 @@ impl<'tcx> Predicate<'tcx> {
     pub fn walk_tys(&self) -> IntoIter<Ty<'tcx>> {
         let vec: Vec<_> = match *self {
             ty::Predicate::Trait(ref data) => {
-                data.0.trait_ref.input_types().to_vec()
-            }
-            ty::Predicate::Rfc1592(ref data) => {
-                return data.walk_tys()
+                data.skip_binder().input_types().collect()
             }
             ty::Predicate::Equate(ty::Binder(ref data)) => {
                 vec![data.0, data.1]
@@ -1130,10 +1115,7 @@ pub fn walk_tys(&self) -> IntoIter<Ty<'tcx>> {
             }
             ty::Predicate::Projection(ref data) => {
                 let trait_inputs = data.0.projection_ty.trait_ref.input_types();
-                trait_inputs.iter()
-                            .cloned()
-                            .chain(Some(data.0.ty))
-                            .collect()
+                trait_inputs.chain(Some(data.0.ty)).collect()
             }
             ty::Predicate::WellFormed(data) => {
                 vec![data]
@@ -1159,7 +1141,6 @@ pub fn to_opt_poly_trait_ref(&self) -> Option<PolyTraitRef<'tcx>> {
             Predicate::Trait(ref t) => {
                 Some(t.to_poly_trait_ref())
             }
-            Predicate::Rfc1592(..) |
             Predicate::Projection(..) |
             Predicate::Equate(..) |
             Predicate::RegionOutlives(..) |
@@ -1213,15 +1194,15 @@ pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> TraitRef<'tcx> {
     }
 
     pub fn self_ty(&self) -> Ty<'tcx> {
-        self.substs.types[0]
+        self.substs.type_at(0)
     }
 
-    pub fn input_types(&self) -> &[Ty<'tcx>] {
+    pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
         // Select only the "input types" from a trait-reference. For
         // now this is all the types that appear in the
         // trait-reference, but it should eventually exclude
         // associated types.
-        &self.substs.types
+        self.substs.types()
     }
 }
 
@@ -1246,7 +1227,7 @@ pub struct ParameterEnvironment<'tcx> {
     /// indicates it must outlive at least the function body (the user
     /// may specify stronger requirements). This field indicates the
     /// region of the callee.
-    pub implicit_region_bound: ty::Region,
+    pub implicit_region_bound: &'tcx ty::Region,
 
     /// Obligations that the caller must satisfy. This is basically
     /// the set of bounds on the in-scope type parameters, translated
@@ -1440,7 +1421,6 @@ pub struct TypeScheme<'tcx> {
         const IS_PHANTOM_DATA     = 1 << 3,
         const IS_SIMD             = 1 << 4,
         const IS_FUNDAMENTAL      = 1 << 5,
-        const IS_NO_DROP_FLAG     = 1 << 6,
     }
 }
 
@@ -1558,9 +1538,6 @@ fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         if attr::contains_name(&attrs, "fundamental") {
             flags = flags | AdtFlags::IS_FUNDAMENTAL;
         }
-        if attr::contains_name(&attrs, "unsafe_no_drop_flag") {
-            flags = flags | AdtFlags::IS_NO_DROP_FLAG;
-        }
         if tcx.lookup_simd(did) {
             flags = flags | AdtFlags::IS_SIMD;
         }
@@ -1627,10 +1604,7 @@ pub fn is_phantom_data(&self) -> bool {
 
     /// Returns whether this type has a destructor.
     pub fn has_dtor(&self) -> bool {
-        match self.dtor_kind() {
-            NoDtor => false,
-            TraitDtor(..) => true
-        }
+        self.dtor_kind().is_present()
     }
 
     /// Asserts this is a struct and returns the struct's unique
@@ -1710,9 +1684,7 @@ pub fn set_destructor(&self, dtor: DefId) {
 
     pub fn dtor_kind(&self) -> DtorKind {
         match self.destructor.get() {
-            Some(_) => {
-                TraitDtor(!self.flags.get().intersects(AdtFlags::IS_NO_DROP_FLAG))
-            }
+            Some(_) => TraitDtor,
             None => NoDtor,
         }
     }
@@ -1840,10 +1812,10 @@ fn sized_constraint_for_ty(
             }
 
             TyTuple(ref tys) => {
-                // FIXME(#33242) we only need to constrain the last field
-                tys.iter().flat_map(|ty| {
-                    self.sized_constraint_for_ty(tcx, stack, ty)
-                }).collect()
+                match tys.last() {
+                    None => vec![],
+                    Some(ty) => self.sized_constraint_for_ty(tcx, stack, ty)
+                }
             }
 
             TyEnum(adt, substs) | TyStruct(adt, substs) => {
@@ -1882,7 +1854,7 @@ fn sized_constraint_for_ty(
                 };
                 let sized_predicate = Binder(TraitRef {
                     def_id: sized_trait,
-                    substs: Substs::new_trait(tcx, vec![], vec![], ty)
+                    substs: Substs::new_trait(tcx, ty, &[])
                 }).to_predicate();
                 let predicates = tcx.lookup_predicates(self.did).predicates;
                 if predicates.into_iter().any(|p| p == sized_predicate) {
@@ -2609,7 +2581,7 @@ pub fn lookup_simd(self, did: DefId) -> bool {
             || self.lookup_repr_hints(did).contains(&attr::ReprSimd)
     }
 
-    pub fn item_variances(self, item_id: DefId) -> Rc<ItemVariances> {
+    pub fn item_variances(self, item_id: DefId) -> Rc<Vec<ty::Variance>> {
         lookup_locally_or_in_crate_store(
             "item_variance_map", item_id, &self.item_variance_map,
             || Rc::new(self.sess.cstore.item_variances(item_id)))
@@ -2843,7 +2815,7 @@ pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> {
         ty::ParameterEnvironment {
             free_substs: Substs::empty(self),
             caller_bounds: Vec::new(),
-            implicit_region_bound: ty::ReEmpty,
+            implicit_region_bound: self.mk_region(ty::ReEmpty),
             free_id_outlive: free_id_outlive
         }
     }
@@ -2859,8 +2831,10 @@ pub fn construct_free_substs(self, def_id: DefId,
 
         let substs = Substs::for_item(self.global_tcx(), def_id, |def, _| {
             // map bound 'a => free 'a
-            ReFree(FreeRegion { scope: free_id_outlive,
-                                bound_region: def.to_bound_region() })
+            self.global_tcx().mk_region(ReFree(FreeRegion {
+                scope: free_id_outlive,
+                bound_region: def.to_bound_region()
+            }))
         }, |def, _| {
             // map T => T
             self.global_tcx().mk_param_from_def(def)
@@ -2910,7 +2884,7 @@ pub fn construct_parameter_environment(self,
 
         let unnormalized_env = ty::ParameterEnvironment {
             free_substs: free_substs,
-            implicit_region_bound: ty::ReScope(free_id_outlive),
+            implicit_region_bound: tcx.mk_region(ty::ReScope(free_id_outlive)),
             caller_bounds: predicates,
             free_id_outlive: free_id_outlive,
         };
@@ -2919,6 +2893,10 @@ pub fn construct_parameter_environment(self,
         traits::normalize_param_env_or_error(tcx, unnormalized_env, cause)
     }
 
+    pub fn node_scope_region(self, id: NodeId) -> &'tcx Region {
+        self.mk_region(ty::ReScope(self.region_maps.node_extent(id)))
+    }
+
     pub fn is_method_call(self, expr_id: NodeId) -> bool {
         self.tables.borrow().method_map.contains_key(&MethodCall::expr(expr_id))
     }
@@ -2928,7 +2906,7 @@ pub fn is_overloaded_autoderef(self, expr_id: NodeId, autoderefs: u32) -> bool {
                                                                             autoderefs))
     }
 
-    pub fn upvar_capture(self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
+    pub fn upvar_capture(self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
         Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone())
     }
 
@@ -2954,10 +2932,10 @@ pub fn span_of_impl(self, impl_did: DefId) -> Result<Span, InternedString> {
 
 /// The category of explicit self.
 #[derive(Clone, Copy, Eq, PartialEq, Debug)]
-pub enum ExplicitSelfCategory {
+pub enum ExplicitSelfCategory<'tcx> {
     Static,
     ByValue,
-    ByReference(Region, hir::Mutability),
+    ByReference(&'tcx Region, hir::Mutability),
     ByBox,
 }
 
index ee431681ad100488cb8c49f63d5f9c89766ce529..4d5b38212f600ee43c18bb29500b01c52dfa5853 100644 (file)
@@ -17,7 +17,7 @@
 
 #[derive(Debug)]
 pub enum Component<'tcx> {
-    Region(ty::Region),
+    Region(&'tcx ty::Region),
     Param(ty::ParamTy),
     UnresolvedInferenceVariable(ty::InferTy),
 
@@ -210,7 +210,7 @@ fn capture_components(&self, ty: Ty<'tcx>) -> Vec<Component<'tcx>> {
     }
 }
 
-fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<ty::Region>) {
+fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<&'tcx ty::Region>) {
     for r in regions {
         if !r.is_bound() {
             out.push(Component::Region(r));
index abf863f953664258de01fbcbf4f0ba40b8603922..5c157ff32e7bbb846bd256f6b98c9c3315a07b61 100644 (file)
@@ -14,7 +14,7 @@
 //! type equality, etc.
 
 use hir::def_id::DefId;
-use ty::subst::Substs;
+use ty::subst::{Kind, Substs};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::error::{ExpectedFound, TypeError};
 use std::rc::Rc;
@@ -71,8 +71,8 @@ fn relate_with_variance<T: Relate<'tcx>>(&mut self,
     fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>)
            -> RelateResult<'tcx, Ty<'tcx>>;
 
-    fn regions(&mut self, a: ty::Region, b: ty::Region)
-               -> RelateResult<'tcx, ty::Region>;
+    fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
+               -> RelateResult<'tcx, &'tcx ty::Region>;
 
     fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
                   -> RelateResult<'tcx, ty::Binder<T>>
@@ -139,7 +139,7 @@ fn relate_item_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
 }
 
 pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
-                                        variances: Option<&ty::ItemVariances>,
+                                        variances: Option<&Vec<ty::Variance>>,
                                         a_subst: &'tcx Substs<'tcx>,
                                         b_subst: &'tcx Substs<'tcx>)
                                         -> RelateResult<'tcx, &'tcx Substs<'tcx>>
@@ -147,19 +147,18 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
 {
     let tcx = relation.tcx();
 
-    let types = a_subst.types.iter().enumerate().map(|(i, a_ty)| {
-        let b_ty = &b_subst.types[i];
-        let variance = variances.map_or(ty::Invariant, |v| v.types[i]);
-        relation.relate_with_variance(variance, a_ty, b_ty)
-    }).collect()?;
-
-    let regions = a_subst.regions.iter().enumerate().map(|(i, a_r)| {
-        let b_r = &b_subst.regions[i];
-        let variance = variances.map_or(ty::Invariant, |v| v.regions[i]);
-        relation.relate_with_variance(variance, a_r, b_r)
-    }).collect()?;
+    let params = a_subst.params().iter().zip(b_subst.params()).enumerate().map(|(i, (a, b))| {
+        let variance = variances.map_or(ty::Invariant, |v| v[i]);
+        if let (Some(a_ty), Some(b_ty)) = (a.as_type(), b.as_type()) {
+            Ok(Kind::from(relation.relate_with_variance(variance, &a_ty, &b_ty)?))
+        } else if let (Some(a_r), Some(b_r)) = (a.as_region(), b.as_region()) {
+            Ok(Kind::from(relation.relate_with_variance(variance, &a_r, &b_r)?))
+        } else {
+            bug!()
+        }
+    });
 
-    Ok(Substs::new(tcx, types, regions))
+    Substs::maybe_new(tcx, params)
 }
 
 impl<'tcx> Relate<'tcx> for &'tcx ty::BareFnTy<'tcx> {
@@ -473,9 +472,9 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
 
         (&ty::TyRef(a_r, ref a_mt), &ty::TyRef(b_r, ref b_mt)) =>
         {
-            let r = relation.relate_with_variance(ty::Contravariant, a_r, b_r)?;
+            let r = relation.relate_with_variance(ty::Contravariant, &a_r, &b_r)?;
             let mt = relation.relate(a_mt, b_mt)?;
-            Ok(tcx.mk_ref(tcx.mk_region(r), mt))
+            Ok(tcx.mk_ref(r, mt))
         }
 
         (&ty::TyArray(a_t, sz_a), &ty::TyArray(b_t, sz_b)) =>
@@ -571,11 +570,11 @@ fn relate<'a, 'gcx, R>(relation: &mut R,
     }
 }
 
-impl<'tcx> Relate<'tcx> for ty::Region {
+impl<'tcx> Relate<'tcx> for &'tcx ty::Region {
     fn relate<'a, 'gcx, R>(relation: &mut R,
-                           a: &ty::Region,
-                           b: &ty::Region)
-                           -> RelateResult<'tcx, ty::Region>
+                           a: &&'tcx ty::Region,
+                           b: &&'tcx ty::Region)
+                           -> RelateResult<'tcx, &'tcx ty::Region>
         where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
     {
         relation.regions(*a, *b)
index f7c4b9938c2794da4c37b619277b6346dd2dee9a..ad3769605abd90023b76362cc4ce16e5a504cb9c 100644 (file)
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 use infer::type_variable;
-use ty::subst::Substs;
 use ty::{self, Lift, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 
@@ -73,13 +72,6 @@ fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lif
     }
 }
 
-impl<'tcx> Lift<'tcx> for ty::Region {
-    type Lifted = Self;
-    fn lift_to_tcx(&self, _: TyCtxt) -> Option<ty::Region> {
-        Some(*self)
-    }
-}
-
 impl<'a, 'tcx> Lift<'tcx> for ty::TraitRef<'a> {
     type Lifted = ty::TraitRef<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
@@ -186,9 +178,6 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lif
             ty::Predicate::WellFormed(ty) => {
                 tcx.lift(&ty).map(ty::Predicate::WellFormed)
             }
-            ty::Predicate::Rfc1592(box ref a) => {
-                tcx.lift(a).map(|a| ty::Predicate::Rfc1592(Box::new(a)))
-            }
             ty::Predicate::ClosureKind(closure_def_id, kind) => {
                 Some(ty::Predicate::ClosureKind(closure_def_id, kind))
             }
@@ -316,13 +305,21 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lif
             FixedArraySize(x) => FixedArraySize(x),
             TyParamSize(x) => TyParamSize(x),
             ArgCount => ArgCount,
-            RegionsDoesNotOutlive(a, b) => RegionsDoesNotOutlive(a, b),
-            RegionsNotSame(a, b) => RegionsNotSame(a, b),
-            RegionsNoOverlap(a, b) => RegionsNoOverlap(a, b),
+            RegionsDoesNotOutlive(a, b) => {
+                return tcx.lift(&(a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b))
+            }
+            RegionsNotSame(a, b) => {
+                return tcx.lift(&(a, b)).map(|(a, b)| RegionsNotSame(a, b))
+            }
+            RegionsNoOverlap(a, b) => {
+                return tcx.lift(&(a, b)).map(|(a, b)| RegionsNoOverlap(a, b))
+            }
             RegionsInsufficientlyPolymorphic(a, b) => {
-                RegionsInsufficientlyPolymorphic(a, b)
+                return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b))
+            }
+            RegionsOverlyPolymorphic(a, b) => {
+                return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b))
             }
-            RegionsOverlyPolymorphic(a, b) => RegionsOverlyPolymorphic(a, b),
             IntegerAsChar => IntegerAsChar,
             IntMismatch(x) => IntMismatch(x),
             FloatMismatch(x) => FloatMismatch(x),
@@ -655,7 +652,7 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::Region {
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
         *self
     }
@@ -673,41 +670,6 @@ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
-        *self
-    }
-
-    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        let region = folder.fold_region(**self);
-        folder.tcx().mk_region(region)
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
-        false
-    }
-
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        visitor.visit_region(**self)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        let types = self.types.fold_with(folder);
-        let regions = self.regions.fold_with(folder);
-        Substs::new(folder.tcx(), types, regions)
-    }
-
-    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_substs(self)
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.types.visit_with(visitor) || self.regions.visit_with(visitor)
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         ty::ClosureSubsts {
@@ -783,7 +745,7 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault {
+impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
             ty::ObjectLifetimeDefault::Ambiguous =>
@@ -805,7 +767,7 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef {
+impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         ty::RegionParameterDef {
             name: self.name,
@@ -825,8 +787,6 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
         match *self {
             ty::Predicate::Trait(ref a) =>
                 ty::Predicate::Trait(a.fold_with(folder)),
-            ty::Predicate::Rfc1592(ref a) =>
-                ty::Predicate::Rfc1592(a.fold_with(folder)),
             ty::Predicate::Equate(ref binder) =>
                 ty::Predicate::Equate(binder.fold_with(folder)),
             ty::Predicate::RegionOutlives(ref binder) =>
@@ -847,7 +807,6 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         match *self {
             ty::Predicate::Trait(ref a) => a.visit_with(visitor),
-            ty::Predicate::Rfc1592(ref a) => a.visit_with(visitor),
             ty::Predicate::Equate(ref binder) => binder.visit_with(visitor),
             ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor),
             ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor),
index 8aa81cc4743c9a639c598863af8fd956f5986215..0e3f18c4474eaed1b91788ee56b3c298eb38f7aa 100644 (file)
@@ -19,8 +19,8 @@
 
 use collections::enum_set::{self, EnumSet, CLike};
 use std::fmt;
-use std::ops;
 use std::mem;
+use std::ops;
 use syntax::abi;
 use syntax::ast::{self, Name};
 use syntax::parse::token::keywords;
@@ -293,7 +293,7 @@ fn decode<D: Decoder>(d: &mut D) -> Result<ClosureSubsts<'tcx>, D::Error> {
 #[derive(Clone, PartialEq, Eq, Hash)]
 pub struct TraitObject<'tcx> {
     pub principal: PolyExistentialTraitRef<'tcx>,
-    pub region_bound: ty::Region,
+    pub region_bound: &'tcx ty::Region,
     pub builtin_bounds: BuiltinBounds,
     pub projection_bounds: Vec<PolyExistentialProjection<'tcx>>,
 }
@@ -335,7 +335,7 @@ pub fn substs(&self) -> &'tcx Substs<'tcx> {
         self.0.substs
     }
 
-    pub fn input_types(&self) -> &[Ty<'tcx>] {
+    pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
         // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<>
         self.0.input_types()
     }
@@ -360,12 +360,12 @@ pub struct ExistentialTraitRef<'tcx> {
 }
 
 impl<'tcx> ExistentialTraitRef<'tcx> {
-    pub fn input_types(&self) -> &[Ty<'tcx>] {
+    pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
         // Select only the "input types" from a trait-reference. For
         // now this is all the types that appear in the
         // trait-reference, but it should eventually exclude
         // associated types.
-        &self.substs.types
+        self.substs.types()
     }
 }
 
@@ -376,7 +376,7 @@ pub fn def_id(&self) -> DefId {
         self.0.def_id
     }
 
-    pub fn input_types(&self) -> &[Ty<'tcx>] {
+    pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
         // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<>
         self.0.input_types()
     }
@@ -675,6 +675,15 @@ pub enum Region {
     ReErased,
 }
 
+impl<'tcx> Decodable for &'tcx Region {
+    fn decode<D: Decoder>(d: &mut D) -> Result<&'tcx Region, D::Error> {
+        let r = Decodable::decode(d)?;
+        cstore::tls::with_decoding_context(d, |dcx, _| {
+            Ok(dcx.tcx().mk_region(r))
+        })
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
 pub struct EarlyBoundRegion {
     pub index: u32,
@@ -1206,26 +1215,26 @@ pub fn ty_adt_def(&self) -> Option<AdtDef<'tcx>> {
     /// Returns the regions directly referenced from this type (but
     /// not types reachable from this type via `walk_tys`). This
     /// ignores late-bound regions binders.
-    pub fn regions(&self) -> Vec<ty::Region> {
+    pub fn regions(&self) -> Vec<&'tcx ty::Region> {
         match self.sty {
             TyRef(region, _) => {
-                vec![*region]
+                vec![region]
             }
             TyTrait(ref obj) => {
                 let mut v = vec![obj.region_bound];
-                v.extend_from_slice(&obj.principal.skip_binder().substs.regions);
+                v.extend(obj.principal.skip_binder().substs.regions());
                 v
             }
             TyEnum(_, substs) |
             TyStruct(_, substs) |
             TyAnon(_, substs) => {
-                substs.regions.to_vec()
+                substs.regions().collect()
             }
             TyClosure(_, ref substs) => {
-                substs.func_substs.regions.to_vec()
+                substs.func_substs.regions().collect()
             }
             TyProjection(ref data) => {
-                data.trait_ref.substs.regions.to_vec()
+                data.trait_ref.substs.regions().collect()
             }
             TyFnDef(..) |
             TyFnPtr(_) |
index e1a19a7b7992ece6edcae09a1b47a11f422cbaea..0ccfea23309999d96d3fdbfa03151764824aa90a 100644 (file)
 use middle::cstore;
 use hir::def_id::DefId;
 use ty::{self, Ty, TyCtxt};
-use ty::fold::{TypeFoldable, TypeFolder};
+use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 
 use serialize::{Encodable, Encoder, Decodable, Decoder};
 use syntax_pos::{Span, DUMMY_SP};
 
-///////////////////////////////////////////////////////////////////////////
+use core::nonzero::NonZero;
+use std::fmt;
+use std::iter;
+use std::marker::PhantomData;
+use std::mem;
+
+/// An entity in the Rust typesystem, which can be one of
+/// several kinds (only types and lifetimes for now).
+/// To reduce memory usage, a `Kind` is a interned pointer,
+/// with the lowest 2 bits being reserved for a tag to
+/// indicate the type (`Ty` or `Region`) it points to.
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Kind<'tcx> {
+    ptr: NonZero<usize>,
+    marker: PhantomData<(Ty<'tcx>, &'tcx ty::Region)>
+}
+
+const TAG_MASK: usize = 0b11;
+const TYPE_TAG: usize = 0b00;
+const REGION_TAG: usize = 0b01;
+
+impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> {
+    fn from(ty: Ty<'tcx>) -> Kind<'tcx> {
+        // Ensure we can use the tag bits.
+        assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0);
+
+        let ptr = ty as *const _ as usize;
+        Kind {
+            ptr: unsafe {
+                NonZero::new(ptr | TYPE_TAG)
+            },
+            marker: PhantomData
+        }
+    }
+}
+
+impl<'tcx> From<&'tcx ty::Region> for Kind<'tcx> {
+    fn from(r: &'tcx ty::Region) -> Kind<'tcx> {
+        // Ensure we can use the tag bits.
+        assert_eq!(mem::align_of_val(r) & TAG_MASK, 0);
+
+        let ptr = r as *const _ as usize;
+        Kind {
+            ptr: unsafe {
+                NonZero::new(ptr | REGION_TAG)
+            },
+            marker: PhantomData
+        }
+    }
+}
+
+impl<'tcx> Kind<'tcx> {
+    #[inline]
+    unsafe fn downcast<T>(self, tag: usize) -> Option<&'tcx T> {
+        let ptr = *self.ptr;
+        if ptr & TAG_MASK == tag {
+            Some(&*((ptr & !TAG_MASK) as *const _))
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    pub fn as_type(self) -> Option<Ty<'tcx>> {
+        unsafe {
+            self.downcast(TYPE_TAG)
+        }
+    }
+
+    #[inline]
+    pub fn as_region(self) -> Option<&'tcx ty::Region> {
+        unsafe {
+            self.downcast(REGION_TAG)
+        }
+    }
+}
+
+impl<'tcx> fmt::Debug for Kind<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if let Some(ty) = self.as_type() {
+            write!(f, "{:?}", ty)
+        } else if let Some(r) = self.as_region() {
+            write!(f, "{:?}", r)
+        } else {
+            write!(f, "<unknwon @ {:p}>", *self.ptr as *const ())
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        if let Some(ty) = self.as_type() {
+            Kind::from(ty.fold_with(folder))
+        } else if let Some(r) = self.as_region() {
+            Kind::from(r.fold_with(folder))
+        } else {
+            bug!()
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        if let Some(ty) = self.as_type() {
+            ty.visit_with(visitor)
+        } else if let Some(r) = self.as_region() {
+            r.visit_with(visitor)
+        } else {
+            bug!()
+        }
+    }
+}
 
 /// A substitution mapping type/region parameters to new values.
-#[derive(Clone, PartialEq, Eq, Hash)]
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct Substs<'tcx> {
-    pub types: Vec<Ty<'tcx>>,
-    pub regions: Vec<ty::Region>,
+    params: Vec<Kind<'tcx>>
 }
 
 impl<'a, 'gcx, 'tcx> Substs<'tcx> {
-    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-               t: Vec<Ty<'tcx>>,
-               r: Vec<ty::Region>)
-               -> &'tcx Substs<'tcx>
-    {
-        tcx.mk_substs(Substs { types: t, regions: r })
+    pub fn new<I>(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I)
+                  -> &'tcx Substs<'tcx>
+    where I: IntoIterator<Item=Kind<'tcx>> {
+        tcx.mk_substs(Substs {
+            params: params.into_iter().collect()
+        })
+    }
+
+    pub fn maybe_new<I, E>(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I)
+                           -> Result<&'tcx Substs<'tcx>, E>
+    where I: IntoIterator<Item=Result<Kind<'tcx>, E>> {
+        Ok(tcx.mk_substs(Substs {
+            params: params.into_iter().collect::<Result<_, _>>()?
+        }))
     }
 
     pub fn new_trait(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                     mut t: Vec<Ty<'tcx>>,
-                     r: Vec<ty::Region>,
-                     s: Ty<'tcx>)
+                     s: Ty<'tcx>,
+                     t: &[Ty<'tcx>])
                     -> &'tcx Substs<'tcx>
     {
-        t.insert(0, s);
-        Substs::new(tcx, t, r)
+        let t = iter::once(s).chain(t.iter().cloned());
+        Substs::new(tcx, t.map(Kind::from))
     }
 
     pub fn empty(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx Substs<'tcx> {
-        Substs::new(tcx, vec![], vec![])
+        Substs::new(tcx, vec![])
     }
 
     /// Creates a Substs for generic parameter definitions,
@@ -60,19 +175,16 @@ pub fn for_item<FR, FT>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                             mut mk_region: FR,
                             mut mk_type: FT)
                             -> &'tcx Substs<'tcx>
-    where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> ty::Region,
+    where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> &'tcx ty::Region,
           FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> {
         let defs = tcx.lookup_generics(def_id);
-        let num_regions = defs.parent_regions as usize + defs.regions.len();
-        let num_types = defs.parent_types as usize + defs.types.len();
         let mut substs = Substs {
-            regions: Vec::with_capacity(num_regions),
-            types: Vec::with_capacity(num_types)
+            params: Vec::with_capacity(defs.count())
         };
 
         substs.fill_item(tcx, defs, &mut mk_region, &mut mk_type);
 
-        Substs::new(tcx, substs.types, substs.regions)
+        tcx.mk_substs(substs)
     }
 
     fn fill_item<FR, FT>(&mut self,
@@ -80,36 +192,76 @@ fn fill_item<FR, FT>(&mut self,
                          defs: &ty::Generics<'tcx>,
                          mk_region: &mut FR,
                          mk_type: &mut FT)
-    where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> ty::Region,
+    where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> &'tcx ty::Region,
           FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> {
         if let Some(def_id) = defs.parent {
             let parent_defs = tcx.lookup_generics(def_id);
             self.fill_item(tcx, parent_defs, mk_region, mk_type);
         }
 
+        // Handle Self first, before all regions.
+        let mut types = defs.types.iter();
+        if defs.parent.is_none() && defs.has_self {
+            let def = types.next().unwrap();
+            let ty = mk_type(def, self);
+            assert_eq!(def.index as usize, self.params.len());
+            self.params.push(Kind::from(ty));
+        }
+
         for def in &defs.regions {
             let region = mk_region(def, self);
-            assert_eq!(def.index as usize, self.regions.len());
-            self.regions.push(region);
+            assert_eq!(def.index as usize, self.params.len());
+            self.params.push(Kind::from(region));
         }
 
-        for def in &defs.types {
+        for def in types {
             let ty = mk_type(def, self);
-            assert_eq!(def.index as usize, self.types.len());
-            self.types.push(ty);
+            assert_eq!(def.index as usize, self.params.len());
+            self.params.push(Kind::from(ty));
         }
     }
 
     pub fn is_noop(&self) -> bool {
-        self.regions.is_empty() && self.types.is_empty()
+        self.params.is_empty()
+    }
+
+    #[inline]
+    pub fn params(&self) -> &[Kind<'tcx>] {
+        &self.params
+    }
+
+    #[inline]
+    pub fn types(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
+        self.params.iter().filter_map(|k| k.as_type())
+    }
+
+    #[inline]
+    pub fn regions(&'a self) -> impl DoubleEndedIterator<Item=&'tcx ty::Region> + 'a {
+        self.params.iter().filter_map(|k| k.as_region())
+    }
+
+    #[inline]
+    pub fn type_at(&self, i: usize) -> Ty<'tcx> {
+        self.params[i].as_type().unwrap_or_else(|| {
+            bug!("expected type for param #{} in {:?}", i, self.params);
+        })
     }
 
+    #[inline]
+    pub fn region_at(&self, i: usize) -> &'tcx ty::Region {
+        self.params[i].as_region().unwrap_or_else(|| {
+            bug!("expected region for param #{} in {:?}", i, self.params);
+        })
+    }
+
+    #[inline]
     pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> {
-        self.types[ty_param_def.index as usize]
+        self.type_at(ty_param_def.index as usize)
     }
 
-    pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> ty::Region {
-        self.regions[def.index as usize]
+    #[inline]
+    pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> &'tcx ty::Region {
+        self.region_at(def.index as usize)
     }
 
     /// Transform from substitutions for a child of `source_ancestor`
@@ -122,11 +274,27 @@ pub fn rebase_onto(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                        target_substs: &Substs<'tcx>)
                        -> &'tcx Substs<'tcx> {
         let defs = tcx.lookup_generics(source_ancestor);
-        let regions = target_substs.regions.iter()
-            .chain(&self.regions[defs.regions.len()..]).cloned().collect();
-        let types = target_substs.types.iter()
-            .chain(&self.types[defs.types.len()..]).cloned().collect();
-        Substs::new(tcx, types, regions)
+        tcx.mk_substs(Substs {
+            params: target_substs.params.iter()
+                .chain(&self.params[defs.own_count()..]).cloned().collect()
+        })
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        let params = self.params.iter().map(|k| k.fold_with(folder)).collect();
+        folder.tcx().mk_substs(Substs {
+            params: params
+        })
+    }
+
+    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        folder.fold_substs(self)
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.params.visit_with(visitor)
     }
 }
 
@@ -215,16 +383,18 @@ fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binde
         t
     }
 
-    fn fold_region(&mut self, r: ty::Region) -> ty::Region {
+    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
         // Note: This routine only handles regions that are bound on
         // type declarations and other outer declarations, not those
         // bound in *fn types*. Region substitution of the bound
         // regions that appear in a function signature is done using
         // the specialized routine `ty::replace_late_regions()`.
-        match r {
+        match *r {
             ty::ReEarlyBound(data) => {
-                match self.substs.regions.get(data.index as usize) {
-                    Some(&r) => {
+                let r = self.substs.params.get(data.index as usize)
+                            .and_then(|k| k.as_region());
+                match r {
+                    Some(r) => {
                         self.shift_region_through_binders(r)
                     }
                     None => {
@@ -278,9 +448,10 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
 impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
     fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
         // Look up the type in the substitutions. It really should be in there.
-        let opt_ty = self.substs.types.get(p.idx as usize);
+        let opt_ty = self.substs.params.get(p.idx as usize)
+                         .and_then(|k| k.as_type());
         let ty = match opt_ty {
-            Some(t) => *t,
+            Some(t) => t,
             None => {
                 let span = self.span.unwrap_or(DUMMY_SP);
                 span_bug!(
@@ -291,7 +462,7 @@ fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
                     source_ty,
                     p.idx,
                     self.root_ty,
-                    self.substs);
+                    self.substs.params);
             }
         };
 
@@ -354,8 +525,8 @@ fn shift_regions_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
         result
     }
 
-    fn shift_region_through_binders(&self, region: ty::Region) -> ty::Region {
-        ty::fold::shift_region(region, self.region_binders_passed)
+    fn shift_region_through_binders(&self, region: &'tcx ty::Region) -> &'tcx ty::Region {
+        self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed))
     }
 }
 
@@ -367,12 +538,11 @@ pub fn from_method(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                        substs: &Substs<'tcx>)
                        -> ty::TraitRef<'tcx> {
         let defs = tcx.lookup_generics(trait_id);
-        let regions = substs.regions[..defs.regions.len()].to_vec();
-        let types = substs.types[..defs.types.len()].to_vec();
 
+        let params = substs.params[..defs.own_count()].iter().cloned();
         ty::TraitRef {
             def_id: trait_id,
-            substs: Substs::new(tcx, types, regions)
+            substs: Substs::new(tcx, params)
         }
     }
 }
@@ -381,13 +551,13 @@ impl<'a, 'gcx, 'tcx> ty::ExistentialTraitRef<'tcx> {
     pub fn erase_self_ty(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                          trait_ref: ty::TraitRef<'tcx>)
                          -> ty::ExistentialTraitRef<'tcx> {
-        let Substs { mut types, regions } = trait_ref.substs.clone();
-
-        types.remove(0);
+        // Assert there is a Self.
+        trait_ref.substs.type_at(0);
 
+        let params = trait_ref.substs.params[1..].iter().cloned();
         ty::ExistentialTraitRef {
             def_id: trait_ref.def_id,
-            substs: Substs::new(tcx, types, regions)
+            substs: Substs::new(tcx, params)
         }
     }
 }
@@ -404,13 +574,11 @@ pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
         assert!(!self_ty.has_escaping_regions());
 
         self.map_bound(|trait_ref| {
-            let Substs { mut types, regions } = trait_ref.substs.clone();
-
-            types.insert(0, self_ty);
-
+            let params = trait_ref.substs.params.iter().cloned();
+            let params = iter::once(Kind::from(self_ty)).chain(params);
             ty::TraitRef {
                 def_id: trait_ref.def_id,
-                substs: Substs::new(tcx, types, regions)
+                substs: Substs::new(tcx, params)
             }
         })
     }
index 51710c13a7deacb9f389d0735be5376747d6784f..77d16287fedc6d5296f2c0063419f29d23d77d73 100644 (file)
@@ -306,7 +306,7 @@ pub fn struct_lockstep_tails(self,
     pub fn required_region_bounds(self,
                                   erased_self_ty: Ty<'tcx>,
                                   predicates: Vec<ty::Predicate<'tcx>>)
-                                  -> Vec<ty::Region>    {
+                                  -> Vec<&'tcx ty::Region>    {
         debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})",
                erased_self_ty,
                predicates);
@@ -318,7 +318,6 @@ pub fn required_region_bounds(self,
                 match predicate {
                     ty::Predicate::Projection(..) |
                     ty::Predicate::Trait(..) |
-                    ty::Predicate::Rfc1592(..) |
                     ty::Predicate::Equate(..) |
                     ty::Predicate::WellFormed(..) |
                     ty::Predicate::ObjectSafe(..) |
@@ -496,8 +495,8 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
         ty.super_visit_with(self)
     }
 
-    fn visit_region(&mut self, r: ty::Region) -> bool {
-        match r {
+    fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
+        match *r {
             ty::ReStatic | ty::ReErased => {
                 self.hash::<u32>(0);
             }
@@ -693,10 +692,7 @@ fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
                         return false;
                     }
 
-                    let types_a = &substs_a.types;
-                    let types_b = &substs_b.types;
-
-                    types_a.iter().zip(types_b).all(|(&a, &b)| same_type(a, b))
+                    substs_a.types().zip(substs_b.types()).all(|(a, b)| same_type(a, b))
                 }
                 _ => {
                     a == b
index 8a9ee45351dfc26c73813eb2835e8e368570f9a9..409f5a85997bda10eb0fff2eb5b76b28862d6a61 100644 (file)
@@ -67,6 +67,12 @@ pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter<Ty<'tcx>> {
     stack.into_iter()
 }
 
+// We push types on the stack in reverse order so as to
+// maintain a pre-order traversal. As of the time of this
+// writing, the fact that the traversal is pre-order is not
+// known to be significant to any code, but it seems like the
+// natural order one would expect (basically, the order of the
+// types as they are written).
 fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
     match parent_ty.sty {
         ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
@@ -79,28 +85,28 @@ fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
             stack.push(mt.ty);
         }
         ty::TyProjection(ref data) => {
-            push_reversed(stack, &data.trait_ref.substs.types);
+            stack.extend(data.trait_ref.substs.types().rev());
         }
         ty::TyTrait(ref obj) => {
-            push_reversed(stack, obj.principal.input_types());
-            push_reversed(stack, &obj.projection_bounds.iter().map(|pred| {
+            stack.extend(obj.principal.input_types().rev());
+            stack.extend(obj.projection_bounds.iter().map(|pred| {
                 pred.0.ty
-            }).collect::<Vec<_>>());
+            }).rev());
         }
         ty::TyEnum(_, ref substs) |
         ty::TyStruct(_, ref substs) |
         ty::TyAnon(_, ref substs) => {
-            push_reversed(stack, &substs.types);
+            stack.extend(substs.types().rev());
         }
         ty::TyClosure(_, ref substs) => {
-            push_reversed(stack, &substs.func_substs.types);
-            push_reversed(stack, &substs.upvar_tys);
+            stack.extend(substs.func_substs.types().rev());
+            stack.extend(substs.upvar_tys.iter().cloned().rev());
         }
-        ty::TyTuple(ref ts) => {
-            push_reversed(stack, ts);
+        ty::TyTuple(ts) => {
+            stack.extend(ts.iter().cloned().rev());
         }
         ty::TyFnDef(_, substs, ref ft) => {
-            push_reversed(stack, &substs.types);
+            stack.extend(substs.types().rev());
             push_sig_subtypes(stack, &ft.sig);
         }
         ty::TyFnPtr(ref ft) => {
@@ -111,17 +117,5 @@ fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
 
 fn push_sig_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, sig: &ty::PolyFnSig<'tcx>) {
     stack.push(sig.0.output);
-    push_reversed(stack, &sig.0.inputs);
-}
-
-fn push_reversed<'tcx>(stack: &mut Vec<Ty<'tcx>>, tys: &[Ty<'tcx>]) {
-    // We push slices on the stack in reverse order so as to
-    // maintain a pre-order traversal. As of the time of this
-    // writing, the fact that the traversal is pre-order is not
-    // known to be significant to any code, but it seems like the
-    // natural order one would expect (basically, the order of the
-    // types as they are written).
-    for &ty in tys.iter().rev() {
-        stack.push(ty);
-    }
+    stack.extend(sig.0.inputs.iter().cloned().rev());
 }
index 54b19362b1d86e43afd1b1c36b5a089f95b374c2..aef646a7aacafdfda6ab9be099be93e046d2342f 100644 (file)
@@ -94,9 +94,6 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
         }
         ty::Predicate::ClosureKind(..) => {
         }
-        ty::Predicate::Rfc1592(ref data) => {
-            bug!("RFC1592 predicate `{:?}` in predicate_obligations", data);
-        }
     }
 
     wf.normalize()
@@ -115,9 +112,9 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
 /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
 #[derive(Debug)]
 pub enum ImpliedBound<'tcx> {
-    RegionSubRegion(ty::Region, ty::Region),
-    RegionSubParam(ty::Region, ty::ParamTy),
-    RegionSubProjection(ty::Region, ty::ProjectionTy<'tcx>),
+    RegionSubRegion(&'tcx ty::Region, &'tcx ty::Region),
+    RegionSubParam(&'tcx ty::Region, ty::ParamTy),
+    RegionSubProjection(&'tcx ty::Region, ty::ProjectionTy<'tcx>),
 }
 
 /// Compute the implied bounds that a callee/impl can assume based on
@@ -158,7 +155,6 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>(
                 assert!(!obligation.has_escaping_regions());
                 match obligation.predicate {
                     ty::Predicate::Trait(..) |
-                    ty::Predicate::Rfc1592(..) |
                     ty::Predicate::Equate(..) |
                     ty::Predicate::Projection(..) |
                     ty::Predicate::ClosureKind(..) |
@@ -196,7 +192,7 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>(
 /// this down to determine what relationships would have to hold for
 /// `T: 'a` to hold. We get to assume that the caller has validated
 /// those relationships.
-fn implied_bounds_from_components<'tcx>(sub_region: ty::Region,
+fn implied_bounds_from_components<'tcx>(sub_region: &'tcx ty::Region,
                                         sup_components: Vec<Component<'tcx>>)
                                         -> Vec<ImpliedBound<'tcx>>
 {
@@ -260,8 +256,7 @@ fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
 
         let cause = self.cause(traits::MiscObligation);
         self.out.extend(
-            trait_ref.substs.types
-                            .iter()
+            trait_ref.substs.types()
                             .filter(|ty| !ty.has_escaping_regions())
                             .map(|ty| traits::Obligation::new(cause.clone(),
                                                               ty::Predicate::WellFormed(ty))));
@@ -283,21 +278,14 @@ fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) {
         }
     }
 
-    fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>,
-                     rfc1592: bool) {
+    fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
         if !subty.has_escaping_regions() {
             let cause = self.cause(cause);
             match self.infcx.tcx.trait_ref_for_builtin_bound(ty::BoundSized, subty) {
                 Ok(trait_ref) => {
-                    let predicate = trait_ref.to_predicate();
-                    let predicate = if rfc1592 {
-                        ty::Predicate::Rfc1592(box predicate)
-                    } else {
-                        predicate
-                    };
                     self.out.push(
                         traits::Obligation::new(cause,
-                                                predicate));
+                                                trait_ref.to_predicate()));
                 }
                 Err(ErrorReported) => { }
             }
@@ -327,13 +315,13 @@ fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
 
                 ty::TySlice(subty) |
                 ty::TyArray(subty, _) => {
-                    self.require_sized(subty, traits::SliceOrArrayElem, false);
+                    self.require_sized(subty, traits::SliceOrArrayElem);
                 }
 
                 ty::TyTuple(ref tys) => {
                     if let Some((_last, rest)) = tys.split_last() {
                         for elem in rest {
-                            self.require_sized(elem, traits::TupleElem, true);
+                            self.require_sized(elem, traits::TupleElem);
                         }
                     }
                 }
@@ -364,7 +352,7 @@ fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
                                 cause,
                                 ty::Predicate::TypeOutlives(
                                     ty::Binder(
-                                        ty::OutlivesPredicate(mt.ty, *r)))));
+                                        ty::OutlivesPredicate(mt.ty, r)))));
                     }
                 }
 
@@ -402,22 +390,15 @@ fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
 
                     let cause = self.cause(traits::MiscObligation);
 
-                    // FIXME(#33243): remove RFC1592
-                    self.out.push(traits::Obligation::new(
-                        cause.clone(),
-                        ty::Predicate::ObjectSafe(data.principal.def_id())
-                    ));
                     let component_traits =
                         data.builtin_bounds.iter().flat_map(|bound| {
                             tcx.lang_items.from_builtin_kind(bound).ok()
-                        });
-//                        .chain(Some(data.principal.def_id()));
+                        })
+                        .chain(Some(data.principal.def_id()));
                     self.out.extend(
                         component_traits.map(|did| { traits::Obligation::new(
                             cause.clone(),
-                            ty::Predicate::Rfc1592(
-                                box ty::Predicate::ObjectSafe(did)
-                            )
+                            ty::Predicate::ObjectSafe(did)
                         )})
                     );
                 }
@@ -535,7 +516,7 @@ pub fn object_region_bounds<'a, 'gcx, 'tcx>(
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     principal: ty::PolyExistentialTraitRef<'tcx>,
     others: ty::BuiltinBounds)
-    -> Vec<ty::Region>
+    -> Vec<&'tcx ty::Region>
 {
     // Since we don't actually *know* the self type for an object,
     // this "open(err)" serves as a kind of dummy standin -- basically
index f4e1c06090e591a9d5d2abd1f33d4db4b019b10f..d7800ccaa5dd393e598cdba8d106598c47ed3af6 100644 (file)
@@ -56,14 +56,49 @@ pub fn fix_windows_verbatim_for_gcc(p: &Path) -> PathBuf {
     }
 }
 
+pub enum LinkOrCopy {
+    Link,
+    Copy
+}
+
 /// Copy `p` into `q`, preferring to use hard-linking if possible. If
 /// `q` already exists, it is removed first.
-pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<()> {
+/// The result indicates which of the two operations has been performed.
+pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<LinkOrCopy> {
     let p = p.as_ref();
     let q = q.as_ref();
     if q.exists() {
         try!(fs::remove_file(&q));
     }
-    fs::hard_link(p, q)
-        .or_else(|_| fs::copy(p, q).map(|_| ()))
+
+    match fs::hard_link(p, q) {
+        Ok(()) => Ok(LinkOrCopy::Link),
+        Err(_) => {
+            match fs::copy(p, q) {
+                Ok(_) => Ok(LinkOrCopy::Copy),
+                Err(e) => Err(e)
+            }
+        }
+    }
+}
+
+// Like std::fs::create_dir_all, except handles concurrent calls among multiple
+// threads or processes.
+pub fn create_dir_racy(path: &Path) -> io::Result<()> {
+    match fs::create_dir(path) {
+        Ok(()) => return Ok(()),
+        Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(()),
+        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
+        Err(e) => return Err(e),
+    }
+    match path.parent() {
+        Some(p) => try!(create_dir_racy(p)),
+        None => return Err(io::Error::new(io::ErrorKind::Other,
+                                          "failed to create whole tree")),
+    }
+    match fs::create_dir(path) {
+        Ok(()) => Ok(()),
+        Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()),
+        Err(e) => Err(e),
+    }
 }
index 02ad8fb7033ed2d50d9900bf2fe2d42864cd9748..7e2cc2938ca9e4b1763c336288673c36b0181b12 100644 (file)
@@ -22,6 +22,8 @@
 
 use std::cell::Cell;
 use std::fmt;
+use std::usize;
+
 use syntax::abi::Abi;
 use syntax::parse::token;
 use syntax::ast::CRATE_NODE_ID;
@@ -80,15 +82,17 @@ pub fn parameterized(f: &mut fmt::Formatter,
         verbose = tcx.sess.verbose();
         has_self = generics.has_self;
 
+        let mut child_types = 0;
         if let Some(def_id) = generics.parent {
             // Methods.
             assert_eq!(ns, Ns::Value);
+            child_types = generics.types.len();
             generics = tcx.lookup_generics(def_id);
             num_regions = generics.regions.len();
             num_types = generics.types.len();
 
             if has_self {
-                write!(f, "<{} as ", substs.types[0])?;
+                write!(f, "<{} as ", substs.type_at(0))?;
             }
 
             item_name = Some(tcx.item_name(did));
@@ -107,8 +111,8 @@ pub fn parameterized(f: &mut fmt::Formatter,
         if !verbose {
             if generics.types.last().map_or(false, |def| def.default.is_some()) {
                 if let Some(substs) = tcx.lift(&substs) {
-                    let tps = &substs.types[..num_types];
-                    for (def, actual) in generics.types.iter().zip(tps).rev() {
+                    let tps = substs.types().rev().skip(child_types);
+                    for (def, actual) in generics.types.iter().rev().zip(tps) {
                         if def.default.subst(tcx, substs) != Some(actual) {
                             break;
                         }
@@ -124,7 +128,7 @@ pub fn parameterized(f: &mut fmt::Formatter,
 
     if !verbose && fn_trait_kind.is_some() && projections.len() == 1 {
         let projection_ty = projections[0].ty;
-        if let TyTuple(ref args) = substs.types[1].sty {
+        if let TyTuple(ref args) = substs.type_at(1).sty {
             return fn_sig(f, args, false, projection_ty);
         }
     }
@@ -139,13 +143,15 @@ pub fn parameterized(f: &mut fmt::Formatter,
         }
     };
 
-    let print_regions = |f: &mut fmt::Formatter, start: &str, regions: &[ty::Region]| {
+    let print_regions = |f: &mut fmt::Formatter, start: &str, skip, count| {
         // Don't print any regions if they're all erased.
-        if regions.iter().all(|r| *r == ty::ReErased) {
+        let regions = || substs.regions().skip(skip).take(count);
+        if regions().all(|r: &ty::Region| *r == ty::ReErased) {
             return Ok(());
         }
 
-        for region in regions {
+        for region in regions() {
+            let region: &ty::Region = region;
             start_or_continue(f, start, ", ")?;
             if verbose {
                 write!(f, "{:?}", region)?;
@@ -167,11 +173,12 @@ pub fn parameterized(f: &mut fmt::Formatter,
         Ok(())
     };
 
-    print_regions(f, "<", &substs.regions[..num_regions])?;
+    print_regions(f, "<", 0, num_regions)?;
 
-    let tps = &substs.types[..num_types];
+    let tps = substs.types().take(num_types - num_supplied_defaults)
+                            .skip(has_self as usize);
 
-    for &ty in &tps[has_self as usize..tps.len() - num_supplied_defaults] {
+    for ty in tps {
         start_or_continue(f, "<", ", ")?;
         write!(f, "{}", ty)?;
     }
@@ -197,10 +204,10 @@ pub fn parameterized(f: &mut fmt::Formatter,
             write!(f, "::{}", item_name)?;
         }
 
-        print_regions(f, "::<", &substs.regions[num_regions..])?;
+        print_regions(f, "::<", num_regions, usize::MAX)?;
 
         // FIXME: consider being smart with defaults here too
-        for ty in &substs.types[num_types..] {
+        for ty in substs.types().skip(num_types) {
             start_or_continue(f, "::<", ", ")?;
             write!(f, "{}", ty)?;
         }
@@ -240,7 +247,7 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
 
     let new_value = tcx.replace_late_bound_regions(&value, |br| {
         let _ = start_or_continue(f, "for<", ", ");
-        ty::ReLateBound(ty::DebruijnIndex::new(1), match br {
+        let br = match br {
             ty::BrNamed(_, name, _) => {
                 let _ = write!(f, "{}", name);
                 br
@@ -254,7 +261,8 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
                             name,
                             ty::Issue32330::WontChange)
             }
-        })
+        };
+        tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br))
     }).0;
 
     start_or_continue(f, "", "> ")?;
@@ -344,7 +352,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-impl fmt::Debug for ty::RegionParameterDef {
+impl<'tcx> fmt::Debug for ty::RegionParameterDef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "RegionParameterDef({}, {:?}, {}, {:?})",
                self.name,
@@ -368,13 +376,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-impl<'tcx> fmt::Debug for Substs<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Substs[types={:?}, regions={:?}]",
-               self.types, self.regions)
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::ItemSubsts<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "ItemSubsts({:?})", self.substs)
@@ -486,9 +487,6 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             ty::Predicate::Trait(ref a) => write!(f, "{:?}", a),
-            ty::Predicate::Rfc1592(ref a) => {
-                write!(f, "RFC1592({:?})", a)
-            }
             ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair),
             ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair),
             ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair),
@@ -598,7 +596,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::ObjectLifetimeDefault {
+impl<'tcx> fmt::Debug for ty::ObjectLifetimeDefault<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             ty::ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"),
@@ -654,13 +652,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-impl fmt::Debug for ty::ItemVariances {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "ItemVariances(types={:?}, regions={:?})",
-               self.types, self.regions)
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::GenericPredicates<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "GenericPredicates({:?})", self.predicates)
@@ -793,13 +784,14 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, ty::Region>> {
+impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, &'tcx ty::Region>> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
     }
 }
 
-impl fmt::Display for ty::Binder<ty::OutlivesPredicate<ty::Region, ty::Region>> {
+impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<&'tcx ty::Region,
+                                                             &'tcx ty::Region>> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
     }
@@ -973,7 +965,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-impl fmt::Debug for ty::UpvarBorrow {
+impl<'tcx> fmt::Debug for ty::UpvarBorrow<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "UpvarBorrow({:?}, {:?})",
                self.kind, self.region)
@@ -997,7 +989,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-impl fmt::Display for ty::ExplicitSelfCategory {
+impl<'tcx> fmt::Display for ty::ExplicitSelfCategory<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.write_str(match *self {
             ty::ExplicitSelfCategory::Static => "static",
@@ -1088,7 +1080,6 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             ty::Predicate::Trait(ref data) => write!(f, "{}", data),
-            ty::Predicate::Rfc1592(ref data) => write!(f, "{}", data),
             ty::Predicate::Equate(ref predicate) => write!(f, "{}", predicate),
             ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate),
             ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate),
index 52269f0cd4a08788408745f8dbc202bd728e6992..7e0306a03e2f6bf93b6b0f81b6a83697c8cfed6b 100644 (file)
@@ -23,8 +23,9 @@ pub fn target() -> TargetResult {
         target_vendor: "unknown".to_string(),
 
         options: TargetOptions {
-            features: "+v7,+vfp3,+neon".to_string(),
-            cpu: "cortex-a8".to_string(),
+            // Info about features at https://wiki.debian.org/ArmHardFloatPort
+            features: "+v7,+vfp3,+d16,+thumb2".to_string(),
+            cpu: "generic".to_string(),
             max_atomic_width: 64,
             .. base
         }
diff --git a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs
new file mode 100644 (file)
index 0000000..8378563
--- /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.
+
+use target::{Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    Ok(Target {
+        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(),
+        arch: "mips64".to_string(),
+        target_os: "linux".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "unknown".to_string(),
+        options: TargetOptions {
+            // NOTE(mips64r2) matches C toolchain
+            cpu: "mips64r2".to_string(),
+            features: "+mips64r2".to_string(),
+            max_atomic_width: 64,
+            ..super::linux_base::opts()
+        },
+    })
+}
diff --git a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs
new file mode 100644 (file)
index 0000000..e1340e8
--- /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.
+
+use target::{Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    Ok(Target {
+        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(),
+        arch: "mips64".to_string(),
+        target_os: "linux".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "unknown".to_string(),
+        options: TargetOptions {
+            // NOTE(mips64r2) matches C toolchain
+            cpu: "mips64r2".to_string(),
+            features: "+mips64r2".to_string(),
+            max_atomic_width: 64,
+            ..super::linux_base::opts()
+        },
+    })
+}
diff --git a/src/librustc_back/target/mips_unknown_linux_uclibc.rs b/src/librustc_back/target/mips_unknown_linux_uclibc.rs
new file mode 100644 (file)
index 0000000..529bd31
--- /dev/null
@@ -0,0 +1,30 @@
+// 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 target::{Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    Ok(Target {
+        llvm_target: "mips-unknown-linux-uclibc".to_string(),
+        target_endian: "big".to_string(),
+        target_pointer_width: "32".to_string(),
+        data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
+        arch: "mips".to_string(),
+        target_os: "linux".to_string(),
+        target_env: "uclibc".to_string(),
+        target_vendor: "unknown".to_string(),
+        options: TargetOptions {
+            cpu: "mips32r2".to_string(),
+            features: "+mips32r2,+soft-float".to_string(),
+            max_atomic_width: 32,
+            ..super::linux_base::opts()
+        },
+    })
+}
diff --git a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs
new file mode 100644 (file)
index 0000000..1040a0f
--- /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.
+
+use target::{Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    Ok(Target {
+        llvm_target: "mipsel-unknown-linux-uclibc".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
+        arch: "mips".to_string(),
+        target_os: "linux".to_string(),
+        target_env: "uclibc".to_string(),
+        target_vendor: "unknown".to_string(),
+
+        options: TargetOptions {
+            cpu: "mips32".to_string(),
+            features: "+mips32,+soft-float".to_string(),
+            max_atomic_width: 32,
+            ..super::linux_base::opts()
+        },
+    })
+}
index 18686e3f1d6489e642f0735755485cba953fbe62..d48370b23b69d6cb8479f9ea1ce348c78614907c 100644 (file)
@@ -128,10 +128,13 @@ fn $module() {
     ("i686-unknown-linux-gnu", i686_unknown_linux_gnu),
     ("i586-unknown-linux-gnu", i586_unknown_linux_gnu),
     ("mips-unknown-linux-gnu", mips_unknown_linux_gnu),
+    ("mips64-unknown-linux-gnuabi64", mips64_unknown_linux_gnuabi64),
+    ("mips64el-unknown-linux-gnuabi64", mips64el_unknown_linux_gnuabi64),
     ("mipsel-unknown-linux-gnu", mipsel_unknown_linux_gnu),
     ("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu),
     ("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu),
     ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
+    ("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu),
     ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi),
     ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf),
     ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi),
@@ -143,6 +146,8 @@ fn $module() {
     ("i686-unknown-linux-musl", i686_unknown_linux_musl),
     ("mips-unknown-linux-musl", mips_unknown_linux_musl),
     ("mipsel-unknown-linux-musl", mipsel_unknown_linux_musl),
+    ("mips-unknown-linux-uclibc", mips_unknown_linux_uclibc),
+    ("mipsel-unknown-linux-uclibc", mipsel_unknown_linux_uclibc),
 
     ("i686-linux-android", i686_linux_android),
     ("arm-linux-androideabi", arm_linux_androideabi),
diff --git a/src/librustc_back/target/s390x_unknown_linux_gnu.rs b/src/librustc_back/target/s390x_unknown_linux_gnu.rs
new file mode 100644 (file)
index 0000000..895d33d
--- /dev/null
@@ -0,0 +1,30 @@
+// 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 target::{Target, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::linux_base::opts();
+    // NOTE(zEC12) matches C toolchain
+    base.cpu = "zEC12".to_string();
+    base.max_atomic_width = 64;
+
+    Ok(Target {
+        llvm_target: "s390x-unknown-linux-gnu".to_string(),
+        target_endian: "big".to_string(),
+        target_pointer_width: "64".to_string(),
+        data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64".to_string(),
+        arch: "s390x".to_string(),
+        target_os: "linux".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "unknown".to_string(),
+        options: base,
+    })
+}
index 9cae270984f0047cce5f873e6004b5c47fe6722b..e86fa9a05f372c4eb1e2503a5a996a6855ac74c8 100644 (file)
@@ -126,7 +126,7 @@ fn borrow(&mut self,
               borrow_id: ast::NodeId,
               borrow_span: Span,
               cmt: mc::cmt<'tcx>,
-              loan_region: ty::Region,
+              loan_region: &'tcx ty::Region,
               bk: ty::BorrowKind,
               loan_cause: euv::LoanCause)
     {
@@ -647,10 +647,13 @@ fn check_for_copy_of_frozen_path(&self,
                 struct_span_err!(self.bccx, span, E0503,
                                  "cannot use `{}` because it was mutably borrowed",
                                  &self.bccx.loan_path_to_string(copy_path))
-                    .span_note(loan_span,
+                    .span_label(loan_span,
                                &format!("borrow of `{}` occurs here",
                                        &self.bccx.loan_path_to_string(&loan_path))
                                )
+                    .span_label(span,
+                               &format!("use of borrowed `{}`",
+                                        &self.bccx.loan_path_to_string(&loan_path)))
                     .emit();
             }
         }
index d3d6fa9eb52b59dc46db40f6b15d5350eb1d951b..a8993724e670630ca2a5fdbacc1fbb012116152a 100644 (file)
@@ -27,7 +27,6 @@
 use std::mem;
 use std::rc::Rc;
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax_pos::{Span, DUMMY_SP};
 
 #[derive(PartialEq, Eq, PartialOrd, Ord)]
index e34c6e567bd8ece197adcf425ef455f1e2d9eb22..9f95175d59d439217bdc5b9e3642b38e2640943b 100644 (file)
@@ -28,7 +28,7 @@ pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                     span: Span,
                                     cause: euv::LoanCause,
                                     cmt: mc::cmt<'tcx>,
-                                    loan_region: ty::Region,
+                                    loan_region: &'tcx ty::Region,
                                     _: ty::BorrowKind)
                                     -> Result<(),()> {
     //! Reports error if `loan_region` is larger than S
@@ -56,7 +56,7 @@ struct GuaranteeLifetimeContext<'a, 'tcx: 'a> {
 
     span: Span,
     cause: euv::LoanCause,
-    loan_region: ty::Region,
+    loan_region: &'tcx ty::Region,
     cmt_original: mc::cmt<'tcx>
 }
 
@@ -92,17 +92,17 @@ fn check(&self, cmt: &mc::cmt<'tcx>, discr_scope: Option<ast::NodeId>) -> R {
         }
     }
 
-    fn check_scope(&self, max_scope: ty::Region) -> R {
+    fn check_scope(&self, max_scope: &'tcx ty::Region) -> R {
         //! Reports an error if `loan_region` is larger than `max_scope`
 
         if !self.bccx.is_subregion_of(self.loan_region, max_scope) {
-            Err(self.report_error(err_out_of_scope(max_scope, self.loan_region)))
+            Err(self.report_error(err_out_of_scope(max_scope, self.loan_region, self.cause)))
         } else {
             Ok(())
         }
     }
 
-    fn scope(&self, cmt: &mc::cmt) -> ty::Region {
+    fn scope(&self, cmt: &mc::cmt<'tcx>) -> &'tcx ty::Region {
         //! Returns the maximal region scope for the which the
         //! lvalue `cmt` is guaranteed to be valid without any
         //! rooting etc, and presuming `cmt` is not mutated.
@@ -112,16 +112,15 @@ fn scope(&self, cmt: &mc::cmt) -> ty::Region {
                 temp_scope
             }
             Categorization::Upvar(..) => {
-                ty::ReScope(self.item_scope)
-            }
-            Categorization::StaticItem => {
-                ty::ReStatic
+                self.bccx.tcx.mk_region(ty::ReScope(self.item_scope))
             }
             Categorization::Local(local_id) => {
-                ty::ReScope(self.bccx.tcx.region_maps.var_scope(local_id))
+                self.bccx.tcx.mk_region(ty::ReScope(
+                    self.bccx.tcx.region_maps.var_scope(local_id)))
             }
+            Categorization::StaticItem |
             Categorization::Deref(_, _, mc::UnsafePtr(..)) => {
-                ty::ReStatic
+                self.bccx.tcx.mk_region(ty::ReStatic)
             }
             Categorization::Deref(_, _, mc::BorrowedPtr(_, r)) |
             Categorization::Deref(_, _, mc::Implicit(_, r)) => {
@@ -135,7 +134,7 @@ fn scope(&self, cmt: &mc::cmt) -> ty::Region {
         }
     }
 
-    fn report_error(&self, code: bckerr_code) {
+    fn report_error(&self, code: bckerr_code<'tcx>) {
         self.bccx.report(BckError { cmt: self.cmt_original.clone(),
                                     span: self.span,
                                     cause: BorrowViolation(self.cause),
index c982fc091d24c0d8ddebce581190335a86635ca8..a255564f01e255397f0c8a538e28df1c3d906096 100644 (file)
@@ -130,7 +130,7 @@ fn borrow(&mut self,
               borrow_id: ast::NodeId,
               borrow_span: Span,
               cmt: mc::cmt<'tcx>,
-              loan_region: ty::Region,
+              loan_region: &'tcx ty::Region,
               bk: ty::BorrowKind,
               loan_cause: euv::LoanCause)
     {
@@ -307,7 +307,7 @@ fn guarantee_valid(&mut self,
                        borrow_span: Span,
                        cmt: mc::cmt<'tcx>,
                        req_kind: ty::BorrowKind,
-                       loan_region: ty::Region,
+                       loan_region: &'tcx ty::Region,
                        cause: euv::LoanCause) {
         debug!("guarantee_valid(borrow_id={}, cmt={:?}, \
                 req_mutbl={:?}, loan_region={:?})",
@@ -318,7 +318,7 @@ fn guarantee_valid(&mut self,
 
         // a loan for the empty region can never be dereferenced, so
         // it is always safe
-        if loan_region == ty::ReEmpty {
+        if *loan_region == ty::ReEmpty {
             return;
         }
 
@@ -358,7 +358,7 @@ fn guarantee_valid(&mut self,
             }
 
             RestrictionResult::SafeIf(loan_path, restricted_paths) => {
-                let loan_scope = match loan_region {
+                let loan_scope = match *loan_region {
                     ty::ReScope(scope) => scope,
 
                     ty::ReFree(ref fr) => fr.scope,
index 3d9df4c8bd0082c2220af04904811d9d4a2a8146..d08f792b30c144251e1d3938db237025bc101d9c 100644 (file)
@@ -31,7 +31,7 @@ pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                       span: Span,
                                       cause: euv::LoanCause,
                                       cmt: mc::cmt<'tcx>,
-                                      loan_region: ty::Region)
+                                      loan_region: &'tcx ty::Region)
                                       -> RestrictionResult<'tcx> {
     let ctxt = RestrictionsContext {
         bccx: bccx,
@@ -49,7 +49,7 @@ pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
 struct RestrictionsContext<'a, 'tcx: 'a> {
     bccx: &'a BorrowckCtxt<'a, 'tcx>,
     span: Span,
-    loan_region: ty::Region,
+    loan_region: &'tcx ty::Region,
     cause: euv::LoanCause,
 }
 
@@ -157,7 +157,7 @@ fn restrict(&self,
     fn extend(&self,
               result: RestrictionResult<'tcx>,
               cmt: &mc::cmt<'tcx>,
-              elem: LoanPathElem) -> RestrictionResult<'tcx> {
+              elem: LoanPathElem<'tcx>) -> RestrictionResult<'tcx> {
         match result {
             RestrictionResult::Safe => RestrictionResult::Safe,
             RestrictionResult::SafeIf(base_lp, mut base_vec) => {
index 90858e4e8b8be2c4c717dfe91873d0d34a033a31..c46daf9c22537226dbadb5d422157eb399b4aab6 100644 (file)
@@ -9,10 +9,9 @@
 // except according to those terms.
 
 use rustc::ty::TyCtxt;
-use rustc::mir::repr::{self, Mir};
+use rustc::mir::repr::{self, Mir, Location};
 use rustc_data_structures::indexed_vec::Idx;
 
-use super::super::gather_moves::{Location};
 use super::super::gather_moves::{MoveOutIndex, MovePathIndex};
 use super::super::MoveDataParamEnv;
 use super::super::DropFlagState;
@@ -252,7 +251,7 @@ fn statement_effect(&self,
     {
         drop_flag_effects_for_location(
             self.tcx, self.mir, ctxt,
-            Location { block: bb, index: idx },
+            Location { block: bb, statement_index: idx },
             |path, s| Self::update_bits(sets, path, s)
         )
     }
@@ -265,7 +264,7 @@ fn terminator_effect(&self,
     {
         drop_flag_effects_for_location(
             self.tcx, self.mir, ctxt,
-            Location { block: bb, index: statements_len },
+            Location { block: bb, statement_index: statements_len },
             |path, s| Self::update_bits(sets, path, s)
         )
     }
@@ -314,7 +313,7 @@ fn statement_effect(&self,
     {
         drop_flag_effects_for_location(
             self.tcx, self.mir, ctxt,
-            Location { block: bb, index: idx },
+            Location { block: bb, statement_index: idx },
             |path, s| Self::update_bits(sets, path, s)
         )
     }
@@ -327,7 +326,7 @@ fn terminator_effect(&self,
     {
         drop_flag_effects_for_location(
             self.tcx, self.mir, ctxt,
-            Location { block: bb, index: statements_len },
+            Location { block: bb, statement_index: statements_len },
             |path, s| Self::update_bits(sets, path, s)
         )
     }
@@ -375,7 +374,7 @@ fn statement_effect(&self,
     {
         drop_flag_effects_for_location(
             self.tcx, self.mir, ctxt,
-            Location { block: bb, index: idx },
+            Location { block: bb, statement_index: idx },
             |path, s| Self::update_bits(sets, path, s)
         )
     }
@@ -388,7 +387,7 @@ fn terminator_effect(&self,
     {
         drop_flag_effects_for_location(
             self.tcx, self.mir, ctxt,
-            Location { block: bb, index: statements_len },
+            Location { block: bb, statement_index: statements_len },
             |path, s| Self::update_bits(sets, path, s)
         )
     }
@@ -431,7 +430,7 @@ fn statement_effect(&self,
         let path_map = &move_data.path_map;
         let rev_lookup = &move_data.rev_lookup;
 
-        let loc = Location { block: bb, index: idx };
+        let loc = Location { block: bb, statement_index: idx };
         debug!("stmt {:?} at loc {:?} moves out of move_indexes {:?}",
                stmt, loc, &loc_map[loc]);
         for move_index in &loc_map[loc] {
@@ -473,7 +472,7 @@ fn terminator_effect(&self,
         let (mir, move_data) = (self.mir, &ctxt.move_data);
         let term = mir[bb].terminator();
         let loc_map = &move_data.loc_map;
-        let loc = Location { block: bb, index: statements_len };
+        let loc = Location { block: bb, statement_index: statements_len };
         debug!("terminator {:?} at loc {:?} moves out of move_indexes {:?}",
                term, loc, &loc_map[loc]);
         let bits_per_block = self.bits_per_block(ctxt);
index 111646912ade30998060c70694305ce1dcbe5b8f..885bbe856c8fb441c9bfe14b864314afa08e3f16 100644 (file)
@@ -9,14 +9,14 @@
 // except according to those terms.
 
 use indexed_set::IdxSetBuf;
-use super::gather_moves::{MoveData, MovePathIndex, MovePathContent, Location};
+use super::gather_moves::{MoveData, MovePathIndex, MovePathContent};
 use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
 use super::dataflow::{DataflowResults};
 use super::{drop_flag_effects_for_location, on_all_children_bits};
 use super::{DropFlagState, MoveDataParamEnv};
 use super::patch::MirPatch;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::subst::{Subst, Substs};
+use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::mir::repr::*;
 use rustc::mir::transform::{Pass, MirPass, MirSource};
 use rustc::middle::const_val::ConstVal;
@@ -26,6 +26,7 @@
 use syntax_pos::Span;
 
 use std::fmt;
+use std::iter;
 use std::u32;
 
 pub struct ElaborateDrops;
@@ -146,9 +147,9 @@ fn initialization_data_at(&self, loc: Location) -> InitializationData {
             dead: self.flow_uninits.sets().on_entry_set_for(loc.block.index())
                 .to_owned(),
         };
-        for stmt in 0..loc.index {
+        for stmt in 0..loc.statement_index {
             data.apply_location(self.tcx, self.mir, self.env,
-                                Location { block: loc.block, index: stmt });
+                                Location { block: loc.block, statement_index: stmt });
         }
         data
     }
@@ -226,7 +227,7 @@ fn collect_drop_flags(&mut self)
 
             let init_data = self.initialization_data_at(Location {
                 block: bb,
-                index: data.statements.len()
+                statement_index: data.statements.len()
             });
 
             let path = self.move_data().rev_lookup.find(location);
@@ -249,7 +250,7 @@ fn collect_drop_flags(&mut self)
     fn elaborate_drops(&mut self)
     {
         for (bb, data) in self.mir.basic_blocks().iter_enumerated() {
-            let loc = Location { block: bb, index: data.statements.len() };
+            let loc = Location { block: bb, statement_index: data.statements.len() };
             let terminator = data.terminator();
 
             let resume_block = self.patch.resume_block();
@@ -359,9 +360,9 @@ fn elaborate_replace(
                 unwind: Some(unwind)
             }, bb);
             on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| {
-                self.set_drop_flag(Location { block: target, index: 0 },
+                self.set_drop_flag(Location { block: target, statement_index: 0 },
                                    child, DropFlagState::Present);
-                self.set_drop_flag(Location { block: unwind, index: 0 },
+                self.set_drop_flag(Location { block: unwind, statement_index: 0 },
                                    child, DropFlagState::Present);
             });
         }
@@ -741,7 +742,7 @@ fn complete_drop<'a>(
         let drop_block = self.drop_block(c);
         if update_drop_flag {
             self.set_drop_flag(
-                Location { block: drop_block, index: 0 },
+                Location { block: drop_block, statement_index: 0 },
                 c.path,
                 DropFlagState::Absent
             );
@@ -859,7 +860,7 @@ fn unelaborated_free_block<'a>(
         let unit_temp = Lvalue::Temp(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, vec![ty], vec![]);
+        let substs = Substs::new(tcx, iter::once(Kind::from(ty)));
         let fty = tcx.lookup_item_type(free_func).ty.subst(tcx, substs);
 
         self.patch.new_block(BasicBlockData {
@@ -924,7 +925,7 @@ fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagSta
     }
 
     fn drop_flags_on_init(&mut self) {
-        let loc = Location { block: START_BLOCK, index: 0 };
+        let loc = Location { block: START_BLOCK, statement_index: 0 };
         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() {
@@ -939,7 +940,7 @@ fn drop_flags_for_fn_rets(&mut self) {
             } = data.terminator().kind {
                 assert!(!self.patch.is_patched(bb));
 
-                let loc = Location { block: tgt, index: 0 };
+                let loc = Location { block: tgt, statement_index: 0 };
                 let path = self.move_data().rev_lookup.find(lv);
                 on_all_children_bits(
                     self.tcx, self.mir, self.move_data(), path,
@@ -950,7 +951,7 @@ fn drop_flags_for_fn_rets(&mut self) {
     }
 
     fn drop_flags_for_args(&mut self) {
-        let loc = Location { block: START_BLOCK, index: 0 };
+        let loc = Location { block: START_BLOCK, statement_index: 0 };
         super::drop_flag_effects_for_function_entry(
             self.tcx, self.mir, self.env, |path, ds| {
                 self.set_drop_flag(loc, path, ds);
@@ -990,7 +991,7 @@ fn drop_flags_for_locs(&mut self) {
                         }
                     }
                 }
-                let loc = Location { block: bb, index: i };
+                let loc = Location { block: bb, statement_index: i };
                 super::drop_flag_effects_for_location(
                     self.tcx, self.mir, self.env, loc, |path, ds| {
                         if ds == DropFlagState::Absent || allow_initializations {
@@ -1008,7 +1009,7 @@ fn drop_flags_for_locs(&mut self) {
             } = data.terminator().kind {
                 assert!(!self.patch.is_patched(bb));
 
-                let loc = Location { block: bb, index: data.statements.len() };
+                let loc = Location { block: bb, statement_index: data.statements.len() };
                 let path = self.move_data().rev_lookup.find(lv);
                 on_all_children_bits(
                     self.tcx, self.mir, self.move_data(), path,
index 8ae40e71bee58a6eac20fc76e55c66938aceab60..01bf8ed0e4b57679a379adf8854a6ad1cd5c1b1c 100644 (file)
@@ -160,8 +160,8 @@ impl Index<Location> for LocMap {
     type Output = [MoveOutIndex];
     fn index(&self, index: Location) -> &Self::Output {
         assert!(index.block.index() < self.map.len());
-        assert!(index.index < self.map[index.block.index()].len());
-        &self.map[index.block.index()][index.index]
+        assert!(index.statement_index < self.map[index.block.index()].len());
+        &self.map[index.block.index()][index.statement_index]
     }
 }
 
@@ -200,21 +200,6 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub struct Location {
-    /// block where action is located
-    pub block: BasicBlock,
-    /// index within above block; statement when < statments.len) or
-    /// the terminator (when = statements.len).
-    pub index: usize,
-}
-
-impl fmt::Debug for Location {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        write!(fmt, "{:?}[{}]", self.block, self.index)
-    }
-}
-
 #[derive(Debug)]
 pub struct MovePathData<'tcx> {
     move_paths: Vec<MovePath<'tcx>>,
@@ -569,7 +554,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
         };
 
         for (i, stmt) in bb_data.statements.iter().enumerate() {
-            let source = Location { block: bb, index: i };
+            let source = Location { block: bb, statement_index: i };
             match stmt.kind {
                 StatementKind::Assign(ref lval, ref rval) => {
                     bb_ctxt.builder.create_move_path(lval);
@@ -631,14 +616,14 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
 
             TerminatorKind::Return => {
                 let source = Location { block: bb,
-                                        index: bb_data.statements.len() };
+                                        statement_index: bb_data.statements.len() };
                 debug!("gather_moves Return on_move_out_lval return {:?}", source);
                 bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source);
             }
 
             TerminatorKind::If { ref cond, targets: _ } => {
                 let source = Location { block: bb,
-                                        index: bb_data.statements.len() };
+                                        statement_index: bb_data.statements.len() };
                 bb_ctxt.on_operand(SK::If, cond, source);
             }
 
@@ -669,7 +654,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
 
             TerminatorKind::Drop { ref location, target: _, unwind: _ } => {
                 let source = Location { block: bb,
-                                        index: bb_data.statements.len() };
+                                        statement_index: bb_data.statements.len() };
                 bb_ctxt.on_move_out_lval(SK::Drop, location, source);
             }
             TerminatorKind::DropAndReplace { ref location, ref value, .. } => {
@@ -677,12 +662,12 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
                 bb_ctxt.path_map.fill_to(assigned_path.index());
 
                 let source = Location { block: bb,
-                                        index: bb_data.statements.len() };
+                                        statement_index: bb_data.statements.len() };
                 bb_ctxt.on_operand(SK::Use, value, source);
             }
             TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => {
                 let source = Location { block: bb,
-                                        index: bb_data.statements.len() };
+                                        statement_index: bb_data.statements.len() };
                 bb_ctxt.on_operand(SK::CallFn, func, source);
                 for arg in args {
                     debug!("gather_moves Call on_operand {:?} {:?}", arg, source);
@@ -757,7 +742,7 @@ fn on_move_out_lval(&mut self,
                         stmt_kind: StmtKind,
                         lval: &Lvalue<'tcx>,
                         source: Location) {
-        let i = source.index;
+        let i = source.statement_index;
         let index = MoveOutIndex::new(self.moves.len());
 
         let path = self.builder.move_path_for(lval);
index dbee0ea9b00e97a870f41cb8b03b0da233d9878f..887c7deb86be0804d9164c942927139fa9ae417b 100644 (file)
@@ -11,7 +11,6 @@
 use borrowck::BorrowckCtxt;
 
 use syntax::ast::{self, MetaItem};
-use syntax::attr::AttrMetaMethods;
 use syntax::ptr::P;
 use syntax_pos::{Span, DUMMY_SP};
 
@@ -19,7 +18,7 @@
 use rustc::hir::intravisit::{FnKind};
 
 use rustc::mir::repr;
-use rustc::mir::repr::{BasicBlock, BasicBlockData, Mir, Statement, Terminator};
+use rustc::mir::repr::{BasicBlock, BasicBlockData, Mir, Statement, Terminator, Location};
 use rustc::session::Session;
 use rustc::ty::{self, TyCtxt};
 
@@ -35,7 +34,7 @@
 use self::dataflow::{Dataflow, DataflowAnalysis, DataflowResults};
 use self::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
 use self::dataflow::{DefinitelyInitializedLvals};
-use self::gather_moves::{MoveData, MovePathIndex, Location};
+use self::gather_moves::{MoveData, MovePathIndex};
 use self::gather_moves::{MovePathContent, MovePathData};
 
 fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<P<MetaItem>> {
@@ -43,8 +42,9 @@ fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<P<MetaItem
         if attr.check_name("rustc_mir") {
             let items = attr.meta_item_list();
             for item in items.iter().flat_map(|l| l.iter()) {
-                if item.check_name(name) {
-                    return Some(item.clone())
+                match item.meta_item() {
+                    Some(mi) if mi.check_name(name) => return Some(mi.clone()),
+                    _ => continue
                 }
             }
         }
@@ -126,8 +126,6 @@ fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              bd: BD) -> DataflowResults<BD>
     where BD: BitDenotation<Idx=MovePathIndex, Ctxt=MoveDataParamEnv<'tcx>> + DataflowOperator
 {
-    use syntax::attr::AttrMetaMethods;
-
     let name_found = |sess: &Session, attrs: &[ast::Attribute], name| -> Option<String> {
         if let Some(item) = has_rustc_mir_with(attrs, name) {
             if let Some(s) = item.value_str() {
@@ -367,7 +365,7 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>(
     }
 
     let block = &mir[loc.block];
-    match block.statements.get(loc.index) {
+    match block.statements.get(loc.statement_index) {
         Some(stmt) => match stmt.kind {
             repr::StatementKind::SetDiscriminant{ .. } => {
                 span_bug!(stmt.source_info.span, "SetDiscrimant should not exist during borrowck");
index 417e719a9dcb9f73cee1c24c6736cdaf532ed185..52cd1a9f949bf6219b7e1cd7e101a9a7c6ea0d8e 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use super::gather_moves::Location;
 use rustc::ty::Ty;
 use rustc::mir::repr::*;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@@ -89,7 +88,7 @@ pub fn terminator_loc(&self, mir: &Mir<'tcx>, bb: BasicBlock) -> Location {
         };
         Location {
             block: bb,
-            index: offset
+            statement_index: offset
         }
     }
 
@@ -149,12 +148,12 @@ pub fn apply(self, mir: &mut Mir<'tcx>) {
             }
             debug!("MirPatch: adding statement {:?} at loc {:?}+{}",
                    stmt, loc, delta);
-            loc.index += delta;
+            loc.statement_index += delta;
             let source_info = Self::source_info_for_index(
                 &mir[loc.block], loc
             );
             mir[loc.block].statements.insert(
-                loc.index, Statement {
+                loc.statement_index, Statement {
                     source_info: source_info,
                     kind: stmt
                 });
@@ -163,7 +162,7 @@ pub fn apply(self, mir: &mut Mir<'tcx>) {
     }
 
     pub fn source_info_for_index(data: &BasicBlockData, loc: Location) -> SourceInfo {
-        match data.statements.get(loc.index) {
+        match data.statements.get(loc.statement_index) {
             Some(stmt) => stmt.source_info,
             None => data.terminator().source_info
         }
index e0cbd972bd37f9f3c62fc9d65e26b18bb47915af..67152ed04ec1def340185f8d902b0ae1cf3c5ead 100644 (file)
@@ -41,8 +41,8 @@
 use std::fmt;
 use std::mem;
 use std::rc::Rc;
+use std::hash::{Hash, Hasher};
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax_pos::{MultiSpan, Span};
 use errors::DiagnosticBuilder;
 
@@ -345,7 +345,7 @@ pub fn loan_path(&self) -> Rc<LoanPath<'tcx>> {
     }
 }
 
-#[derive(Eq, Hash)]
+#[derive(Eq)]
 pub struct LoanPath<'tcx> {
     kind: LoanPathKind<'tcx>,
     ty: ty::Ty<'tcx>,
@@ -353,10 +353,13 @@ pub struct LoanPath<'tcx> {
 
 impl<'tcx> PartialEq for LoanPath<'tcx> {
     fn eq(&self, that: &LoanPath<'tcx>) -> bool {
-        let r = self.kind == that.kind;
-        debug_assert!(self.ty == that.ty || !r,
-                      "Somehow loan paths are equal though their tys are not.");
-        r
+        self.kind == that.kind
+    }
+}
+
+impl<'tcx> Hash for LoanPath<'tcx> {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.kind.hash(state);
     }
 }
 
@@ -365,7 +368,7 @@ pub enum LoanPathKind<'tcx> {
     LpVar(ast::NodeId),                         // `x` in README.md
     LpUpvar(ty::UpvarId),                       // `x` captured by-value into closure
     LpDowncast(Rc<LoanPath<'tcx>>, DefId), // `x` downcast to particular enum variant
-    LpExtend(Rc<LoanPath<'tcx>>, mc::MutabilityCategory, LoanPathElem)
+    LpExtend(Rc<LoanPath<'tcx>>, mc::MutabilityCategory, LoanPathElem<'tcx>)
 }
 
 impl<'tcx> LoanPath<'tcx> {
@@ -410,8 +413,8 @@ fn cleaned(self) -> InteriorKind {
 // `enum E { X { foo: u32 }, Y { foo: u32 }}`
 // each `foo` is qualified by the definitition id of the variant (`X` or `Y`).
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub enum LoanPathElem {
-    LpDeref(mc::PointerKind),
+pub enum LoanPathElem<'tcx> {
+    LpDeref(mc::PointerKind<'tcx>),
     LpInterior(Option<DefId>, InteriorKind),
 }
 
@@ -564,10 +567,11 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option<Rc<LoanPath<'tcx>>> {
 
 // Errors that can occur
 #[derive(PartialEq)]
-pub enum bckerr_code {
+pub enum bckerr_code<'tcx> {
     err_mutbl,
-    err_out_of_scope(ty::Region, ty::Region), // superscope, subscope
-    err_borrowed_pointer_too_short(ty::Region, ty::Region), // loan, ptr
+    /// superscope, subscope, loan cause
+    err_out_of_scope(&'tcx ty::Region, &'tcx ty::Region, euv::LoanCause),
+    err_borrowed_pointer_too_short(&'tcx ty::Region, &'tcx ty::Region), // loan, ptr
 }
 
 // Combination of an error code and the categorization of the expression
@@ -577,7 +581,7 @@ pub struct BckError<'tcx> {
     span: Span,
     cause: AliasableViolationKind,
     cmt: mc::cmt<'tcx>,
-    code: bckerr_code
+    code: bckerr_code<'tcx>
 }
 
 #[derive(Copy, Clone, Debug, PartialEq)]
@@ -605,7 +609,7 @@ fn with_temp_region_map<F>(&mut self, id: ast::NodeId, f: F)
         self.free_region_map = old_free_region_map;
     }
 
-    pub fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region)
+    pub fn is_subregion_of(&self, r_sub: &'tcx ty::Region, r_sup: &'tcx ty::Region)
                            -> bool
     {
         self.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup)
@@ -614,9 +618,9 @@ pub fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region)
     pub fn report(&self, err: BckError<'tcx>) {
         // Catch and handle some particular cases.
         match (&err.code, &err.cause) {
-            (&err_out_of_scope(ty::ReScope(_), ty::ReStatic),
+            (&err_out_of_scope(&ty::ReScope(_), &ty::ReStatic, _),
              &BorrowViolation(euv::ClosureCapture(span))) |
-            (&err_out_of_scope(ty::ReScope(_), ty::ReFree(..)),
+            (&err_out_of_scope(&ty::ReScope(_), &ty::ReFree(..), _),
              &BorrowViolation(euv::ClosureCapture(span))) => {
                 return self.report_out_of_scope_escaping_closure_capture(&err, span);
             }
@@ -914,14 +918,18 @@ pub fn report_aliasability_violation(&self,
             }
             mc::AliasableStatic |
             mc::AliasableStaticMut => {
-                struct_span_err!(
+                let mut err = struct_span_err!(
                     self.tcx.sess, span, E0388,
-                    "{} in a static location", prefix)
+                    "{} in a static location", prefix);
+                err.span_label(span, &format!("cannot write data in a static definition"));
+                err
             }
             mc::AliasableBorrowed => {
-                struct_span_err!(
+                let mut e = struct_span_err!(
                     self.tcx.sess, span, E0389,
-                    "{} in a `&` reference", prefix)
+                    "{} in a `&` reference", prefix);
+                e.span_label(span, &"assignment into an immutable reference");
+                e
             }
         };
 
@@ -963,6 +971,22 @@ fn report_out_of_scope_escaping_closure_capture(&self,
             .emit();
     }
 
+    fn region_end_span(&self, region: &'tcx ty::Region) -> Option<Span> {
+        match *region {
+            ty::ReScope(scope) => {
+                match scope.span(&self.tcx.region_maps, &self.tcx.map) {
+                    Some(s) => {
+                        Some(s.end_point())
+                    }
+                    None => {
+                        None
+                    }
+                }
+            }
+            _ => None
+        }
+    }
+
     pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>,
         error_span: Span) {
         let code = err.code;
@@ -1003,21 +1027,73 @@ pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<
                 }
             }
 
-            err_out_of_scope(super_scope, sub_scope) => {
-                self.tcx.note_and_explain_region(
-                    db,
-                    "reference must be valid for ",
-                    sub_scope,
-                    "...");
-                self.tcx.note_and_explain_region(
-                    db,
-                    "...but borrowed value is only valid for ",
-                    super_scope,
-                    "");
-                if let Some(span) = statement_scope_span(self.tcx, super_scope) {
-                    db.span_label(error_span, &format!("does not live long enough"));
-                    db.span_help(span,
-                                 "consider using a `let` binding to increase its lifetime");
+            err_out_of_scope(super_scope, sub_scope, cause) => {
+                let (value_kind, value_msg) = match err.cmt.cat {
+                    mc::Categorization::Rvalue(_) =>
+                        ("temporary value", "temporary value created here"),
+                    _ =>
+                        ("borrowed value", "does not live long enough")
+                };
+                match cause {
+                    euv::ClosureCapture(s) => {
+                        // The primary span starts out as the closure creation point.
+                        // Change the primary span here to highlight the use of the variable
+                        // in the closure, because it seems more natural. Highlight
+                        // closure creation point as a secondary span.
+                        match db.span.primary_span() {
+                            Some(primary) => {
+                                db.span = MultiSpan::from_span(s);
+                                db.span_label(primary, &format!("capture occurs here"));
+                                db.span_label(s, &value_msg);
+                            }
+                            None => ()
+                        }
+                    }
+                    _ => {
+                        db.span_label(error_span, &value_msg);
+                    }
+                }
+
+                let sub_span = self.region_end_span(sub_scope);
+                let super_span = self.region_end_span(super_scope);
+
+                match (sub_span, super_span) {
+                    (Some(s1), Some(s2)) if s1 == s2 => {
+                        db.span_label(s1, &format!("{} dropped before borrower", value_kind));
+                        db.note("values in a scope are dropped in the opposite order \
+                                they are created");
+                    }
+                    _ => {
+                        match sub_span {
+                            Some(s) => {
+                                db.span_label(s, &format!("{} needs to live until here",
+                                                          value_kind));
+                            }
+                            None => {
+                                self.tcx.note_and_explain_region(
+                                    db,
+                                    "borrowed value must be valid for ",
+                                    sub_scope,
+                                    "...");
+                            }
+                        }
+                        match super_span {
+                            Some(s) => {
+                                db.span_label(s, &format!("{} only lives until here", value_kind));
+                            }
+                            None => {
+                                self.tcx.note_and_explain_region(
+                                    db,
+                                    "...but borrowed value is only valid for ",
+                                    super_scope,
+                                    "");
+                            }
+                        }
+                    }
+                }
+
+                if let Some(_) = statement_scope_span(self.tcx, super_scope) {
+                    db.note("consider using a `let` binding to increase its lifetime");
                 }
             }
 
@@ -1130,8 +1206,8 @@ pub fn cmt_to_path_or_string(&self, cmt: &mc::cmt<'tcx>) -> String {
     }
 }
 
-fn statement_scope_span(tcx: TyCtxt, region: ty::Region) -> Option<Span> {
-    match region {
+fn statement_scope_span(tcx: TyCtxt, region: &ty::Region) -> Option<Span> {
+    match *region {
         ty::ReScope(scope) => {
             match tcx.map.find(scope.node_id(&tcx.region_maps)) {
                 Some(hir_map::NodeStmt(stmt)) => Some(stmt.span),
index 5db293f5bb016786ad409920e5d8545829bd0fde..e71a780dd89bca7e6e2649b16befbcc8cb61ca29 100644 (file)
@@ -324,7 +324,10 @@ fn check_arms(cx: &MatchCheckCtxt,
                             let &(ref first_arm_pats, _) = &arms[0];
                             let first_pat = &first_arm_pats[0];
                             let span = first_pat.span;
-                            span_err!(cx.tcx.sess, span, E0165, "irrefutable while-let pattern");
+                            struct_span_err!(cx.tcx.sess, span, E0165,
+                                             "irrefutable while-let pattern")
+                                .span_label(span, &format!("irrefutable pattern"))
+                                .emit();
                         },
 
                         hir::MatchSource::ForLoopDesugar => {
@@ -1121,10 +1124,11 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
                 .span_label(p.span, &format!("moves value into pattern guard"))
                 .emit();
         } else if by_ref_span.is_some() {
-            let mut err = struct_span_err!(cx.tcx.sess, p.span, E0009,
-                                           "cannot bind by-move and by-ref in the same pattern");
-            span_note!(&mut err, by_ref_span.unwrap(), "by-ref binding occurs here");
-            err.emit();
+            struct_span_err!(cx.tcx.sess, p.span, E0009,
+                            "cannot bind by-move and by-ref in the same pattern")
+                    .span_label(p.span, &format!("by-move pattern here"))
+                    .span_label(by_ref_span.unwrap(), &format!("both by-ref and by-move used"))
+                    .emit();
         }
     };
 
@@ -1171,7 +1175,7 @@ fn borrow(&mut self,
               _: NodeId,
               span: Span,
               _: cmt,
-              _: Region,
+              _: &'tcx Region,
               kind: BorrowKind,
               _: LoanCause) {
         match kind {
diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs
new file mode 100644 (file)
index 0000000..4a184d3
--- /dev/null
@@ -0,0 +1,338 @@
+// 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.
+
+//! Simple file-locking apis for each OS.
+//!
+//! This is not meant to be in the standard library, it does nothing with
+//! green/native threading. This is just a bare-bones enough solution for
+//! librustdoc, it is not production quality at all.
+
+#![allow(non_camel_case_types)]
+use std::path::Path;
+
+pub use self::imp::Lock;
+
+#[cfg(unix)]
+mod imp {
+    use std::ffi::{CString, OsStr};
+    use std::os::unix::prelude::*;
+    use std::path::Path;
+    use std::io;
+    use libc;
+
+    #[cfg(target_os = "linux")]
+    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_RDLCK: libc::c_short = 0;
+        pub const F_WRLCK: libc::c_short = 1;
+        pub const F_UNLCK: libc::c_short = 2;
+        pub const F_SETLK: libc::c_int = 6;
+        pub const F_SETLKW: libc::c_int = 7;
+    }
+
+    #[cfg(target_os = "freebsd")]
+    mod os {
+        use libc;
+
+        pub struct flock {
+            pub l_start: libc::off_t,
+            pub l_len: libc::off_t,
+            pub l_pid: libc::pid_t,
+            pub l_type: libc::c_short,
+            pub l_whence: libc::c_short,
+            pub l_sysid: libc::c_int,
+        }
+
+        pub const F_RDLCK: libc::c_short = 1;
+        pub const F_UNLCK: libc::c_short = 2;
+        pub const F_WRLCK: libc::c_short = 3;
+        pub const F_SETLK: libc::c_int = 12;
+        pub const F_SETLKW: libc::c_int = 13;
+    }
+
+    #[cfg(any(target_os = "dragonfly",
+              target_os = "bitrig",
+              target_os = "netbsd",
+              target_os = "openbsd"))]
+    mod os {
+        use libc;
+
+        pub struct flock {
+            pub l_start: libc::off_t,
+            pub l_len: libc::off_t,
+            pub l_pid: libc::pid_t,
+            pub l_type: libc::c_short,
+            pub l_whence: libc::c_short,
+
+            // not actually here, but brings in line with freebsd
+            pub l_sysid: libc::c_int,
+        }
+
+        pub const F_RDLCK: libc::c_short = 1;
+        pub const F_UNLCK: libc::c_short = 2;
+        pub const F_WRLCK: libc::c_short = 3;
+        pub const F_SETLK: libc::c_int = 8;
+        pub const F_SETLKW: libc::c_int = 9;
+    }
+
+    #[cfg(any(target_os = "macos", target_os = "ios"))]
+    mod os {
+        use libc;
+
+        pub struct flock {
+            pub l_start: libc::off_t,
+            pub l_len: libc::off_t,
+            pub l_pid: libc::pid_t,
+            pub l_type: libc::c_short,
+            pub l_whence: libc::c_short,
+
+            // not actually here, but brings in line with freebsd
+            pub l_sysid: libc::c_int,
+        }
+
+        pub const F_RDLCK: libc::c_short = 1;
+        pub const F_UNLCK: libc::c_short = 2;
+        pub const F_WRLCK: libc::c_short = 3;
+        pub const F_SETLK: libc::c_int = 8;
+        pub const F_SETLKW: libc::c_int = 9;
+    }
+
+    #[cfg(target_os = "solaris")]
+    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_sysid: libc::c_int,
+            pub l_pid: libc::pid_t,
+        }
+
+        pub const F_RDLCK: libc::c_short = 1;
+        pub const F_WRLCK: libc::c_short = 2;
+        pub const F_UNLCK: libc::c_short = 3;
+        pub const F_SETLK: libc::c_int = 6;
+        pub const F_SETLKW: libc::c_int = 7;
+    }
+
+    #[derive(Debug)]
+    pub struct Lock {
+        fd: libc::c_int,
+    }
+
+    impl Lock {
+        pub fn new(p: &Path,
+                   wait: bool,
+                   create: bool,
+                   exclusive: bool)
+                   -> io::Result<Lock> {
+            let os: &OsStr = p.as_ref();
+            let buf = CString::new(os.as_bytes()).unwrap();
+            let open_flags = if create {
+                libc::O_RDWR | libc::O_CREAT
+            } else {
+                libc::O_RDWR
+            };
+
+            let fd = unsafe {
+                libc::open(buf.as_ptr(), open_flags,
+                           libc::S_IRWXU as libc::c_int)
+            };
+
+            if fd < 0 {
+                return Err(io::Error::last_os_error());
+            }
+
+            let lock_type = if exclusive {
+                os::F_WRLCK
+            } else {
+                os::F_RDLCK
+            };
+
+            let flock = os::flock {
+                l_start: 0,
+                l_len: 0,
+                l_pid: 0,
+                l_whence: libc::SEEK_SET as libc::c_short,
+                l_type: lock_type,
+                l_sysid: 0,
+            };
+            let cmd = if wait { os::F_SETLKW } else { os::F_SETLK };
+            let ret = unsafe {
+                libc::fcntl(fd, cmd, &flock)
+            };
+            if ret == -1 {
+                let err = io::Error::last_os_error();
+                unsafe { libc::close(fd); }
+                Err(err)
+            } else {
+                Ok(Lock { fd: fd })
+            }
+        }
+    }
+
+    impl Drop for Lock {
+        fn drop(&mut self) {
+            let flock = os::flock {
+                l_start: 0,
+                l_len: 0,
+                l_pid: 0,
+                l_whence: libc::SEEK_SET as libc::c_short,
+                l_type: os::F_UNLCK,
+                l_sysid: 0,
+            };
+            unsafe {
+                libc::fcntl(self.fd, os::F_SETLK, &flock);
+                libc::close(self.fd);
+            }
+        }
+    }
+}
+
+#[cfg(windows)]
+#[allow(bad_style)]
+mod imp {
+    use std::io;
+    use std::mem;
+    use std::os::windows::prelude::*;
+    use std::os::windows::raw::HANDLE;
+    use std::path::Path;
+    use std::fs::{File, OpenOptions};
+    use std::os::raw::{c_ulong, c_ulonglong, c_int};
+
+    type DWORD = c_ulong;
+    type BOOL = c_int;
+    type ULONG_PTR = c_ulonglong;
+
+    type LPOVERLAPPED = *mut OVERLAPPED;
+    const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x00000002;
+    const LOCKFILE_FAIL_IMMEDIATELY: DWORD = 0x00000001;
+
+    const FILE_SHARE_DELETE: DWORD = 0x4;
+    const FILE_SHARE_READ: DWORD = 0x1;
+    const FILE_SHARE_WRITE: DWORD = 0x2;
+
+    #[repr(C)]
+    struct OVERLAPPED {
+        Internal: ULONG_PTR,
+        InternalHigh: ULONG_PTR,
+        Offset: DWORD,
+        OffsetHigh: DWORD,
+        hEvent: HANDLE,
+    }
+
+    extern "system" {
+        fn LockFileEx(hFile: HANDLE,
+                      dwFlags: DWORD,
+                      dwReserved: DWORD,
+                      nNumberOfBytesToLockLow: DWORD,
+                      nNumberOfBytesToLockHigh: DWORD,
+                      lpOverlapped: LPOVERLAPPED) -> BOOL;
+    }
+
+    #[derive(Debug)]
+    pub struct Lock {
+        _file: File,
+    }
+
+    impl Lock {
+        pub fn new(p: &Path,
+                   wait: bool,
+                   create: bool,
+                   exclusive: bool)
+                   -> io::Result<Lock> {
+            assert!(p.parent().unwrap().exists(),
+                "Parent directory of lock-file must exist: {}",
+                p.display());
+
+            let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+            let mut open_options = OpenOptions::new();
+            open_options.read(true)
+                        .share_mode(share_mode);
+
+            if create {
+                open_options.create(true)
+                            .write(true);
+            }
+
+            debug!("Attempting to open lock file `{}`", p.display());
+            let file = match open_options.open(p) {
+                Ok(file) => {
+                    debug!("Lock file opened successfully");
+                    file
+                }
+                Err(err) => {
+                    debug!("Error opening lock file: {}", err);
+                    return Err(err)
+                }
+            };
+
+            let ret = unsafe {
+                let mut overlapped: OVERLAPPED = mem::zeroed();
+
+                let mut dwFlags = 0;
+                if !wait {
+                    dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
+                }
+
+                if exclusive {
+                    dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
+                }
+
+                debug!("Attempting to acquire lock on lock file `{}`",
+                       p.display());
+                LockFileEx(file.as_raw_handle(),
+                           dwFlags,
+                           0,
+                           0xFFFF_FFFF,
+                           0xFFFF_FFFF,
+                           &mut overlapped)
+            };
+            if ret == 0 {
+                let err = io::Error::last_os_error();
+                debug!("Failed acquiring file lock: {}", err);
+                Err(err)
+            } else {
+                debug!("Successfully acquired lock.");
+                Ok(Lock { _file: file })
+            }
+        }
+    }
+
+    // Note that we don't need a Drop impl on the Windows: The file is unlocked
+    // automatically when it's closed.
+}
+
+impl imp::Lock {
+    pub fn panicking_new(p: &Path,
+                         wait: bool,
+                         create: bool,
+                         exclusive: bool)
+                         -> Lock {
+        Lock::new(p, wait, create, exclusive).unwrap_or_else(|err| {
+            panic!("could not lock `{}`: {}", p.display(), err);
+        })
+    }
+}
index 34c3961d5b4c18980c4b2ea36f6729d06dd22f20..e7da18cef10f967eb83b78a74d187241c23b7d64 100644 (file)
 #![feature(unboxed_closures)]
 #![feature(fn_traits)]
 
+#![cfg_attr(unix, feature(libc))]
 #![cfg_attr(test, feature(test))]
 
 extern crate core;
 #[macro_use]
 extern crate log;
 extern crate serialize as rustc_serialize; // used by deriving
+#[cfg(unix)]
+extern crate libc;
 
 pub mod bitvec;
 pub mod graph;
@@ -51,6 +54,7 @@
 pub mod tuple_slice;
 pub mod veccell;
 pub mod control_flow_graph;
+pub mod flock;
 
 // See comments in src/librustc/lib.rs
 #[doc(hidden)]
index c6100004786bef8b97f9018cf30d7cddbd71cd49..94092be4922b52fd35fb764ca9293e5d04acc811 100644 (file)
@@ -26,7 +26,7 @@
 use rustc::util::nodemap::NodeSet;
 use rustc_back::sha2::{Sha256, Digest};
 use rustc_borrowck as borrowck;
-use rustc_incremental;
+use rustc_incremental::{self, IncrementalHashesMap};
 use rustc_resolve::{MakeGlobMap, Resolver};
 use rustc_metadata::macro_import;
 use rustc_metadata::creader::read_local_crates;
@@ -49,7 +49,7 @@
 use std::io::{self, Write};
 use std::path::{Path, PathBuf};
 use syntax::{ast, diagnostics, visit};
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::attr;
 use syntax::parse::{self, PResult, token};
 use syntax::util::node_count::NodeCounter;
 use syntax;
@@ -88,7 +88,7 @@ macro_rules! controller_entry_point {
     // We need nested scopes here, because the intermediate results can keep
     // large chunks of memory alive and we want to free them as soon as
     // possible to keep the peak memory usage low
-    let (outputs, trans, crate_name) = {
+    let (outputs, trans) = {
         let krate = match phase_1_parse_input(sess, cfg, input) {
             Ok(krate) => krate,
             Err(mut parse_error) => {
@@ -172,7 +172,7 @@ macro_rules! controller_entry_point {
                                     resolutions,
                                     &arenas,
                                     &crate_name,
-                                    |tcx, mir_map, analysis, result| {
+                                    |tcx, mir_map, analysis, incremental_hashes_map, result| {
             {
                 // Eventually, we will want to track plugins.
                 let _ignore = tcx.dep_graph.in_ignore();
@@ -202,7 +202,8 @@ macro_rules! controller_entry_point {
             }
             let trans = phase_4_translate_to_llvm(tcx,
                                                   mir_map.unwrap(),
-                                                  analysis);
+                                                  analysis,
+                                                  &incremental_hashes_map);
 
             if log_enabled!(::log::INFO) {
                 println!("Post-trans");
@@ -212,11 +213,11 @@ macro_rules! controller_entry_point {
             // Discard interned strings as they are no longer required.
             token::clear_ident_interner();
 
-            Ok((outputs, trans, crate_name.clone()))
+            Ok((outputs, trans))
         })??
     };
 
-    let phase5_result = phase_5_run_llvm_passes(sess, &crate_name, &trans, &outputs);
+    let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs);
 
     controller_entry_point!(after_llvm,
                             sess,
@@ -228,6 +229,10 @@ macro_rules! controller_entry_point {
 
     phase_6_link_output(sess, &trans, &outputs);
 
+    // Now that we won't touch anything in the incremental compilation directory
+    // any more, we can finalize it (which involves renaming it)
+    rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash);
+
     controller_entry_point!(compilation_done,
                             sess,
                             CompileState::state_when_compilation_done(input, sess, outdir, output),
@@ -797,14 +802,15 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
     where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>,
                             Option<MirMap<'tcx>>,
                             ty::CrateAnalysis,
+                            IncrementalHashesMap,
                             CompileResult) -> R
 {
     macro_rules! try_with_f {
-        ($e: expr, ($t: expr, $m: expr, $a: expr)) => {
+        ($e: expr, ($t: expr, $m: expr, $a: expr, $h: expr)) => {
             match $e {
                 Ok(x) => x,
                 Err(x) => {
-                    f($t, $m, $a, Err(x));
+                    f($t, $m, $a, $h, Err(x));
                     return Err(x);
                 }
             }
@@ -860,12 +866,16 @@ macro_rules! try_with_f {
                              index,
                              name,
                              |tcx| {
+        let incremental_hashes_map =
+            time(time_passes,
+                 "compute_incremental_hashes_map",
+                 || rustc_incremental::compute_incremental_hashes_map(tcx));
         time(time_passes,
              "load_dep_graph",
-             || rustc_incremental::load_dep_graph(tcx));
+             || rustc_incremental::load_dep_graph(tcx, &incremental_hashes_map));
 
         // passes are timed inside typeck
-        try_with_f!(typeck::check_crate(tcx), (tcx, None, analysis));
+        try_with_f!(typeck::check_crate(tcx), (tcx, None, analysis, incremental_hashes_map));
 
         time(time_passes,
              "const checking",
@@ -935,7 +945,11 @@ macro_rules! try_with_f {
         // lint warnings and so on -- kindck used to do this abort, but
         // kindck is gone now). -nmatsakis
         if sess.err_count() > 0 {
-            return Ok(f(tcx, Some(mir_map), analysis, Err(sess.err_count())));
+            return Ok(f(tcx,
+                        Some(mir_map),
+                        analysis,
+                        incremental_hashes_map,
+                        Err(sess.err_count())));
         }
 
         analysis.reachable =
@@ -963,17 +977,22 @@ macro_rules! try_with_f {
 
         // The above three passes generate errors w/o aborting
         if sess.err_count() > 0 {
-            return Ok(f(tcx, Some(mir_map), analysis, Err(sess.err_count())));
+            return Ok(f(tcx,
+                        Some(mir_map),
+                        analysis,
+                        incremental_hashes_map,
+                        Err(sess.err_count())));
         }
 
-        Ok(f(tcx, Some(mir_map), analysis, Ok(())))
+        Ok(f(tcx, Some(mir_map), analysis, incremental_hashes_map, Ok(())))
     })
 }
 
 /// Run the translation phase to LLVM, after which the AST and analysis can
 pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                            mut mir_map: MirMap<'tcx>,
-                                           analysis: ty::CrateAnalysis)
+                                           analysis: ty::CrateAnalysis,
+                                           incremental_hashes_map: &IncrementalHashesMap)
                                            -> trans::CrateTranslation {
     let time_passes = tcx.sess.time_passes();
 
@@ -1007,23 +1026,23 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let translation =
         time(time_passes,
              "translation",
-             move || trans::trans_crate(tcx, &mir_map, analysis));
+             move || trans::trans_crate(tcx, &mir_map, analysis, &incremental_hashes_map));
 
     time(time_passes,
          "assert dep graph",
-         move || rustc_incremental::assert_dep_graph(tcx));
+         || rustc_incremental::assert_dep_graph(tcx));
 
     time(time_passes,
          "serialize dep graph",
-         move || rustc_incremental::save_dep_graph(tcx));
-
+         || rustc_incremental::save_dep_graph(tcx,
+                                              &incremental_hashes_map,
+                                              translation.link.crate_hash));
     translation
 }
 
 /// Run LLVM itself, producing a bitcode file, assembly file or object file
 /// as a side effect.
 pub fn phase_5_run_llvm_passes(sess: &Session,
-                               crate_name: &str,
                                trans: &trans::CrateTranslation,
                                outputs: &OutputFilenames) -> CompileResult {
     if sess.opts.cg.no_integrated_as {
@@ -1046,7 +1065,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
 
     time(sess.time_passes(),
          "serialize work products",
-         move || rustc_incremental::save_work_products(sess, crate_name));
+         move || rustc_incremental::save_work_products(sess));
 
     if sess.err_count() > 0 {
         Err(sess.err_count())
index 6f57ae2941838d8185afde07b900a4b2aa635a5c..efadf1ff488dfbee24919b4a0504c3246129d893 100644 (file)
@@ -95,7 +95,6 @@
 use rustc::session::early_error;
 
 use syntax::{ast, json};
-use syntax::attr::AttrMetaMethods;
 use syntax::codemap::{CodeMap, FileLoader, RealFileLoader};
 use syntax::feature_gate::{GatedCfg, UnstableFeatures};
 use syntax::parse::{self, PResult};
@@ -655,17 +654,19 @@ fn print_crate_info(sess: &Session,
                         if !allow_unstable_cfg && GatedCfg::gate(&*cfg).is_some() {
                             continue;
                         }
+
                         if cfg.is_word() {
                             println!("{}", cfg.name());
-                        } else if cfg.is_value_str() {
-                            if let Some(s) = cfg.value_str() {
-                                println!("{}=\"{}\"", cfg.name(), s);
-                            }
+                        } else if let Some(s) = cfg.value_str() {
+                            println!("{}=\"{}\"", cfg.name(), s);
                         } else if cfg.is_meta_item_list() {
                             // Right now there are not and should not be any
                             // MetaItemKind::List items in the configuration returned by
                             // `build_configuration`.
-                            panic!("MetaItemKind::List encountered in default cfg")
+                            panic!("Found an unexpected list in cfg attribute '{}'!", cfg.name())
+                        } else {
+                            // There also shouldn't be literals.
+                            panic!("Found an unexpected literal in cfg attribute '{}'!", cfg.name())
                         }
                     }
                 }
@@ -861,7 +862,7 @@ fn sort_lint_groups(lints: Vec<(&'static str, Vec<lint::LintId>, bool)>)
         for (name, to) in lints {
             let name = name.to_lowercase().replace("_", "-");
             let desc = to.into_iter()
-                         .map(|x| x.as_str().replace("_", "-"))
+                         .map(|x| x.to_string().replace("_", "-"))
                          .collect::<Vec<String>>()
                          .join(", ");
             println!("    {}  {}", padded(&name[..]), desc);
index e3e06963ad43bf59f242c1025decbd173fe729ff..1ffeaf322bf5715c678b30729170ac30c138df87 100644 (file)
@@ -234,7 +234,7 @@ fn call_with_pp_support_hir<'tcx, A, B, F>(&self,
                                                                  resolutions.clone(),
                                                                  arenas,
                                                                  id,
-                                                                 |tcx, _, _, _| {
+                                                                 |tcx, _, _, _, _| {
                     let annotation = TypedAnnotation {
                         tcx: tcx,
                     };
@@ -951,7 +951,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
                                                      resolutions.clone(),
                                                      arenas,
                                                      crate_name,
-                                                     |tcx, mir_map, _, _| {
+                                                     |tcx, mir_map, _, _, _| {
         match ppm {
             PpmMir | PpmMirCFG => {
                 if let Some(mir_map) = mir_map {
index 32d0bbbfdb6b7d8e179542345e71af35580856e2..460a6e68a5c5a20f4c4af373c67fdc40c80f8279 100644 (file)
 use rustc::middle::region::CodeExtentData;
 use rustc::middle::resolve_lifetime;
 use rustc::middle::stability;
-use rustc::ty::subst::{Subst, Substs};
+use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits::Reveal;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::infer::{self, InferOk, InferResult, TypeOrigin};
 use rustc_metadata::cstore::CStore;
 use rustc::hir::map as hir_map;
 use rustc::session::{self, config};
+use std::iter;
 use std::rc::Rc;
 use syntax::ast;
 use syntax::abi::Abi;
@@ -283,25 +284,26 @@ pub fn t_param(&self, index: u32) -> Ty<'tcx> {
     pub fn re_early_bound(&self,
                           index: u32,
                           name: &'static str)
-                          -> ty::Region {
+                          -> &'tcx ty::Region {
         let name = token::intern(name);
-        ty::ReEarlyBound(ty::EarlyBoundRegion {
+        self.infcx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
             index: index,
             name: name,
-        })
+        }))
     }
 
-    pub fn re_late_bound_with_debruijn(&self, id: u32, debruijn: ty::DebruijnIndex) -> ty::Region {
-        ty::ReLateBound(debruijn, ty::BrAnon(id))
+    pub fn re_late_bound_with_debruijn(&self, id: u32, debruijn: ty::DebruijnIndex)
+                                       -> &'tcx ty::Region {
+        self.infcx.tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(id)))
     }
 
-    pub fn t_rptr(&self, r: ty::Region) -> Ty<'tcx> {
-        self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
+    pub fn t_rptr(&self, r: &'tcx ty::Region) -> Ty<'tcx> {
+        self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
     }
 
     pub fn t_rptr_late_bound(&self, id: u32) -> Ty<'tcx> {
         let r = self.re_late_bound_with_debruijn(id, ty::DebruijnIndex::new(1));
-        self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
+        self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
     }
 
     pub fn t_rptr_late_bound_with_debruijn(&self,
@@ -309,7 +311,7 @@ pub fn t_rptr_late_bound_with_debruijn(&self,
                                            debruijn: ty::DebruijnIndex)
                                            -> Ty<'tcx> {
         let r = self.re_late_bound_with_debruijn(id, debruijn);
-        self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
+        self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
     }
 
     pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> {
@@ -317,16 +319,16 @@ pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> {
         self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
     }
 
-    pub fn re_free(&self, nid: ast::NodeId, id: u32) -> ty::Region {
-        ty::ReFree(ty::FreeRegion {
+    pub fn re_free(&self, nid: ast::NodeId, id: u32) -> &'tcx ty::Region {
+        self.infcx.tcx.mk_region(ty::ReFree(ty::FreeRegion {
             scope: self.tcx().region_maps.item_extent(nid),
             bound_region: ty::BrAnon(id),
-        })
+        }))
     }
 
     pub fn t_rptr_free(&self, nid: ast::NodeId, id: u32) -> Ty<'tcx> {
         let r = self.re_free(nid, id);
-        self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
+        self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
     }
 
     pub fn t_rptr_static(&self) -> Ty<'tcx> {
@@ -675,7 +677,7 @@ fn subst_ty_renumber_bound() {
             env.t_fn(&[t_param], env.t_nil())
         };
 
-        let substs = Substs::new(env.infcx.tcx, vec![t_rptr_bound1], vec![]);
+        let substs = Substs::new(env.infcx.tcx, iter::once(Kind::from(t_rptr_bound1)));
         let t_substituted = t_source.subst(env.infcx.tcx, substs);
 
         // t_expected = fn(&'a isize)
@@ -710,7 +712,7 @@ fn subst_ty_renumber_some_bounds() {
             env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil()))
         };
 
-        let substs = Substs::new(env.infcx.tcx, vec![t_rptr_bound1], vec![]);
+        let substs = Substs::new(env.infcx.tcx, iter::once(Kind::from(t_rptr_bound1)));
         let t_substituted = t_source.subst(env.infcx.tcx, substs);
 
         // t_expected = (&'a isize, fn(&'a isize))
@@ -772,7 +774,7 @@ fn subst_region_renumber_region() {
             env.t_fn(&[env.t_rptr(re_early)], env.t_nil())
         };
 
-        let substs = Substs::new(env.infcx.tcx, vec![], vec![re_bound1]);
+        let substs = Substs::new(env.infcx.tcx, iter::once(Kind::from(re_bound1)));
         let t_substituted = t_source.subst(env.infcx.tcx, substs);
 
         // t_expected = fn(&'a isize)
index 981729ddb839581ceecabe70f30093b388313de1..dcdbe2a85259bee34e30089bb8e59d10aecaa71d 100644 (file)
@@ -12,7 +12,7 @@
 
 use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos};
 
-use {Level, CodeSuggestion, DiagnosticBuilder, CodeMapper};
+use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper};
 use RenderSpan::*;
 use snippet::{StyledString, Style, Annotation, Line};
 use styled_buffer::StyledBuffer;
@@ -30,7 +30,10 @@ pub trait Emitter {
 
 impl Emitter for EmitterWriter {
     fn emit(&mut self, db: &DiagnosticBuilder) {
-        self.emit_messages_default(db);
+        let mut primary_span = db.span.clone();
+        let mut children = db.children.clone();
+        self.fix_multispans_in_std_macros(&mut primary_span, &mut children);
+        self.emit_messages_default(&db.level, &db.message, &db.code, &primary_span, &children);
     }
 }
 
@@ -381,19 +384,102 @@ fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize {
         max
     }
 
-    fn get_max_line_num(&mut self, db: &DiagnosticBuilder) -> usize {
+    fn get_max_line_num(&mut self, span: &MultiSpan, children: &Vec<SubDiagnostic>) -> usize {
         let mut max = 0;
 
-        let primary = self.get_multispan_max_line_num(&db.span);
+        let primary = self.get_multispan_max_line_num(span);
         max = if primary > max { primary } else { max };
 
-        for sub in &db.children {
+        for sub in children {
             let sub_result = self.get_multispan_max_line_num(&sub.span);
             max = if sub_result > max { primary } else { max };
         }
         max
     }
 
+    // This "fixes" MultiSpans that contain Spans that are pointing to locations inside of
+    // <*macros>. Since these locations are often difficult to read, we move these Spans from
+    // <*macros> to their corresponding use site.
+    fn fix_multispan_in_std_macros(&mut self, span: &mut MultiSpan) -> bool {
+        let mut spans_updated = false;
+
+        if let Some(ref cm) = self.cm {
+            let mut before_after: Vec<(Span, Span)> = vec![];
+            let mut new_labels: Vec<(Span, String)> = vec![];
+
+            // First, find all the spans in <*macros> and point instead at their use site
+            for sp in span.primary_spans() {
+                if (*sp == COMMAND_LINE_SP) || (*sp == DUMMY_SP) {
+                    continue;
+                }
+                if cm.span_to_filename(sp.clone()).contains("macros>") {
+                    let v = cm.macro_backtrace(sp.clone());
+                    if let Some(use_site) = v.last() {
+                        before_after.push((sp.clone(), use_site.call_site.clone()));
+                    }
+                }
+                for trace in cm.macro_backtrace(sp.clone()).iter().rev() {
+                    // Only show macro locations that are local
+                    // and display them like a span_note
+                    if let Some(def_site) = trace.def_site_span {
+                        if (def_site == COMMAND_LINE_SP) || (def_site == DUMMY_SP) {
+                            continue;
+                        }
+                        // Check to make sure we're not in any <*macros>
+                        if !cm.span_to_filename(def_site).contains("macros>") &&
+                            !trace.macro_decl_name.starts_with("#[")
+                        {
+                            new_labels.push((trace.call_site,
+                                             "in this macro invocation".to_string()));
+                            break;
+                        }
+                    }
+                }
+            }
+            for (label_span, label_text) in new_labels {
+                span.push_span_label(label_span, label_text);
+            }
+            for sp_label in span.span_labels() {
+                if (sp_label.span == COMMAND_LINE_SP) || (sp_label.span == DUMMY_SP) {
+                    continue;
+                }
+                if cm.span_to_filename(sp_label.span.clone()).contains("macros>") {
+                    let v = cm.macro_backtrace(sp_label.span.clone());
+                    if let Some(use_site) = v.last() {
+                        before_after.push((sp_label.span.clone(), use_site.call_site.clone()));
+                    }
+                }
+            }
+            // After we have them, make sure we replace these 'bad' def sites with their use sites
+            for (before, after) in before_after {
+                span.replace(before, after);
+                spans_updated = true;
+            }
+        }
+
+        spans_updated
+    }
+
+    // This does a small "fix" for multispans by looking to see if it can find any that
+    // point directly at <*macros>. Since these are often difficult to read, this
+    // will change the span to point at the use site.
+    fn fix_multispans_in_std_macros(&mut self,
+                                    span: &mut MultiSpan,
+                                    children: &mut Vec<SubDiagnostic>) {
+        let mut spans_updated = self.fix_multispan_in_std_macros(span);
+        for child in children.iter_mut() {
+            spans_updated |= self.fix_multispan_in_std_macros(&mut child.span);
+        }
+        if spans_updated {
+            children.push(SubDiagnostic {
+                level: Level::Note,
+                message: "this error originates in a macro from the standard library".to_string(),
+                span: MultiSpan::new(),
+                render_span: None
+            });
+        }
+    }
+
     fn emit_message_default(&mut self,
                             msp: &MultiSpan,
                             msg: &str,
@@ -528,10 +614,6 @@ fn emit_message_default(&mut self,
             }
         }
 
-        if let Some(ref primary_span) = msp.primary_span().as_ref() {
-            self.render_macro_backtrace_old_school(primary_span, &mut buffer)?;
-        }
-
         // final step: take our styled buffer, render it, then output it
         emit_to_destination(&buffer.render(), level, &mut self.dst)?;
 
@@ -578,26 +660,31 @@ fn emit_suggestion_default(&mut self,
         }
         Ok(())
     }
-    fn emit_messages_default(&mut self, db: &DiagnosticBuilder) {
-        let max_line_num = self.get_max_line_num(db);
+    fn emit_messages_default(&mut self,
+                             level: &Level,
+                             message: &String,
+                             code: &Option<String>,
+                             span: &MultiSpan,
+                             children: &Vec<SubDiagnostic>) {
+        let max_line_num = self.get_max_line_num(span, children);
         let max_line_num_len = max_line_num.to_string().len();
 
-        match self.emit_message_default(&db.span,
-                                        &db.message,
-                                        &db.code,
-                                        &db.level,
+        match self.emit_message_default(span,
+                                        message,
+                                        code,
+                                        level,
                                         max_line_num_len,
                                         false) {
             Ok(()) => {
-                if !db.children.is_empty() {
+                if !children.is_empty() {
                     let mut buffer = StyledBuffer::new();
                     draw_col_separator_no_space(&mut buffer, 0, max_line_num_len + 1);
-                    match emit_to_destination(&buffer.render(), &db.level, &mut self.dst) {
+                    match emit_to_destination(&buffer.render(), level, &mut self.dst) {
                         Ok(()) => (),
                         Err(e) => panic!("failed to emit error: {}", e)
                     }
                 }
-                for child in &db.children {
+                for child in children {
                     match child.render_span {
                         Some(FullSpan(ref msp)) => {
                             match self.emit_message_default(msp,
@@ -637,31 +724,11 @@ fn emit_messages_default(&mut self, db: &DiagnosticBuilder) {
         }
         match write!(&mut self.dst, "\n") {
             Err(e) => panic!("failed to emit error: {}", e),
-            _ => ()
-        }
-    }
-    fn render_macro_backtrace_old_school(&mut self,
-                                         sp: &Span,
-                                         buffer: &mut StyledBuffer) -> io::Result<()> {
-        if let Some(ref cm) = self.cm {
-            for trace in cm.macro_backtrace(sp.clone()) {
-                let line_offset = buffer.num_lines();
-
-                let mut diag_string =
-                    format!("in this expansion of {}", trace.macro_decl_name);
-                if let Some(def_site_span) = trace.def_site_span {
-                    diag_string.push_str(
-                        &format!(" (defined in {})",
-                            cm.span_to_filename(def_site_span)));
-                }
-                let snippet = cm.span_to_string(trace.call_site);
-                buffer.append(line_offset, &format!("{} ", snippet), Style::NoStyle);
-                buffer.append(line_offset, "note", Style::Level(Level::Note));
-                buffer.append(line_offset, ": ", Style::NoStyle);
-                buffer.append(line_offset, &diag_string, Style::OldSchoolNoteText);
+            _ => match self.dst.flush() {
+                Err(e) => panic!("failed to emit error: {}", e),
+                _ => ()
             }
         }
-        Ok(())
     }
 }
 
@@ -685,6 +752,21 @@ fn overlaps(a1: &Annotation, a2: &Annotation) -> bool {
 fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>,
         lvl: &Level,
         dst: &mut Destination) -> io::Result<()> {
+    use lock;
+
+    // In order to prevent error message interleaving, where multiple error lines get intermixed
+    // when multiple compiler processes error simultaneously, we emit errors with additional
+    // steps.
+    //
+    // On Unix systems, we write into a buffered terminal rather than directly to a terminal. When
+    // the .flush() is called we take the buffer created from the buffered writes and write it at
+    // one shot.  Because the Unix systems use ANSI for the colors, which is a text-based styling
+    // scheme, this buffered approach works and maintains the styling.
+    //
+    // On Windows, styling happens through calls to a terminal API. This prevents us from using the
+    // same buffering approach.  Instead, we use a global Windows mutex, which we acquire long
+    // enough to output the full error message, then we release.
+    let _buffer_lock = lock::acquire_global_lock("rustc_errors");
     for line in rendered_buffer {
         for part in line {
             dst.apply_style(lvl.clone(), part.style)?;
@@ -693,6 +775,7 @@ fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>,
         }
         write!(dst, "\n")?;
     }
+    dst.flush()?;
     Ok(())
 }
 
@@ -719,14 +802,74 @@ fn GetConsoleMode(hConsoleHandle: HANDLE,
     }
 }
 
+pub type BufferedStderr = term::Terminal<Output = BufferedWriter> + Send;
+
 pub enum Destination {
     Terminal(Box<term::StderrTerminal>),
+    BufferedTerminal(Box<BufferedStderr>),
     Raw(Box<Write + Send>),
 }
 
+/// Buffered writer gives us a way on Unix to buffer up an entire error message before we output
+/// it.  This helps to prevent interleaving of multiple error messages when multiple compiler
+/// processes error simultaneously
+pub struct BufferedWriter {
+    buffer: Vec<u8>,
+}
+
+impl BufferedWriter {
+    // note: we use _new because the conditional compilation at its use site may make this
+    // this function unused on some platforms
+    fn _new() -> BufferedWriter {
+        BufferedWriter {
+            buffer: vec![]
+        }
+    }
+}
+
+impl Write for BufferedWriter {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        for b in buf {
+            self.buffer.push(*b);
+        }
+        Ok(buf.len())
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        let mut stderr = io::stderr();
+        let result = (|| {
+            stderr.write_all(&self.buffer)?;
+            stderr.flush()
+        })();
+        self.buffer.clear();
+        result
+    }
+}
+
 impl Destination {
+    #[cfg(not(windows))]
+    /// When not on Windows, prefer the buffered terminal so that we can buffer an entire error
+    /// to be emitted at one time.
     fn from_stderr() -> Destination {
-        match term::stderr() {
+        let stderr: Option<Box<BufferedStderr>>  =
+            term::TerminfoTerminal::new(BufferedWriter::_new())
+                .map(|t| Box::new(t) as Box<BufferedStderr>);
+
+        match stderr {
+            Some(t) => BufferedTerminal(t),
+            None    => Raw(Box::new(io::stderr())),
+        }
+    }
+
+    #[cfg(windows)]
+    /// Return a normal, unbuffered terminal when on Windows.
+    fn from_stderr() -> Destination {
+        let stderr: Option<Box<term::StderrTerminal>> =
+            term::TerminfoTerminal::new(io::stderr())
+                .map(|t| Box::new(t) as Box<term::StderrTerminal>)
+                .or_else(|| term::WinConsole::new(io::stderr()).ok()
+                    .map(|t| Box::new(t) as Box<term::StderrTerminal>));
+
+        match stderr {
             Some(t) => Terminal(t),
             None    => Raw(Box::new(io::stderr())),
         }
@@ -740,7 +883,11 @@ fn apply_style(&mut self,
             Style::FileNameStyle | Style::LineAndColumn => {}
             Style::LineNumber => {
                 try!(self.start_attr(term::Attr::Bold));
-                try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE)));
+                if cfg!(windows) {
+                    try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN)));
+                } else {
+                    try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE)));
+                }
             }
             Style::ErrorCode => {
                 try!(self.start_attr(term::Attr::Bold));
@@ -753,6 +900,9 @@ fn apply_style(&mut self,
             }
             Style::OldSchoolNoteText | Style::HeaderMsg => {
                 try!(self.start_attr(term::Attr::Bold));
+                if cfg!(windows) {
+                    try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_WHITE)));
+                }
             }
             Style::UnderlinePrimary | Style::LabelPrimary => {
                 try!(self.start_attr(term::Attr::Bold));
@@ -761,7 +911,11 @@ fn apply_style(&mut self,
             Style::UnderlineSecondary |
             Style::LabelSecondary => {
                 try!(self.start_attr(term::Attr::Bold));
-                try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE)));
+                if cfg!(windows) {
+                    try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN)));
+                } else {
+                    try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE)));
+                }
             }
             Style::NoStyle => {}
             Style::Level(l) => {
@@ -775,6 +929,7 @@ fn apply_style(&mut self,
     fn start_attr(&mut self, attr: term::Attr) -> io::Result<()> {
         match *self {
             Terminal(ref mut t) => { t.attr(attr)?; }
+            BufferedTerminal(ref mut t) => { t.attr(attr)?; }
             Raw(_) => { }
         }
         Ok(())
@@ -783,6 +938,7 @@ fn start_attr(&mut self, attr: term::Attr) -> io::Result<()> {
     fn reset_attrs(&mut self) -> io::Result<()> {
         match *self {
             Terminal(ref mut t) => { t.reset()?; }
+            BufferedTerminal(ref mut t) => { t.reset()?; }
             Raw(_) => { }
         }
         Ok(())
@@ -793,12 +949,14 @@ impl Write for Destination {
     fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
         match *self {
             Terminal(ref mut t) => t.write(bytes),
+            BufferedTerminal(ref mut t) => t.write(bytes),
             Raw(ref mut w) => w.write(bytes),
         }
     }
     fn flush(&mut self) -> io::Result<()> {
         match *self {
             Terminal(ref mut t) => t.flush(),
+            BufferedTerminal(ref mut t) => t.flush(),
             Raw(ref mut w) => w.flush(),
         }
     }
index 172e27d56d4852b83bb80be3e0ff00112a0c1500..d82d7dbe70f920afcfb53f0c1bce044c2407da5f 100644 (file)
@@ -50,6 +50,7 @@
 pub mod snippet;
 pub mod registry;
 pub mod styled_buffer;
+mod lock;
 
 use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION };
 use syntax_pos::{MacroBacktrace};
@@ -564,6 +565,15 @@ pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
         self.bump_err_count();
         self.panic_if_treat_err_as_bug();
     }
+    pub fn mut_span_err<'a, S: Into<MultiSpan>>(&'a self,
+                                                sp: S,
+                                                msg: &str)
+                                                -> DiagnosticBuilder<'a> {
+        let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
+        result.set_span(sp);
+        self.bump_err_count();
+        result
+    }
     pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
         self.emit_with_code(&sp.into(), msg, code, Error);
         self.bump_err_count();
@@ -722,7 +732,13 @@ impl Level {
     pub fn color(self) -> term::color::Color {
         match self {
             Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED,
-            Warning => term::color::YELLOW,
+            Warning => {
+                if cfg!(windows) {
+                    term::color::BRIGHT_YELLOW
+                } else {
+                    term::color::YELLOW
+                }
+            },
             Note => term::color::BRIGHT_GREEN,
             Help => term::color::BRIGHT_CYAN,
             Cancelled => unreachable!(),
diff --git a/src/librustc_errors/lock.rs b/src/librustc_errors/lock.rs
new file mode 100644 (file)
index 0000000..0a9e0c4
--- /dev/null
@@ -0,0 +1,112 @@
+// 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.
+
+//! Bindings to acquire a global named lock.
+//!
+//! This is intended to be used to synchronize multiple compiler processes to
+//! ensure that we can output complete errors without interleaving on Windows.
+//! Note that this is currently only needed for allowing only one 32-bit MSVC
+//! linker to execute at once on MSVC hosts, so this is only implemented for
+//! `cfg(windows)`. Also note that this may not always be used on Windows,
+//! only when targeting 32-bit MSVC.
+//!
+//! For more information about why this is necessary, see where this is called.
+
+use std::any::Any;
+
+#[cfg(windows)]
+#[allow(bad_style)]
+pub fn acquire_global_lock(name: &str) -> Box<Any> {
+    use std::ffi::CString;
+    use std::io;
+
+    type LPSECURITY_ATTRIBUTES = *mut u8;
+    type BOOL = i32;
+    type LPCSTR = *const u8;
+    type HANDLE = *mut u8;
+    type DWORD = u32;
+
+    const INFINITE: DWORD = !0;
+    const WAIT_OBJECT_0: DWORD = 0;
+    const WAIT_ABANDONED: DWORD = 0x00000080;
+
+    extern "system" {
+        fn CreateMutexA(lpMutexAttributes: LPSECURITY_ATTRIBUTES,
+                        bInitialOwner: BOOL,
+                        lpName: LPCSTR) -> HANDLE;
+        fn WaitForSingleObject(hHandle: HANDLE,
+                               dwMilliseconds: DWORD) -> DWORD;
+        fn ReleaseMutex(hMutex: HANDLE) -> BOOL;
+        fn CloseHandle(hObject: HANDLE) -> BOOL;
+    }
+
+    struct Handle(HANDLE);
+
+    impl Drop for Handle {
+        fn drop(&mut self) {
+            unsafe {
+                CloseHandle(self.0);
+            }
+        }
+    }
+
+    struct Guard(Handle);
+
+    impl Drop for Guard {
+        fn drop(&mut self) {
+            unsafe {
+                ReleaseMutex((self.0).0);
+            }
+        }
+    }
+
+    let cname = CString::new(name).unwrap();
+    unsafe {
+        // Create a named mutex, with no security attributes and also not
+        // acquired when we create it.
+        //
+        // This will silently create one if it doesn't already exist, or it'll
+        // open up a handle to one if it already exists.
+        let mutex = CreateMutexA(0 as *mut _, 0, cname.as_ptr() as *const u8);
+        if mutex.is_null() {
+            panic!("failed to create global mutex named `{}`: {}", name,
+                   io::Error::last_os_error());
+        }
+        let mutex = Handle(mutex);
+
+        // Acquire the lock through `WaitForSingleObject`.
+        //
+        // A return value of `WAIT_OBJECT_0` means we successfully acquired it.
+        //
+        // A return value of `WAIT_ABANDONED` means that the previous holder of
+        // the thread exited without calling `ReleaseMutex`. This can happen,
+        // for example, when the compiler crashes or is interrupted via ctrl-c
+        // or the like. In this case, however, we are still transferred
+        // ownership of the lock so we continue.
+        //
+        // If an error happens.. well... that's surprising!
+        match WaitForSingleObject(mutex.0, INFINITE) {
+            WAIT_OBJECT_0 | WAIT_ABANDONED => {}
+            code => {
+                panic!("WaitForSingleObject failed on global mutex named \
+                        `{}`: {} (ret={:x})", name,
+                       io::Error::last_os_error(), code);
+            }
+        }
+
+        // Return a guard which will call `ReleaseMutex` when dropped.
+        Box::new(Guard(mutex))
+    }
+}
+
+#[cfg(unix)]
+pub fn acquire_global_lock(_name: &str) -> Box<Any> {
+    Box::new(())
+}
index 420c88e89be0d0373aff440bc5bbc9173a1543b8..8df8f5003711883aa5b906c1a3c25140ae84c058 100644 (file)
@@ -56,7 +56,6 @@
 use std::fs::File;
 use std::io::Write;
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax::parse::token::InternedString;
 use syntax_pos::Span;
 
@@ -116,14 +115,18 @@ fn process_attrs(&mut self, node_id: ast::NodeId, def_id: DefId) {
         for attr in self.tcx.get_attrs(def_id).iter() {
             if attr.check_name(IF_THIS_CHANGED) {
                 let mut id = None;
-                for meta_item in attr.meta_item_list().unwrap_or_default() {
-                    if meta_item.is_word() && id.is_none() {
-                        id = Some(meta_item.name().clone());
-                    } else {
-                        // FIXME better-encapsulate meta_item (don't directly access `node`)
-                        span_bug!(meta_item.span(), "unexpected meta-item {:?}", meta_item.node)
+                for list_item in attr.meta_item_list().unwrap_or_default() {
+                    match list_item.word() {
+                        Some(word) if id.is_none() => {
+                            id = Some(word.name().clone())
+                        },
+                        _ => {
+                            // FIXME better-encapsulate meta_item (don't directly access `node`)
+                            span_bug!(list_item.span(), "unexpected list-item {:?}", list_item.node)
+                        }
                     }
                 }
+
                 let id = id.unwrap_or(InternedString::new(ID));
                 self.if_this_changed.entry(id)
                                     .or_insert(FnvHashSet())
@@ -131,16 +134,21 @@ fn process_attrs(&mut self, node_id: ast::NodeId, def_id: DefId) {
             } else if attr.check_name(THEN_THIS_WOULD_NEED) {
                 let mut dep_node_interned = None;
                 let mut id = None;
-                for meta_item in attr.meta_item_list().unwrap_or_default() {
-                    if meta_item.is_word() && dep_node_interned.is_none() {
-                        dep_node_interned = Some(meta_item.name().clone());
-                    } else if meta_item.is_word() && id.is_none() {
-                        id = Some(meta_item.name().clone());
-                    } else {
-                        // FIXME better-encapsulate meta_item (don't directly access `node`)
-                        span_bug!(meta_item.span(), "unexpected meta-item {:?}", meta_item.node)
+                for list_item in attr.meta_item_list().unwrap_or_default() {
+                    match list_item.word() {
+                        Some(word) if dep_node_interned.is_none() => {
+                            dep_node_interned = Some(word.name().clone());
+                        },
+                        Some(word) if id.is_none() => {
+                            id = Some(word.name().clone())
+                        },
+                        _ => {
+                            // FIXME better-encapsulate meta_item (don't directly access `node`)
+                            span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item.node)
+                        }
                     }
                 }
+
                 let dep_node = match dep_node_interned {
                     Some(ref n) => {
                         match DepNode::from_label_string(&n[..], def_id) {
diff --git a/src/librustc_incremental/calculate_svh/def_path_hash.rs b/src/librustc_incremental/calculate_svh/def_path_hash.rs
new file mode 100644 (file)
index 0000000..8aa134b
--- /dev/null
@@ -0,0 +1,36 @@
+// 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::ty::TyCtxt;
+use rustc::util::nodemap::DefIdMap;
+
+pub struct DefPathHashes<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    data: DefIdMap<u64>,
+}
+
+impl<'a, 'tcx> DefPathHashes<'a, 'tcx> {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
+        DefPathHashes {
+            tcx: tcx,
+            data: DefIdMap()
+        }
+    }
+
+    pub fn hash(&mut self, def_id: DefId) -> u64 {
+        let tcx = self.tcx;
+        *self.data.entry(def_id)
+                  .or_insert_with(|| {
+                      let def_path = tcx.def_path(def_id);
+                      def_path.deterministic_hash(tcx)
+                  })
+    }
+}
index d7caf8c882f0b36d52f575f98125ab368e81b3ad..b14c20ae8d46e84b54ebc54a19778b01031a373e 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Calculation of a Strict Version Hash for crates.  For a length
-//! comment explaining the general idea, see `librustc/middle/svh.rs`.
-
-use syntax::attr::AttributeMethods;
+//! Calculation of the (misnamed) "strict version hash" for crates and
+//! items. This hash is used to tell when the HIR changed in such a
+//! way that results from previous compilations may no longer be
+//! applicable and hence must be recomputed. It should probably be
+//! renamed to the ICH (incremental compilation hash).
+//!
+//! The hashes for all items are computed once at the beginning of
+//! compilation and stored into a map. In addition, a hash is computed
+//! of the **entire crate**.
+//!
+//! Storing the hashes in a map avoids the need to compute them twice
+//! (once when loading prior incremental results and once when
+//! saving), but it is also important for correctness: at least as of
+//! the time of this writing, the typeck passes rewrites entries in
+//! the dep-map in-place to accommodate UFCS resolutions. Since name
+//! resolution is part of the hash, the result is that hashes computed
+//! at the end of compilation would be different from those computed
+//! at the beginning.
+
+use syntax::ast;
 use std::hash::{Hash, SipHasher, Hasher};
+use rustc::dep_graph::DepNode;
+use rustc::hir;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
-use rustc::hir::map::{NodeItem, NodeForeignItem};
-use rustc::hir::svh::Svh;
+use rustc::hir::intravisit as visit;
 use rustc::ty::TyCtxt;
-use rustc::hir::intravisit::{self, Visitor};
+use rustc_data_structures::fnv::FnvHashMap;
 
+use self::def_path_hash::DefPathHashes;
 use self::svh_visitor::StrictVersionHashVisitor;
 
+mod def_path_hash;
 mod svh_visitor;
 
-pub trait SvhCalculate {
-    /// Calculate the SVH for an entire krate.
-    fn calculate_krate_hash(self) -> Svh;
-
-    /// Calculate the SVH for a particular item.
-    fn calculate_item_hash(self, def_id: DefId) -> u64;
+pub type IncrementalHashesMap = FnvHashMap<DepNode<DefId>, u64>;
+
+pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                                                    -> IncrementalHashesMap {
+    let _ignore = tcx.dep_graph.in_ignore();
+    let krate = tcx.map.krate();
+    let mut visitor = HashItemsVisitor { tcx: tcx,
+                                         hashes: FnvHashMap(),
+                                         def_path_hashes: DefPathHashes::new(tcx) };
+    visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| visit::walk_crate(v, krate));
+    krate.visit_all_items(&mut visitor);
+    visitor.compute_crate_hash();
+    visitor.hashes
 }
 
-impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> {
-    fn calculate_krate_hash(self) -> Svh {
-        // FIXME (#14132): This is better than it used to be, but it still not
-        // ideal. We now attempt to hash only the relevant portions of the
-        // Crate AST as well as the top-level crate attributes. (However,
-        // the hashing of the crate attributes should be double-checked
-        // to ensure it is not incorporating implementation artifacts into
-        // the hash that are not otherwise visible.)
+struct HashItemsVisitor<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    def_path_hashes: DefPathHashes<'a, 'tcx>,
+    hashes: IncrementalHashesMap,
+}
 
-        let crate_disambiguator = self.sess.local_crate_disambiguator();
-        let krate = self.map.krate();
+impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
+    fn calculate_node_id<W>(&mut self, id: ast::NodeId, walk_op: W)
+        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
+    {
+        let def_id = self.tcx.map.local_def_id(id);
+        self.calculate_def_id(def_id, walk_op)
+    }
 
-        // FIXME: this should use SHA1, not SipHash. SipHash is not built to
-        //        avoid collisions.
+    fn calculate_def_id<W>(&mut self, def_id: DefId, mut walk_op: W)
+        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
+    {
+        assert!(def_id.is_local());
+        debug!("HashItemsVisitor::calculate(def_id={:?})", def_id);
+        // FIXME: this should use SHA1, not SipHash. SipHash is not
+        // built to avoid collisions.
         let mut state = SipHasher::new();
-        debug!("state: {:?}", state);
+        walk_op(&mut StrictVersionHashVisitor::new(&mut state,
+                                                   self.tcx,
+                                                   &mut self.def_path_hashes));
+        let item_hash = state.finish();
+        self.hashes.insert(DepNode::Hir(def_id), item_hash);
+        debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, item_hash);
+    }
+
+    fn compute_crate_hash(&mut self) {
+        let krate = self.tcx.map.krate();
 
-        // FIXME(#32753) -- at (*) we `to_le` for endianness, but is
-        // this enough, and does it matter anyway?
-        "crate_disambiguator".hash(&mut state);
-        crate_disambiguator.len().to_le().hash(&mut state); // (*)
-        crate_disambiguator.hash(&mut state);
+        let mut crate_state = SipHasher::new();
 
-        debug!("crate_disambiguator: {:?}", crate_disambiguator);
-        debug!("state: {:?}", state);
+        let crate_disambiguator = self.tcx.sess.local_crate_disambiguator();
+        "crate_disambiguator".hash(&mut crate_state);
+        crate_disambiguator.len().hash(&mut crate_state);
+        crate_disambiguator.hash(&mut crate_state);
 
+        // add each item (in some deterministic order) to the overall
+        // crate hash.
         {
-            let mut visit = StrictVersionHashVisitor::new(&mut state, self);
-            krate.visit_all_items(&mut visit);
+            let def_path_hashes = &mut self.def_path_hashes;
+            let mut item_hashes: Vec<_> =
+                self.hashes.iter()
+                           .map(|(item_dep_node, &item_hash)| {
+                               // convert from a DepNode<DefId> tp a
+                               // DepNode<u64> where the u64 is the
+                               // hash of the def-id's def-path:
+                               let item_dep_node =
+                                   item_dep_node.map_def(|&did| Some(def_path_hashes.hash(did)))
+                                                .unwrap();
+                               (item_dep_node, item_hash)
+                           })
+                           .collect();
+            item_hashes.sort(); // avoid artificial dependencies on item ordering
+            item_hashes.hash(&mut crate_state);
         }
 
-        // FIXME (#14132): This hash is still sensitive to e.g. the
-        // spans of the crate Attributes and their underlying
-        // MetaItems; we should make ContentHashable impl for those
-        // types and then use hash_content.  But, since all crate
-        // attributes should appear near beginning of the file, it is
-        // not such a big deal to be sensitive to their spans for now.
-        //
-        // We hash only the MetaItems instead of the entire Attribute
-        // to avoid hashing the AttrId
         for attr in &krate.attrs {
             debug!("krate attr {:?}", attr);
-            attr.meta().hash(&mut state);
+            attr.meta().hash(&mut crate_state);
         }
 
-        Svh::new(state.finish())
+        let crate_hash = crate_state.finish();
+        self.hashes.insert(DepNode::Krate, crate_hash);
+        debug!("calculate_crate_hash: crate_hash={:?}", crate_hash);
     }
+}
 
-    fn calculate_item_hash(self, def_id: DefId) -> u64 {
-        assert!(def_id.is_local());
-
-        debug!("calculate_item_hash(def_id={:?})", def_id);
-
-        let mut state = SipHasher::new();
-
-        {
-            let mut visit = StrictVersionHashVisitor::new(&mut state, self);
-            if def_id.index == CRATE_DEF_INDEX {
-                // the crate root itself is not registered in the map
-                // as an item, so we have to fetch it this way
-                let krate = self.map.krate();
-                intravisit::walk_crate(&mut visit, krate);
-            } else {
-                let node_id = self.map.as_local_node_id(def_id).unwrap();
-                match self.map.find(node_id) {
-                    Some(NodeItem(item)) => visit.visit_item(item),
-                    Some(NodeForeignItem(item)) => visit.visit_foreign_item(item),
-                    r => bug!("calculate_item_hash: expected an item for node {} not {:?}",
-                              node_id, r),
-                }
-            }
-        }
-
-        let hash = state.finish();
 
-        debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, hash);
+impl<'a, 'tcx> visit::Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
+        self.calculate_node_id(item.id, |v| v.visit_item(item));
+        visit::walk_item(self, item);
+    }
 
-        hash
+    fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
+        self.calculate_node_id(item.id, |v| v.visit_foreign_item(item));
+        visit::walk_foreign_item(self, item);
     }
 }
+
index 42e7abeeaca8f250d809c0760fc142570c0a5622..c1158dc2d5fe990dfbabf3fa7c3c4047f12fb4e4 100644 (file)
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit as visit;
 use rustc::hir::intravisit::{Visitor, FnKind};
-use rustc::hir::map::DefPath;
 use rustc::ty::TyCtxt;
 
 use std::hash::{Hash, SipHasher};
 
-pub struct StrictVersionHashVisitor<'a, 'tcx: 'a> {
-    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
+use super::def_path_hash::DefPathHashes;
+
+pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> {
+    pub tcx: TyCtxt<'hash, 'tcx, 'tcx>,
     pub st: &'a mut SipHasher,
+
+    // collect a deterministic hash of def-ids that we have seen
+    def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
 }
 
-impl<'a, 'tcx> StrictVersionHashVisitor<'a, 'tcx> {
+impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
     pub fn new(st: &'a mut SipHasher,
-               tcx: TyCtxt<'a, 'tcx, 'tcx>)
+               tcx: TyCtxt<'hash, 'tcx, 'tcx>,
+               def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>)
                -> Self {
-        StrictVersionHashVisitor { st: st, tcx: tcx }
+        StrictVersionHashVisitor { st: st, tcx: tcx, def_path_hashes: def_path_hashes }
     }
 
-    fn hash_def_path(&mut self, path: &DefPath) {
-        path.deterministic_hash_to(self.tcx, self.st);
+    fn compute_def_id_hash(&mut self, def_id: DefId) -> u64 {
+        self.def_path_hashes.hash(def_id)
     }
 }
 
@@ -187,20 +192,20 @@ pub enum SawStmtComponent {
     SawStmtSemi,
 }
 
-impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> {
+impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> {
     fn visit_nested_item(&mut self, _: ItemId) {
         // Each item is hashed independently; ignore nested items.
     }
 
-    fn visit_variant_data(&mut self, s: &'a VariantData, name: Name,
-                          g: &'a Generics, _: NodeId, _: Span) {
+    fn visit_variant_data(&mut self, s: &'tcx VariantData, name: Name,
+                          g: &'tcx Generics, _: NodeId, _: Span) {
         debug!("visit_variant_data: st={:?}", self.st);
         SawStructDef(name.as_str()).hash(self.st);
         visit::walk_generics(self, g);
         visit::walk_struct_def(self, s)
     }
 
-    fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) {
+    fn visit_variant(&mut self, v: &'tcx Variant, g: &'tcx Generics, item_id: NodeId) {
         debug!("visit_variant: st={:?}", self.st);
         SawVariant.hash(self.st);
         // walk_variant does not call walk_generics, so do it here.
@@ -227,12 +232,12 @@ fn visit_name(&mut self, _: Span, name: Name) {
         SawIdent(name.as_str()).hash(self.st);
     }
 
-    fn visit_lifetime(&mut self, l: &'a Lifetime) {
+    fn visit_lifetime(&mut self, l: &'tcx Lifetime) {
         debug!("visit_lifetime: st={:?}", self.st);
         SawLifetime(l.name.as_str()).hash(self.st);
     }
 
-    fn visit_lifetime_def(&mut self, l: &'a LifetimeDef) {
+    fn visit_lifetime_def(&mut self, l: &'tcx LifetimeDef) {
         debug!("visit_lifetime_def: st={:?}", self.st);
         SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st);
     }
@@ -242,12 +247,12 @@ fn visit_lifetime_def(&mut self, l: &'a LifetimeDef) {
     // monomorphization and cross-crate inlining generally implies
     // that a change to a crate body will require downstream
     // crates to be recompiled.
-    fn visit_expr(&mut self, ex: &'a Expr) {
+    fn visit_expr(&mut self, ex: &'tcx Expr) {
         debug!("visit_expr: st={:?}", self.st);
         SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex)
     }
 
-    fn visit_stmt(&mut self, s: &'a Stmt) {
+    fn visit_stmt(&mut self, s: &'tcx Stmt) {
         debug!("visit_stmt: st={:?}", self.st);
 
         // We don't want to modify the hash for decls, because
@@ -265,7 +270,7 @@ fn visit_stmt(&mut self, s: &'a Stmt) {
         visit::walk_stmt(self, s)
     }
 
-    fn visit_foreign_item(&mut self, i: &'a ForeignItem) {
+    fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) {
         debug!("visit_foreign_item: st={:?}", self.st);
 
         // FIXME (#14132) ideally we would incorporate privacy (or
@@ -275,7 +280,7 @@ fn visit_foreign_item(&mut self, i: &'a ForeignItem) {
         SawForeignItem.hash(self.st); visit::walk_foreign_item(self, i)
     }
 
-    fn visit_item(&mut self, i: &'a Item) {
+    fn visit_item(&mut self, i: &'tcx Item) {
         debug!("visit_item: {:?} st={:?}", i, self.st);
 
         // FIXME (#14132) ideally would incorporate reachability
@@ -285,63 +290,63 @@ fn visit_item(&mut self, i: &'a Item) {
         SawItem.hash(self.st); visit::walk_item(self, i)
     }
 
-    fn visit_mod(&mut self, m: &'a Mod, _s: Span, n: NodeId) {
+    fn visit_mod(&mut self, m: &'tcx Mod, _s: Span, n: NodeId) {
         debug!("visit_mod: st={:?}", self.st);
         SawMod.hash(self.st); visit::walk_mod(self, m, n)
     }
 
-    fn visit_ty(&mut self, t: &'a Ty) {
+    fn visit_ty(&mut self, t: &'tcx Ty) {
         debug!("visit_ty: st={:?}", self.st);
         SawTy.hash(self.st); visit::walk_ty(self, t)
     }
 
-    fn visit_generics(&mut self, g: &'a Generics) {
+    fn visit_generics(&mut self, g: &'tcx Generics) {
         debug!("visit_generics: st={:?}", self.st);
         SawGenerics.hash(self.st); visit::walk_generics(self, g)
     }
 
-    fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl,
-                b: &'a Block, s: Span, n: NodeId) {
+    fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx FnDecl,
+                b: &'tcx Block, s: Span, n: NodeId) {
         debug!("visit_fn: st={:?}", self.st);
         SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s, n)
     }
 
-    fn visit_trait_item(&mut self, ti: &'a TraitItem) {
+    fn visit_trait_item(&mut self, ti: &'tcx TraitItem) {
         debug!("visit_trait_item: st={:?}", self.st);
         SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti)
     }
 
-    fn visit_impl_item(&mut self, ii: &'a ImplItem) {
+    fn visit_impl_item(&mut self, ii: &'tcx ImplItem) {
         debug!("visit_impl_item: st={:?}", self.st);
         SawImplItem.hash(self.st); visit::walk_impl_item(self, ii)
     }
 
-    fn visit_struct_field(&mut self, s: &'a StructField) {
+    fn visit_struct_field(&mut self, s: &'tcx StructField) {
         debug!("visit_struct_field: st={:?}", self.st);
         SawStructField.hash(self.st); visit::walk_struct_field(self, s)
     }
 
-    fn visit_path(&mut self, path: &'a Path, _: ast::NodeId) {
+    fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) {
         debug!("visit_path: st={:?}", self.st);
         SawPath.hash(self.st); visit::walk_path(self, path)
     }
 
-    fn visit_block(&mut self, b: &'a Block) {
+    fn visit_block(&mut self, b: &'tcx Block) {
         debug!("visit_block: st={:?}", self.st);
         SawBlock.hash(self.st); visit::walk_block(self, b)
     }
 
-    fn visit_pat(&mut self, p: &'a Pat) {
+    fn visit_pat(&mut self, p: &'tcx Pat) {
         debug!("visit_pat: st={:?}", self.st);
         SawPat.hash(self.st); visit::walk_pat(self, p)
     }
 
-    fn visit_local(&mut self, l: &'a Local) {
+    fn visit_local(&mut self, l: &'tcx Local) {
         debug!("visit_local: st={:?}", self.st);
         SawLocal.hash(self.st); visit::walk_local(self, l)
     }
 
-    fn visit_arm(&mut self, a: &'a Arm) {
+    fn visit_arm(&mut self, a: &'tcx Arm) {
         debug!("visit_arm: st={:?}", self.st);
         SawArm.hash(self.st); visit::walk_arm(self, a)
     }
@@ -361,7 +366,7 @@ pub enum DefHash {
     SawErr,
 }
 
-impl<'a, 'tcx> StrictVersionHashVisitor<'a, 'tcx> {
+impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
     fn hash_resolve(&mut self, id: ast::NodeId) {
         // Because whether or not a given id has an entry is dependent
         // solely on expr variant etc, we don't need to hash whether
@@ -369,20 +374,29 @@ fn hash_resolve(&mut self, id: ast::NodeId) {
         // variant it is above when we visit the HIR).
 
         if let Some(def) = self.tcx.def_map.borrow().get(&id) {
+            debug!("hash_resolve: id={:?} def={:?} st={:?}", id, def, self.st);
             self.hash_partial_def(def);
         }
 
         if let Some(traits) = self.tcx.trait_map.get(&id) {
+            debug!("hash_resolve: id={:?} traits={:?} st={:?}", id, traits, self.st);
             traits.len().hash(self.st);
-            for candidate in traits {
-                self.hash_def_id(candidate.def_id);
-            }
+
+            // The ordering of the candidates is not fixed. So we hash
+            // the def-ids and then sort them and hash the collection.
+            let mut candidates: Vec<_> =
+                traits.iter()
+                      .map(|&TraitCandidate { def_id, import_id: _ }| {
+                          self.compute_def_id_hash(def_id)
+                      })
+                      .collect();
+            candidates.sort();
+            candidates.hash(self.st);
         }
     }
 
     fn hash_def_id(&mut self, def_id: DefId) {
-        let def_path = self.tcx.def_path(def_id);
-        self.hash_def_path(&def_path);
+        self.compute_def_id_hash(def_id).hash(self.st);
     }
 
     fn hash_partial_def(&mut self, def: &PathResolution) {
index 0d11b0794feacea61a4292f1be2c7bc7286b0d58..511ba8ec19cc7fe3e9ceea29a359757271df2317 100644 (file)
@@ -22,6 +22,7 @@
 #![feature(question_mark)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
+#![feature(rand)]
 
 extern crate graphviz;
 extern crate rbml;
 mod persist;
 
 pub use assert_dep_graph::assert_dep_graph;
-pub use calculate_svh::SvhCalculate;
+pub use calculate_svh::compute_incremental_hashes_map;
+pub use calculate_svh::IncrementalHashesMap;
 pub use persist::load_dep_graph;
 pub use persist::save_dep_graph;
 pub use persist::save_trans_partition;
 pub use persist::save_work_products;
 pub use persist::in_incr_comp_dir;
+pub use persist::finalize_session_directory;
index 3c77cc07d3d89283b37a1feda18444e8309618c7..fda7ef207a3447a434a97edd5f85f7197fd0944a 100644 (file)
@@ -31,8 +31,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::Visitor;
 use rustc_data_structures::fnv::FnvHashSet;
-use syntax::ast::{self, Attribute, MetaItem};
-use syntax::attr::AttrMetaMethods;
+use syntax::ast::{self, Attribute, NestedMetaItem};
 use syntax::parse::token::InternedString;
 use rustc::ty::TyCtxt;
 
@@ -71,13 +70,17 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
 }
 
 impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
-    fn expect_associated_value(&self, item: &MetaItem) -> InternedString {
+    fn expect_associated_value(&self, item: &NestedMetaItem) -> InternedString {
         if let Some(value) = item.value_str() {
             value
         } else {
-            self.tcx.sess.span_fatal(
-                item.span,
-                &format!("associated value expected for `{}`", item.name()));
+            let msg = if let Some(name) = item.name() {
+                format!("associated value expected for `{}`", name)
+            } else {
+                "expected an associated value".to_string()
+            };
+
+            self.tcx.sess.span_fatal(item.span, &msg);
         }
     }
 
@@ -133,6 +136,7 @@ fn assert_dirty(&self, item: &hir::Item, dep_node: DepNode<DefId>) {
         debug!("assert_dirty({:?})", dep_node);
 
         match dep_node {
+            DepNode::Krate |
             DepNode::Hir(_) => {
                 // HIR nodes are inputs, so if we are asserting that the HIR node is
                 // dirty, we check the dirty input set.
@@ -161,6 +165,7 @@ fn assert_clean(&self, item: &hir::Item, dep_node: DepNode<DefId>) {
         debug!("assert_clean({:?})", dep_node);
 
         match dep_node {
+            DepNode::Krate |
             DepNode::Hir(_) => {
                 // For HIR nodes, check the inputs.
                 if self.dirty_inputs.contains(&dep_node) {
diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs
new file mode 100644 (file)
index 0000000..4ad4b11
--- /dev/null
@@ -0,0 +1,1049 @@
+// 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 manages how the incremental compilation cache is represented in
+//! the file system.
+//!
+//! Incremental compilation caches are managed according to a copy-on-write
+//! strategy: Once a complete, consistent cache version is finalized, it is
+//! never modified. Instead, when a subsequent compilation session is started,
+//! the compiler will allocate a new version of the cache that starts out as
+//! a copy of the previous version. Then only this new copy is modified and it
+//! will not be visible to other processes until it is finalized. This ensures
+//! that multiple compiler processes can be executed concurrently for the same
+//! crate without interfering with each other or blocking each other.
+//!
+//! More concretely this is implemented via the following protocol:
+//!
+//! 1. For a newly started compilation session, the compiler allocates a
+//!    new `session` directory within the incremental compilation directory.
+//!    This session directory will have a unique name that ends with the suffix
+//!    "-working" and that contains a creation timestamp.
+//! 2. Next, the compiler looks for the newest finalized session directory,
+//!    that is, a session directory from a previous compilation session that
+//!    has been marked as valid and consistent. A session directory is
+//!    considered finalized if the "-working" suffix in the directory name has
+//!    been replaced by the SVH of the crate.
+//! 3. Once the compiler has found a valid, finalized session directory, it will
+//!    hard-link/copy its contents into the new "-working" directory. If all
+//!    goes well, it will have its own, private copy of the source directory and
+//!    subsequently not have to worry about synchronizing with other compiler
+//!    processes.
+//! 4. Now the compiler can do its normal compilation process, which involves
+//!    reading and updating its private session directory.
+//! 5. When compilation finishes without errors, the private session directory
+//!    will be in a state where it can be used as input for other compilation
+//!    sessions. That is, it will contain a dependency graph and cache artifacts
+//!    that are consistent with the state of the source code it was compiled
+//!    from, with no need to change them ever again. At this point, the compiler
+//!    finalizes and "publishes" its private session directory by renaming it
+//!    from "s-{timestamp}-{random}-working" to "s-{timestamp}-{SVH}".
+//! 6. At this point the "old" session directory that we copied our data from
+//!    at the beginning of the session has become obsolete because we have just
+//!    published a more current version. Thus the compiler will delete it.
+//!
+//! ## Garbage Collection
+//!
+//! Naively following the above protocol might lead to old session directories
+//! piling up if a compiler instance crashes for some reason before its able to
+//! remove its private session directory. In order to avoid wasting disk space,
+//! the compiler also does some garbage collection each time it is started in
+//! incremental compilation mode. Specifically, it will scan the incremental
+//! compilation directory for private session directories that are not in use
+//! any more and will delete those. It will also delete any finalized session
+//! directories for a given crate except for the most recent one.
+//!
+//! ## Synchronization
+//!
+//! There is some synchronization needed in order for the compiler to be able to
+//! determine whether a given private session directory is not in used any more.
+//! This is done by creating a lock file for each session directory and
+//! locking it while the directory is still being used. Since file locks have
+//! operating system support, we can rely on the lock being released if the
+//! compiler process dies for some unexpected reason. Thus, when garbage
+//! collecting private session directories, the collecting process can determine
+//! whether the directory is still in use by trying to acquire a lock on the
+//! file. If locking the file fails, the original process must still be alive.
+//! If locking the file succeeds, we know that the owning process is not alive
+//! any more and we can safely delete the directory.
+//! There is still a small time window between the original process creating the
+//! lock file and actually locking it. In order to minimize the chance that
+//! another process tries to acquire the lock in just that instance, only
+//! session directories that are older than a few seconds are considered for
+//! garbage collection.
+//!
+//! Another case that has to be considered is what happens if one process
+//! deletes a finalized session directory that another process is currently
+//! trying to copy from. This case is also handled via the lock file. Before
+//! a process starts copying a finalized session directory, it will acquire a
+//! shared lock on the directory's lock file. Any garbage collecting process,
+//! on the other hand, will acquire an exclusive lock on the lock file.
+//! Thus, if a directory is being collected, any reader process will fail
+//! acquiring the shared lock and will leave the directory alone. Conversely,
+//! if a collecting process can't acquire the exclusive lock because the
+//! directory is currently being read from, it will leave collecting that
+//! directory to another process at a later point in time.
+//! The exact same scheme is also used when reading the metadata hashes file
+//! from an extern crate. When a crate is compiled, the hash values of its
+//! metadata are stored in a file in its session directory. When the
+//! compilation session of another crate imports the first crate's metadata,
+//! it also has to read in the accompanying metadata hashes. It thus will access
+//! the finalized session directory of all crates it links to and while doing
+//! so, it will also place a read lock on that the respective session directory
+//! so that it won't be deleted while the metadata hashes are loaded.
+//!
+//! ## Preconditions
+//!
+//! This system relies on two features being available in the file system in
+//! order to work really well: file locking and hard linking.
+//! If hard linking is not available (like on FAT) the data in the cache
+//! actually has to be copied at the beginning of each session.
+//! If file locking does not work reliably (like on NFS), some of the
+//! synchronization will go haywire.
+//! In both cases we recommend to locate the incremental compilation directory
+//! on a file system that supports these things.
+//! It might be a good idea though to try and detect whether we are on an
+//! unsupported file system and emit a warning in that case. This is not yet
+//! implemented.
+
+use rustc::hir::svh::Svh;
+use rustc::middle::cstore::LOCAL_CRATE;
+use rustc::session::Session;
+use rustc::ty::TyCtxt;
+use rustc::util::fs as fs_util;
+use rustc_data_structures::flock;
+use rustc_data_structures::fnv::{FnvHashSet, FnvHashMap};
+
+use std::ffi::OsString;
+use std::fs as std_fs;
+use std::io;
+use std::mem;
+use std::path::{Path, PathBuf};
+use std::time::{UNIX_EPOCH, SystemTime, Duration};
+use std::__rand::{thread_rng, Rng};
+use syntax::ast;
+
+const LOCK_FILE_EXT: &'static str = ".lock";
+const DEP_GRAPH_FILENAME: &'static str = "dep-graph.bin";
+const WORK_PRODUCTS_FILENAME: &'static str = "work-products.bin";
+const METADATA_HASHES_FILENAME: &'static str = "metadata.bin";
+
+pub fn dep_graph_path(sess: &Session) -> PathBuf {
+    in_incr_comp_dir_sess(sess, DEP_GRAPH_FILENAME)
+}
+
+pub fn work_products_path(sess: &Session) -> PathBuf {
+    in_incr_comp_dir_sess(sess, WORK_PRODUCTS_FILENAME)
+}
+
+pub fn metadata_hash_export_path(sess: &Session) -> PathBuf {
+    in_incr_comp_dir_sess(sess, METADATA_HASHES_FILENAME)
+}
+
+pub fn metadata_hash_import_path(import_session_dir: &Path) -> PathBuf {
+    import_session_dir.join(METADATA_HASHES_FILENAME)
+}
+
+pub fn lock_file_path(session_dir: &Path) -> PathBuf {
+    let crate_dir = session_dir.parent().unwrap();
+
+    let directory_name = session_dir.file_name().unwrap().to_string_lossy();
+    assert_no_characters_lost(&directory_name);
+
+    let dash_indices: Vec<_> = directory_name.match_indices("-")
+                                             .map(|(idx, _)| idx)
+                                             .collect();
+    if dash_indices.len() != 3 {
+        bug!("Encountered incremental compilation session directory with \
+              malformed name: {}",
+             session_dir.display())
+    }
+
+    crate_dir.join(&directory_name[0 .. dash_indices[2]])
+             .with_extension(&LOCK_FILE_EXT[1..])
+}
+
+pub fn in_incr_comp_dir_sess(sess: &Session, file_name: &str) -> PathBuf {
+    in_incr_comp_dir(&sess.incr_comp_session_dir(), file_name)
+}
+
+pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBuf {
+    incr_comp_session_dir.join(file_name)
+}
+
+/// Allocates the private session directory. The boolean in the Ok() result
+/// indicates whether we should try loading a dep graph from the successfully
+/// initialized directory, or not.
+/// The post-condition of this fn is that we have a valid incremental
+/// compilation session directory, if the result is `Ok`. A valid session
+/// directory is one that contains a locked lock file. It may or may not contain
+/// a dep-graph and work products from a previous session.
+/// If the call fails, the fn may leave behind an invalid session directory.
+/// The garbage collection will take care of it.
+pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
+    debug!("prepare_session_directory");
+
+    // {incr-comp-dir}/{crate-name-and-disambiguator}
+    let crate_dir = crate_path_tcx(tcx, LOCAL_CRATE);
+    debug!("crate-dir: {}", crate_dir.display());
+    try!(create_dir(tcx.sess, &crate_dir, "crate"));
+
+    let mut source_directories_already_tried = FnvHashSet();
+
+    loop {
+        // Generate a session directory of the form:
+        //
+        // {incr-comp-dir}/{crate-name-and-disambiguator}/s-{timestamp}-{random}-working
+        let session_dir = generate_session_dir_path(&crate_dir);
+        debug!("session-dir: {}", session_dir.display());
+
+        // Lock the new session directory. If this fails, return an
+        // error without retrying
+        let (directory_lock, lock_file_path) = try!(lock_directory(tcx.sess, &session_dir));
+
+        // Now that we have the lock, we can actually create the session
+        // directory
+        try!(create_dir(tcx.sess, &session_dir, "session"));
+
+        // Find a suitable source directory to copy from. Ignore those that we
+        // have already tried before.
+        let source_directory = find_source_directory(&crate_dir,
+                                                     &source_directories_already_tried);
+
+        let source_directory = if let Some(dir) = source_directory {
+            dir
+        } else {
+            // There's nowhere to copy from, we're done
+            debug!("no source directory found. Continuing with empty session \
+                    directory.");
+
+            tcx.sess.init_incr_comp_session(session_dir, directory_lock);
+            return Ok(false)
+        };
+
+        debug!("attempting to copy data from source: {}",
+               source_directory.display());
+
+        let print_file_copy_stats = tcx.sess.opts.debugging_opts.incremental_info;
+
+        // Try copying over all files from the source directory
+        if copy_files(&session_dir, &source_directory, print_file_copy_stats).is_ok() {
+            debug!("successfully copied data from: {}",
+                   source_directory.display());
+
+            tcx.sess.init_incr_comp_session(session_dir, directory_lock);
+            return Ok(true)
+        } else {
+             debug!("copying failed - trying next directory");
+
+            // Something went wrong while trying to copy/link files from the
+            // source directory. Try again with a different one.
+            source_directories_already_tried.insert(source_directory);
+
+            // Try to remove the session directory we just allocated. We don't
+            // know if there's any garbage in it from the failed copy action.
+            if let Err(err) = safe_remove_dir_all(&session_dir) {
+                tcx.sess.warn(&format!("Failed to delete partly initialized \
+                                        session dir `{}`: {}",
+                                       session_dir.display(),
+                                       err));
+            }
+
+            delete_session_dir_lock_file(tcx.sess, &lock_file_path);
+            mem::drop(directory_lock);
+        }
+    }
+}
+
+
+/// This function finalizes and thus 'publishes' the session directory by
+/// renaming it to `s-{timestamp}-{svh}` and releasing the file lock.
+/// If there have been compilation errors, however, this function will just
+/// delete the presumably invalid session directory.
+pub fn finalize_session_directory(sess: &Session, svh: Svh) {
+    if sess.opts.incremental.is_none() {
+        return;
+    }
+
+    let incr_comp_session_dir: PathBuf = sess.incr_comp_session_dir().clone();
+
+    if sess.has_errors() {
+        // If there have been any errors during compilation, we don't want to
+        // publish this session directory. Rather, we'll just delete it.
+
+        debug!("finalize_session_directory() - invalidating session directory: {}",
+                incr_comp_session_dir.display());
+
+        if let Err(err) = safe_remove_dir_all(&*incr_comp_session_dir) {
+            sess.warn(&format!("Error deleting incremental compilation \
+                                session directory `{}`: {}",
+                               incr_comp_session_dir.display(),
+                               err));
+        }
+
+        let lock_file_path = lock_file_path(&*incr_comp_session_dir);
+        delete_session_dir_lock_file(sess, &lock_file_path);
+        sess.mark_incr_comp_session_as_invalid();
+    }
+
+    debug!("finalize_session_directory() - session directory: {}",
+            incr_comp_session_dir.display());
+
+    let old_sub_dir_name = incr_comp_session_dir.file_name()
+                                                .unwrap()
+                                                .to_string_lossy();
+    assert_no_characters_lost(&old_sub_dir_name);
+
+    // Keep the 's-{timestamp}-{random-number}' prefix, but replace the
+    // '-working' part with the SVH of the crate
+    let dash_indices: Vec<_> = old_sub_dir_name.match_indices("-")
+                                               .map(|(idx, _)| idx)
+                                               .collect();
+    if dash_indices.len() != 3 {
+        bug!("Encountered incremental compilation session directory with \
+              malformed name: {}",
+             incr_comp_session_dir.display())
+    }
+
+    // State: "s-{timestamp}-{random-number}-"
+    let mut new_sub_dir_name = String::from(&old_sub_dir_name[.. dash_indices[2] + 1]);
+
+    // Append the svh
+    new_sub_dir_name.push_str(&encode_base_36(svh.as_u64()));
+
+    // Create the full path
+    let new_path = incr_comp_session_dir.parent().unwrap().join(new_sub_dir_name);
+    debug!("finalize_session_directory() - new path: {}", new_path.display());
+
+    match std_fs::rename(&*incr_comp_session_dir, &new_path) {
+        Ok(_) => {
+            debug!("finalize_session_directory() - directory renamed successfully");
+
+            // This unlocks the directory
+            sess.finalize_incr_comp_session(new_path);
+        }
+        Err(e) => {
+            // Warn about the error. However, no need to abort compilation now.
+            sess.warn(&format!("Error finalizing incremental compilation \
+                               session directory `{}`: {}",
+                               incr_comp_session_dir.display(),
+                               e));
+
+            debug!("finalize_session_directory() - error, marking as invalid");
+            // Drop the file lock, so we can garage collect
+            sess.mark_incr_comp_session_as_invalid();
+        }
+    }
+
+    let _ = garbage_collect_session_directories(sess);
+}
+
+fn copy_files(target_dir: &Path,
+              source_dir: &Path,
+              print_stats_on_success: bool)
+              -> Result<(), ()> {
+    // We acquire a shared lock on the lock file of the directory, so that
+    // nobody deletes it out from under us while we are reading from it.
+    let lock_file_path = lock_file_path(source_dir);
+    let _lock = if let Ok(lock) = flock::Lock::new(&lock_file_path,
+                                                   false,   // don't wait,
+                                                   false,   // don't create
+                                                   false) { // not exclusive
+        lock
+    } else {
+        // Could not acquire the lock, don't try to copy from here
+        return Err(())
+    };
+
+    let source_dir_iterator = match source_dir.read_dir() {
+        Ok(it) => it,
+        Err(_) => return Err(())
+    };
+
+    let mut files_linked = 0;
+    let mut files_copied = 0;
+
+    for entry in source_dir_iterator {
+        match entry {
+            Ok(entry) => {
+                let file_name = entry.file_name();
+
+                let target_file_path = target_dir.join(file_name);
+                let source_path = entry.path();
+
+                debug!("copying into session dir: {}", source_path.display());
+                match fs_util::link_or_copy(source_path, target_file_path) {
+                    Ok(fs_util::LinkOrCopy::Link) => {
+                        files_linked += 1
+                    }
+                    Ok(fs_util::LinkOrCopy::Copy) => {
+                        files_copied += 1
+                    }
+                    Err(_) => return Err(())
+                }
+            }
+            Err(_) => {
+                return Err(())
+            }
+        }
+    }
+
+    if print_stats_on_success {
+        println!("incr. comp. session directory: {} files hard-linked", files_linked);
+        println!("incr. comp. session directory: {} files copied", files_copied);
+    }
+
+    Ok(())
+}
+
+/// Generate unique directory path of the form:
+/// {crate_dir}/s-{timestamp}-{random-number}-working
+fn generate_session_dir_path(crate_dir: &Path) -> PathBuf {
+    let timestamp = timestamp_to_string(SystemTime::now());
+    debug!("generate_session_dir_path: timestamp = {}", timestamp);
+    let random_number = thread_rng().next_u32();
+    debug!("generate_session_dir_path: random_number = {}", random_number);
+
+    let directory_name = format!("s-{}-{}-working",
+                                  timestamp,
+                                  encode_base_36(random_number as u64));
+    debug!("generate_session_dir_path: directory_name = {}", directory_name);
+    let directory_path = crate_dir.join(directory_name);
+    debug!("generate_session_dir_path: directory_path = {}", directory_path.display());
+    directory_path
+}
+
+fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(),()> {
+    match fs_util::create_dir_racy(path) {
+        Ok(()) => {
+            debug!("{} directory created successfully", dir_tag);
+            Ok(())
+        }
+        Err(err) => {
+            sess.err(&format!("Could not create incremental compilation {} \
+                               directory `{}`: {}",
+                              dir_tag,
+                              path.display(),
+                              err));
+            Err(())
+        }
+    }
+}
+
+/// Allocate a the lock-file and lock it.
+fn lock_directory(sess: &Session,
+                  session_dir: &Path)
+                  -> Result<(flock::Lock, PathBuf), ()> {
+    let lock_file_path = lock_file_path(session_dir);
+    debug!("lock_directory() - lock_file: {}", lock_file_path.display());
+
+    match flock::Lock::new(&lock_file_path,
+                           false, // don't wait
+                           true,  // create the lock file
+                           true) { // the lock should be exclusive
+        Ok(lock) => Ok((lock, lock_file_path)),
+        Err(err) => {
+            sess.err(&format!("incremental compilation: could not create \
+                               session directory lock file: {}", err));
+            Err(())
+        }
+    }
+}
+
+fn delete_session_dir_lock_file(sess: &Session,
+                                lock_file_path: &Path) {
+    if let Err(err) = safe_remove_file(&lock_file_path) {
+        sess.warn(&format!("Error deleting lock file for incremental \
+                            compilation session directory `{}`: {}",
+                           lock_file_path.display(),
+                           err));
+    }
+}
+
+/// Find the most recent published session directory that is not in the
+/// ignore-list.
+fn find_source_directory(crate_dir: &Path,
+                         source_directories_already_tried: &FnvHashSet<PathBuf>)
+                         -> Option<PathBuf> {
+    let iter = crate_dir.read_dir()
+                        .unwrap() // FIXME
+                        .filter_map(|e| e.ok().map(|e| e.path()));
+
+    find_source_directory_in_iter(iter, source_directories_already_tried)
+}
+
+fn find_source_directory_in_iter<I>(iter: I,
+                                    source_directories_already_tried: &FnvHashSet<PathBuf>)
+                                    -> Option<PathBuf>
+    where I: Iterator<Item=PathBuf>
+{
+    let mut best_candidate = (UNIX_EPOCH, None);
+
+    for session_dir in iter {
+        debug!("find_source_directory_in_iter - inspecting `{}`",
+               session_dir.display());
+
+        let directory_name = session_dir.file_name().unwrap().to_string_lossy();
+        assert_no_characters_lost(&directory_name);
+
+        if source_directories_already_tried.contains(&session_dir) ||
+           !is_session_directory(&directory_name) ||
+           !is_finalized(&directory_name) {
+            debug!("find_source_directory_in_iter - ignoring.");
+            continue
+        }
+
+        let timestamp = extract_timestamp_from_session_dir(&directory_name)
+            .unwrap_or_else(|_| {
+                bug!("unexpected incr-comp session dir: {}", session_dir.display())
+            });
+
+        if timestamp > best_candidate.0 {
+            best_candidate = (timestamp, Some(session_dir.clone()));
+        }
+    }
+
+    best_candidate.1
+}
+
+fn is_finalized(directory_name: &str) -> bool {
+    !directory_name.ends_with("-working")
+}
+
+fn is_session_directory(directory_name: &str) -> bool {
+    directory_name.starts_with("s-") &&
+    !directory_name.ends_with(LOCK_FILE_EXT)
+}
+
+fn is_session_directory_lock_file(file_name: &str) -> bool {
+    file_name.starts_with("s-") && file_name.ends_with(LOCK_FILE_EXT)
+}
+
+fn extract_timestamp_from_session_dir(directory_name: &str)
+                                      -> Result<SystemTime, ()> {
+    if !is_session_directory(directory_name) {
+        return Err(())
+    }
+
+    let dash_indices: Vec<_> = directory_name.match_indices("-")
+                                             .map(|(idx, _)| idx)
+                                             .collect();
+    if dash_indices.len() != 3 {
+        return Err(())
+    }
+
+    string_to_timestamp(&directory_name[dash_indices[0]+1 .. dash_indices[1]])
+}
+
+const BASE_36: &'static [u8] = b"0123456789abcdefghijklmnopqrstuvwxyz";
+
+fn encode_base_36(mut n: u64) -> String {
+    let mut s = Vec::with_capacity(13);
+    loop {
+        s.push(BASE_36[(n % 36) as usize]);
+        n /= 36;
+
+        if n == 0 {
+            break;
+        }
+    }
+    s.reverse();
+    String::from_utf8(s).unwrap()
+}
+
+fn timestamp_to_string(timestamp: SystemTime) -> String {
+    let duration = timestamp.duration_since(UNIX_EPOCH).unwrap();
+    let micros = duration.as_secs() * 1_000_000 +
+                (duration.subsec_nanos() as u64) / 1000;
+    encode_base_36(micros)
+}
+
+fn string_to_timestamp(s: &str) -> Result<SystemTime, ()> {
+    let micros_since_unix_epoch = u64::from_str_radix(s, 36);
+
+    if micros_since_unix_epoch.is_err() {
+        return Err(())
+    }
+
+    let micros_since_unix_epoch = micros_since_unix_epoch.unwrap();
+
+    let duration = Duration::new(micros_since_unix_epoch / 1_000_000,
+                                 1000 * (micros_since_unix_epoch % 1_000_000) as u32);
+    Ok(UNIX_EPOCH + duration)
+}
+
+fn crate_path_tcx(tcx: TyCtxt, cnum: ast::CrateNum) -> PathBuf {
+    crate_path(tcx.sess, &tcx.crate_name(cnum), &tcx.crate_disambiguator(cnum))
+}
+
+/// Finds the session directory containing the correct metadata hashes file for
+/// the given crate. In order to do that it has to compute the crate directory
+/// of the given crate, and in there, look for the session directory with the
+/// correct SVH in it.
+/// Note that we have to match on the exact SVH here, not just the
+/// crate's (name, disambiguator) pair. The metadata hashes are only valid for
+/// the exact version of the binary we are reading from now (i.e. the hashes
+/// are part of the dependency graph of a specific compilation session).
+pub fn find_metadata_hashes_for(tcx: TyCtxt, cnum: ast::CrateNum) -> Option<PathBuf> {
+    let crate_directory = crate_path_tcx(tcx, cnum);
+
+    if !crate_directory.exists() {
+        return None
+    }
+
+    let dir_entries = match crate_directory.read_dir() {
+        Ok(dir_entries) => dir_entries,
+        Err(e) => {
+            tcx.sess
+               .err(&format!("incremental compilation: Could not read crate directory `{}`: {}",
+                             crate_directory.display(), e));
+            return None
+        }
+    };
+
+    let target_svh = tcx.sess.cstore.crate_hash(cnum);
+    let target_svh = encode_base_36(target_svh.as_u64());
+
+    let sub_dir = find_metadata_hashes_iter(&target_svh, dir_entries.filter_map(|e| {
+        e.ok().map(|e| e.file_name().to_string_lossy().into_owned())
+    }));
+
+    sub_dir.map(|sub_dir_name| crate_directory.join(&sub_dir_name))
+}
+
+fn find_metadata_hashes_iter<'a, I>(target_svh: &str, iter: I) -> Option<OsString>
+    where I: Iterator<Item=String>
+{
+    for sub_dir_name in iter {
+        if !is_session_directory(&sub_dir_name) || !is_finalized(&sub_dir_name) {
+            // This is not a usable session directory
+            continue
+        }
+
+        let is_match = if let Some(last_dash_pos) = sub_dir_name.rfind("-") {
+            let candidate_svh = &sub_dir_name[last_dash_pos + 1 .. ];
+            target_svh == candidate_svh
+        } else {
+            // some kind of invalid directory name
+            continue
+        };
+
+        if is_match {
+            return Some(OsString::from(sub_dir_name))
+        }
+    }
+
+    None
+}
+
+fn crate_path(sess: &Session,
+              crate_name: &str,
+              crate_disambiguator: &str)
+              -> PathBuf {
+    use std::hash::{SipHasher, Hasher, Hash};
+
+    let incr_dir = sess.opts.incremental.as_ref().unwrap().clone();
+
+    // The full crate disambiguator is really long. A hash of it should be
+    // sufficient.
+    let mut hasher = SipHasher::new();
+    crate_disambiguator.hash(&mut hasher);
+
+    let crate_name = format!("{}-{}", crate_name, encode_base_36(hasher.finish()));
+    incr_dir.join(crate_name)
+}
+
+fn assert_no_characters_lost(s: &str) {
+    if s.contains('\u{FFFD}') {
+        bug!("Could not losslessly convert '{}'.", s)
+    }
+}
+
+fn is_old_enough_to_be_collected(timestamp: SystemTime) -> bool {
+    timestamp < SystemTime::now() - Duration::from_secs(10)
+}
+
+pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> {
+    debug!("garbage_collect_session_directories() - begin");
+
+    let session_directory = sess.incr_comp_session_dir();
+    debug!("garbage_collect_session_directories() - session directory: {}",
+        session_directory.display());
+
+    let crate_directory = session_directory.parent().unwrap();
+    debug!("garbage_collect_session_directories() - crate directory: {}",
+        crate_directory.display());
+
+    // First do a pass over the crate directory, collecting lock files and
+    // session directories
+    let mut session_directories = FnvHashSet();
+    let mut lock_files = FnvHashSet();
+
+    for dir_entry in try!(crate_directory.read_dir()) {
+        let dir_entry = match dir_entry {
+            Ok(dir_entry) => dir_entry,
+            _ => {
+                // Ignore any errors
+                continue
+            }
+        };
+
+        let entry_name = dir_entry.file_name();
+        let entry_name = entry_name.to_string_lossy();
+
+        if is_session_directory_lock_file(&entry_name) {
+            assert_no_characters_lost(&entry_name);
+            lock_files.insert(entry_name.into_owned());
+        } else if is_session_directory(&entry_name) {
+            assert_no_characters_lost(&entry_name);
+            session_directories.insert(entry_name.into_owned());
+        } else {
+            // This is something we don't know, leave it alone
+        }
+    }
+
+    // Now map from lock files to session directories
+    let lock_file_to_session_dir: FnvHashMap<String, Option<String>> =
+        lock_files.into_iter()
+                  .map(|lock_file_name| {
+                        assert!(lock_file_name.ends_with(LOCK_FILE_EXT));
+                        let dir_prefix_end = lock_file_name.len() - LOCK_FILE_EXT.len();
+                        let session_dir = {
+                            let dir_prefix = &lock_file_name[0 .. dir_prefix_end];
+                            session_directories.iter()
+                                               .find(|dir_name| dir_name.starts_with(dir_prefix))
+                        };
+                        (lock_file_name, session_dir.map(String::clone))
+                    })
+                  .collect();
+
+    // Delete all lock files, that don't have an associated directory. They must
+    // be some kind of leftover
+    for (lock_file_name, directory_name) in &lock_file_to_session_dir {
+        if directory_name.is_none() {
+            let timestamp = match extract_timestamp_from_session_dir(lock_file_name) {
+                Ok(timestamp) => timestamp,
+                Err(()) => {
+                    debug!("Found lock-file with malformed timestamp: {}",
+                        crate_directory.join(&lock_file_name).display());
+                    // Ignore it
+                    continue
+                }
+            };
+
+            let lock_file_path = crate_directory.join(&**lock_file_name);
+
+            if is_old_enough_to_be_collected(timestamp) {
+                debug!("garbage_collect_session_directories() - deleting \
+                        garbage lock file: {}", lock_file_path.display());
+                delete_session_dir_lock_file(sess, &lock_file_path);
+            } else {
+                debug!("garbage_collect_session_directories() - lock file with \
+                        no session dir not old enough to be collected: {}",
+                       lock_file_path.display());
+            }
+        }
+    }
+
+    // Filter out `None` directories
+    let lock_file_to_session_dir: FnvHashMap<String, String> =
+        lock_file_to_session_dir.into_iter()
+                                .filter_map(|(lock_file_name, directory_name)| {
+                                    directory_name.map(|n| (lock_file_name, n))
+                                })
+                                .collect();
+
+    let mut deletion_candidates = vec![];
+    let mut definitely_delete = vec![];
+
+    for (lock_file_name, directory_name) in &lock_file_to_session_dir {
+        debug!("garbage_collect_session_directories() - inspecting: {}",
+                directory_name);
+
+        let timestamp = match extract_timestamp_from_session_dir(directory_name) {
+            Ok(timestamp) => timestamp,
+            Err(()) => {
+                debug!("Found session-dir with malformed timestamp: {}",
+                        crate_directory.join(directory_name).display());
+                // Ignore it
+                continue
+            }
+        };
+
+        if is_finalized(directory_name) {
+            let lock_file_path = crate_directory.join(lock_file_name);
+            match flock::Lock::new(&lock_file_path,
+                                   false,  // don't wait
+                                   false,  // don't create the lock-file
+                                   true) { // get an exclusive lock
+                Ok(lock) => {
+                    debug!("garbage_collect_session_directories() - \
+                            successfully acquired lock");
+                    debug!("garbage_collect_session_directories() - adding \
+                            deletion candidate: {}", directory_name);
+
+                    // Note that we are holding on to the lock
+                    deletion_candidates.push((timestamp,
+                                              crate_directory.join(directory_name),
+                                              Some(lock)));
+                }
+                Err(_) => {
+                    debug!("garbage_collect_session_directories() - \
+                            not collecting, still in use");
+                }
+            }
+        } else if is_old_enough_to_be_collected(timestamp) {
+            // When cleaning out "-working" session directories, i.e.
+            // session directories that might still be in use by another
+            // compiler instance, we only look a directories that are
+            // at least ten seconds old. This is supposed to reduce the
+            // chance of deleting a directory in the time window where
+            // the process has allocated the directory but has not yet
+            // acquired the file-lock on it.
+
+            // Try to acquire the directory lock. If we can't, it
+            // means that the owning process is still alive and we
+            // leave this directory alone.
+            let lock_file_path = crate_directory.join(lock_file_name);
+            match flock::Lock::new(&lock_file_path,
+                                   false,  // don't wait
+                                   false,  // don't create the lock-file
+                                   true) { // get an exclusive lock
+                Ok(lock) => {
+                    debug!("garbage_collect_session_directories() - \
+                            successfully acquired lock");
+
+                    // Note that we are holding on to the lock
+                    definitely_delete.push((crate_directory.join(directory_name),
+                                            Some(lock)));
+                }
+                Err(_) => {
+                    debug!("garbage_collect_session_directories() - \
+                            not collecting, still in use");
+                }
+            }
+        } else {
+            debug!("garbage_collect_session_directories() - not finalized, not \
+                    old enough");
+        }
+    }
+
+    // Delete all but the most recent of the candidates
+    for (path, lock) in all_except_most_recent(deletion_candidates) {
+        debug!("garbage_collect_session_directories() - deleting `{}`",
+                path.display());
+
+        if let Err(err) = safe_remove_dir_all(&path) {
+            sess.warn(&format!("Failed to garbage collect finalized incremental \
+                                compilation session directory `{}`: {}",
+                               path.display(),
+                               err));
+        } else {
+            delete_session_dir_lock_file(sess, &lock_file_path(&path));
+        }
+
+
+        // Let's make it explicit that the file lock is released at this point,
+        // or rather, that we held on to it until here
+        mem::drop(lock);
+    }
+
+    for (path, lock) in definitely_delete {
+        debug!("garbage_collect_session_directories() - deleting `{}`",
+                path.display());
+
+        if let Err(err) = safe_remove_dir_all(&path) {
+            sess.warn(&format!("Failed to garbage collect incremental \
+                                compilation session directory `{}`: {}",
+                               path.display(),
+                               err));
+        } else {
+            delete_session_dir_lock_file(sess, &lock_file_path(&path));
+        }
+
+        // Let's make it explicit that the file lock is released at this point,
+        // or rather, that we held on to it until here
+        mem::drop(lock);
+    }
+
+    Ok(())
+}
+
+fn all_except_most_recent(deletion_candidates: Vec<(SystemTime, PathBuf, Option<flock::Lock>)>)
+                          -> FnvHashMap<PathBuf, Option<flock::Lock>> {
+    let most_recent = deletion_candidates.iter()
+                                         .map(|&(timestamp, _, _)| timestamp)
+                                         .max();
+
+    if let Some(most_recent) = most_recent {
+        deletion_candidates.into_iter()
+                           .filter(|&(timestamp, _, _)| timestamp != most_recent)
+                           .map(|(_, path, lock)| (path, lock))
+                           .collect()
+    } else {
+        FnvHashMap()
+    }
+}
+
+/// Since paths of artifacts within session directories can get quite long, we
+/// need to support deleting files with very long paths. The regular
+/// WinApi functions only support paths up to 260 characters, however. In order
+/// to circumvent this limitation, we canonicalize the path of the directory
+/// before passing it to std::fs::remove_dir_all(). This will convert the path
+/// into the '\\?\' format, which supports much longer paths.
+fn safe_remove_dir_all(p: &Path) -> io::Result<()> {
+    if p.exists() {
+        let canonicalized = try!(p.canonicalize());
+        std_fs::remove_dir_all(canonicalized)
+    } else {
+        Ok(())
+    }
+}
+
+fn safe_remove_file(p: &Path) -> io::Result<()> {
+    if p.exists() {
+        let canonicalized = try!(p.canonicalize());
+        std_fs::remove_file(canonicalized)
+    } else {
+        Ok(())
+    }
+}
+
+#[test]
+fn test_all_except_most_recent() {
+    assert_eq!(all_except_most_recent(
+        vec![
+            (UNIX_EPOCH + Duration::new(4, 0), PathBuf::from("4"), None),
+            (UNIX_EPOCH + Duration::new(1, 0), PathBuf::from("1"), None),
+            (UNIX_EPOCH + Duration::new(5, 0), PathBuf::from("5"), None),
+            (UNIX_EPOCH + Duration::new(3, 0), PathBuf::from("3"), None),
+            (UNIX_EPOCH + Duration::new(2, 0), PathBuf::from("2"), None),
+        ]).keys().cloned().collect::<FnvHashSet<PathBuf>>(),
+        vec![
+            PathBuf::from("1"),
+            PathBuf::from("2"),
+            PathBuf::from("3"),
+            PathBuf::from("4"),
+        ].into_iter().collect::<FnvHashSet<PathBuf>>()
+    );
+
+    assert_eq!(all_except_most_recent(
+        vec![
+        ]).keys().cloned().collect::<FnvHashSet<PathBuf>>(),
+        FnvHashSet()
+    );
+}
+
+#[test]
+fn test_timestamp_serialization() {
+    for i in 0 .. 1_000u64 {
+        let time = UNIX_EPOCH + Duration::new(i * 1_434_578, (i as u32) * 239_000);
+        let s = timestamp_to_string(time);
+        assert_eq!(Ok(time), string_to_timestamp(&s));
+    }
+}
+
+#[test]
+fn test_find_source_directory_in_iter() {
+    let already_visited = FnvHashSet();
+
+    // Find newest
+    assert_eq!(find_source_directory_in_iter(
+        vec![PathBuf::from("crate-dir/s-3234-0000-svh"),
+             PathBuf::from("crate-dir/s-2234-0000-svh"),
+             PathBuf::from("crate-dir/s-1234-0000-svh")].into_iter(), &already_visited),
+        Some(PathBuf::from("crate-dir/s-3234-0000-svh")));
+
+    // Filter out "-working"
+    assert_eq!(find_source_directory_in_iter(
+        vec![PathBuf::from("crate-dir/s-3234-0000-working"),
+             PathBuf::from("crate-dir/s-2234-0000-svh"),
+             PathBuf::from("crate-dir/s-1234-0000-svh")].into_iter(), &already_visited),
+        Some(PathBuf::from("crate-dir/s-2234-0000-svh")));
+
+    // Handle empty
+    assert_eq!(find_source_directory_in_iter(vec![].into_iter(), &already_visited),
+               None);
+
+    // Handle only working
+    assert_eq!(find_source_directory_in_iter(
+        vec![PathBuf::from("crate-dir/s-3234-0000-working"),
+             PathBuf::from("crate-dir/s-2234-0000-working"),
+             PathBuf::from("crate-dir/s-1234-0000-working")].into_iter(), &already_visited),
+        None);
+}
+
+#[test]
+fn test_find_metadata_hashes_iter()
+{
+    assert_eq!(find_metadata_hashes_iter("testsvh2",
+        vec![
+            String::from("s-timestamp1-testsvh1"),
+            String::from("s-timestamp2-testsvh2"),
+            String::from("s-timestamp3-testsvh3"),
+        ].into_iter()),
+        Some(OsString::from("s-timestamp2-testsvh2"))
+    );
+
+    assert_eq!(find_metadata_hashes_iter("testsvh2",
+        vec![
+            String::from("s-timestamp1-testsvh1"),
+            String::from("s-timestamp2-testsvh2"),
+            String::from("invalid-name"),
+        ].into_iter()),
+        Some(OsString::from("s-timestamp2-testsvh2"))
+    );
+
+    assert_eq!(find_metadata_hashes_iter("testsvh2",
+        vec![
+            String::from("s-timestamp1-testsvh1"),
+            String::from("s-timestamp2-testsvh2-working"),
+            String::from("s-timestamp3-testsvh3"),
+        ].into_iter()),
+        None
+    );
+
+    assert_eq!(find_metadata_hashes_iter("testsvh1",
+        vec![
+            String::from("s-timestamp1-random1-working"),
+            String::from("s-timestamp2-random2-working"),
+            String::from("s-timestamp3-random3-working"),
+        ].into_iter()),
+        None
+    );
+
+    assert_eq!(find_metadata_hashes_iter("testsvh2",
+        vec![
+            String::from("timestamp1-testsvh2"),
+            String::from("timestamp2-testsvh2"),
+            String::from("timestamp3-testsvh2"),
+        ].into_iter()),
+        None
+    );
+}
+
+#[test]
+fn test_encode_base_36() {
+    fn test(n: u64) {
+        assert_eq!(Ok(n), u64::from_str_radix(&encode_base_36(n)[..], 36));
+    }
+
+    test(0);
+    test(1);
+    test(35);
+    test(36);
+    test(37);
+    test(u64::max_value());
+
+    for i in 0 .. 1_000 {
+        test(i * 983);
+    }
+}
index 344b05f095457ec4d5e2c6eccce7bf0b31afab94..95bee669d3256151cafdc3ba174f21ec4391e591 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use calculate_svh::SvhCalculate;
 use rbml::Error;
 use rbml::opaque::Decoder;
 use rustc::dep_graph::DepNode;
 use rustc::hir::svh::Svh;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fnv::FnvHashMap;
+use rustc_data_structures::flock;
 use rustc_serialize::Decodable;
 use std::io::{ErrorKind, Read};
 use std::fs::File;
 use syntax::ast;
 
+use IncrementalHashesMap;
 use super::data::*;
-use super::util::*;
+use super::fs::*;
 
 pub struct HashContext<'a, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    incremental_hashes_map: &'a IncrementalHashesMap,
     item_metadata_hashes: FnvHashMap<DefId, u64>,
     crate_hashes: FnvHashMap<ast::CrateNum, Svh>,
 }
 
 impl<'a, 'tcx> HashContext<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+               incremental_hashes_map: &'a IncrementalHashesMap)
+               -> Self {
         HashContext {
             tcx: tcx,
+            incremental_hashes_map: incremental_hashes_map,
             item_metadata_hashes: FnvHashMap(),
             crate_hashes: FnvHashMap(),
         }
@@ -41,17 +46,32 @@ pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
 
     pub fn is_hashable(dep_node: &DepNode<DefId>) -> bool {
         match *dep_node {
+            DepNode::Krate |
             DepNode::Hir(_) => true,
             DepNode::MetaData(def_id) => !def_id.is_local(),
             _ => false,
         }
     }
 
-    pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<(DefId, u64)> {
+    pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<u64> {
         match *dep_node {
+            DepNode::Krate => {
+                Some(self.incremental_hashes_map[dep_node])
+            }
+
             // HIR nodes (which always come from our crate) are an input:
             DepNode::Hir(def_id) => {
-                Some((def_id, self.hir_hash(def_id)))
+                assert!(def_id.is_local(),
+                        "cannot hash HIR for non-local def-id {:?} => {:?}",
+                        def_id,
+                        self.tcx.item_path_str(def_id));
+
+                assert!(!self.tcx.map.is_inlined_def_id(def_id),
+                        "cannot hash HIR for inlined def-id {:?} => {:?}",
+                        def_id,
+                        self.tcx.item_path_str(def_id));
+
+                Some(self.incremental_hashes_map[dep_node])
             }
 
             // MetaData from other crates is an *input* to us.
@@ -59,7 +79,7 @@ pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<(DefId, u64)> {
             // don't hash them, but we do compute a hash for them and
             // save it for others to use.
             DepNode::MetaData(def_id) if !def_id.is_local() => {
-                Some((def_id, self.metadata_hash(def_id)))
+                Some(self.metadata_hash(def_id))
             }
 
             _ => {
@@ -72,21 +92,6 @@ pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<(DefId, u64)> {
         }
     }
 
-    fn hir_hash(&mut self, def_id: DefId) -> u64 {
-        assert!(def_id.is_local(),
-                "cannot hash HIR for non-local def-id {:?} => {:?}",
-                def_id,
-                self.tcx.item_path_str(def_id));
-
-        assert!(!self.tcx.map.is_inlined_def_id(def_id),
-                "cannot hash HIR for inlined def-id {:?} => {:?}",
-                def_id,
-                self.tcx.item_path_str(def_id));
-
-        // FIXME(#32753) -- should we use a distinct hash here
-        self.tcx.calculate_item_hash(def_id)
-    }
-
     fn metadata_hash(&mut self, def_id: DefId) -> u64 {
         debug!("metadata_hash(def_id={:?})", def_id);
 
@@ -124,19 +129,43 @@ fn load_data(&mut self, cnum: ast::CrateNum) {
         debug!("load_data: svh={}", svh);
         assert!(old.is_none(), "loaded data for crate {:?} twice", cnum);
 
-        if let Some(path) = metadata_hash_path(self.tcx, cnum) {
-            debug!("load_data: path={:?}", path);
+        if let Some(session_dir) = find_metadata_hashes_for(self.tcx, cnum) {
+            debug!("load_data: session_dir={:?}", session_dir);
+
+            // Lock the directory we'll be reading  the hashes from.
+            let lock_file_path = lock_file_path(&session_dir);
+            let _lock = match flock::Lock::new(&lock_file_path,
+                                               false,   // don't wait
+                                               false,   // don't create the lock-file
+                                               false) { // shared lock
+                Ok(lock) => lock,
+                Err(err) => {
+                    debug!("Could not acquire lock on `{}` while trying to \
+                            load metadata hashes: {}",
+                            lock_file_path.display(),
+                            err);
+
+                    // Could not acquire the lock. The directory is probably in
+                    // in the process of being deleted. It's OK to just exit
+                    // here. It's the same scenario as if the file had not
+                    // existed in the first place.
+                    return
+                }
+            };
+
+            let hashes_file_path = metadata_hash_import_path(&session_dir);
+
             let mut data = vec![];
             match
-                File::open(&path)
-                .and_then(|mut file| file.read_to_end(&mut data))
+                File::open(&hashes_file_path)
+                     .and_then(|mut file| file.read_to_end(&mut data))
             {
                 Ok(_) => {
-                    match self.load_from_data(cnum, &data) {
+                    match self.load_from_data(cnum, &data, svh) {
                         Ok(()) => { }
                         Err(err) => {
                             bug!("decoding error in dep-graph from `{}`: {}",
-                                 path.display(), err);
+                                 &hashes_file_path.display(), err);
                         }
                     }
                 }
@@ -148,7 +177,7 @@ fn load_data(&mut self, cnum: ast::CrateNum) {
                         _ => {
                             self.tcx.sess.err(
                                 &format!("could not load dep information from `{}`: {}",
-                                         path.display(), err));
+                                         hashes_file_path.display(), err));
                             return;
                         }
                     }
@@ -157,11 +186,22 @@ fn load_data(&mut self, cnum: ast::CrateNum) {
         }
     }
 
-    fn load_from_data(&mut self, cnum: ast::CrateNum, data: &[u8]) -> Result<(), Error> {
+    fn load_from_data(&mut self,
+                      cnum: ast::CrateNum,
+                      data: &[u8],
+                      expected_svh: Svh) -> Result<(), Error> {
         debug!("load_from_data(cnum={})", cnum);
 
         // Load up the hashes for the def-ids from this crate.
         let mut decoder = Decoder::new(data, 0);
+        let svh_in_hashes_file = try!(Svh::decode(&mut decoder));
+
+        if svh_in_hashes_file != expected_svh {
+            // We should not be able to get here. If we do, then
+            // `fs::find_metadata_hashes_for()` has messed up.
+            bug!("mismatch between SVH in crate and SVH in incr. comp. hashes")
+        }
+
         let serialized_hashes = try!(SerializedMetadataHashes::decode(&mut decoder));
         for serialized_hash in serialized_hashes.hashes {
             // the hashes are stored with just a def-index, which is
index c736437df1a9e8b178f36e574bc98e425c128eb8..48f95430f26b6f47c650bb003b07924a0dee6c56 100644 (file)
 use std::fs::{self, File};
 use std::path::{Path};
 
+use IncrementalHashesMap;
 use super::data::*;
 use super::directory::*;
 use super::dirty_clean;
 use super::hash::*;
-use super::util::*;
+use super::fs::*;
 
 pub type DirtyNodes = FnvHashSet<DepNode<DefPathIndex>>;
 
 /// early in compilation, before we've really done any work, but
 /// actually it doesn't matter all that much.) See `README.md` for
 /// more general overview.
-pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                incremental_hashes_map: &IncrementalHashesMap) {
     if tcx.sess.opts.incremental.is_none() {
         return;
     }
 
+    match prepare_session_directory(tcx) {
+        Ok(true) => {
+            // We successfully allocated a session directory and there is
+            // something in it to load, so continue
+        }
+        Ok(false) => {
+            // We successfully allocated a session directory, but there is no
+            // dep-graph data in it to load (because this is the first
+            // compilation session with this incr. comp. dir.)
+            return
+        }
+        Err(()) => {
+            // Something went wrong while trying to allocate the session
+            // directory. Don't try to use it any further.
+            return
+        }
+    }
+
     let _ignore = tcx.dep_graph.in_ignore();
-    load_dep_graph_if_exists(tcx);
+    load_dep_graph_if_exists(tcx, incremental_hashes_map);
 }
 
-fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let dep_graph_path = dep_graph_path(tcx).unwrap();
+fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                      incremental_hashes_map: &IncrementalHashesMap) {
+    let dep_graph_path = dep_graph_path(tcx.sess);
     let dep_graph_data = match load_data(tcx.sess, &dep_graph_path) {
         Some(p) => p,
         None => return // no file
     };
 
-    let work_products_path = tcx_work_products_path(tcx).unwrap();
+    let work_products_path = work_products_path(tcx.sess);
     let work_products_data = match load_data(tcx.sess, &work_products_path) {
         Some(p) => p,
         None => return // no file
     };
 
-    match decode_dep_graph(tcx, &dep_graph_data, &work_products_data) {
+    match decode_dep_graph(tcx, incremental_hashes_map, &dep_graph_data, &work_products_data) {
         Ok(dirty_nodes) => dirty_nodes,
         Err(err) => {
             tcx.sess.warn(
@@ -97,6 +118,7 @@ fn load_data(sess: &Session, path: &Path) -> Option<Vec<u8>> {
 /// Decode the dep graph and load the edges/nodes that are still clean
 /// into `tcx.dep_graph`.
 pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                  incremental_hashes_map: &IncrementalHashesMap,
                                   dep_graph_data: &[u8],
                                   work_products_data: &[u8])
                                   -> Result<(), Error>
@@ -133,7 +155,10 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // reason for this is that this way we can include nodes that have
     // been removed (which no longer have a `DefId` in the current
     // compilation).
-    let dirty_raw_source_nodes = dirty_nodes(tcx, &serialized_dep_graph.hashes, &retraced);
+    let dirty_raw_source_nodes = dirty_nodes(tcx,
+                                             incremental_hashes_map,
+                                             &serialized_dep_graph.hashes,
+                                             &retraced);
 
     // Create a list of (raw-source-node ->
     // retracted-target-node) edges. In the process of retracing the
@@ -206,15 +231,16 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 /// Computes which of the original set of def-ids are dirty. Stored in
 /// a bit vector where the index is the DefPathIndex.
 fn dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                         hashes: &[SerializedHash],
+                         incremental_hashes_map: &IncrementalHashesMap,
+                         serialized_hashes: &[SerializedHash],
                          retraced: &RetracedDefIdDirectory)
                          -> DirtyNodes {
-    let mut hcx = HashContext::new(tcx);
+    let mut hcx = HashContext::new(tcx, incremental_hashes_map);
     let mut dirty_nodes = FnvHashSet();
 
-    for hash in hashes {
+    for hash in serialized_hashes {
         if let Some(dep_node) = retraced.map(&hash.dep_node) {
-            let (_, current_hash) = hcx.hash(&dep_node).unwrap();
+            let current_hash = hcx.hash(&dep_node).unwrap();
             if current_hash == hash.hash {
                 continue;
             }
@@ -250,7 +276,7 @@ fn reconcile_work_products<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                    .saved_files
                    .iter()
                    .all(|&(_, ref file_name)| {
-                       let path = in_incr_comp_dir(tcx.sess, &file_name).unwrap();
+                       let path = in_incr_comp_dir_sess(tcx.sess, &file_name);
                        path.exists()
                    });
             if all_files_exist {
@@ -268,7 +294,7 @@ fn delete_dirty_work_product(tcx: TyCtxt,
                              swp: SerializedWorkProduct) {
     debug!("delete_dirty_work_product({:?})", swp);
     for &(_, ref file_name) in &swp.work_product.saved_files {
-        let path = in_incr_comp_dir(tcx.sess, file_name).unwrap();
+        let path = in_incr_comp_dir_sess(tcx.sess, file_name);
         match fs::remove_file(&path) {
             Ok(()) => { }
             Err(err) => {
index 4a042497e044114c3d3421ff777cfa906826f548..ba0f71971bb45e9afce432e341843b41d164816c 100644 (file)
 mod data;
 mod directory;
 mod dirty_clean;
+mod fs;
 mod hash;
 mod load;
 mod preds;
 mod save;
-mod util;
 mod work_product;
 
+pub use self::fs::finalize_session_directory;
+pub use self::fs::in_incr_comp_dir;
 pub use self::load::load_dep_graph;
 pub use self::save::save_dep_graph;
 pub use self::save::save_work_products;
 pub use self::work_product::save_trans_partition;
-pub use self::util::in_incr_comp_dir;
index a82951afcb1efc8c4858052152acd075b745cb22..af13484e4288d54174ee0763d4beb44717cebd27 100644 (file)
@@ -62,7 +62,7 @@ pub fn new(query: &'q DepGraphQuery<DefId>, hcx: &mut HashContext) -> Self {
         let mut hashes = FnvHashMap();
         for input in inputs.values().flat_map(|v| v.iter().cloned()) {
             hashes.entry(input)
-                  .or_insert_with(|| hcx.hash(input).unwrap().1);
+                  .or_insert_with(|| hcx.hash(input).unwrap());
         }
 
         Predecessors {
index a9523a81fbaf7b9da78a0f11056fde88b61677bb..d31252be5e857295bce2ea16ffb321148e009c66 100644 (file)
@@ -11,7 +11,7 @@
 use rbml::opaque::Encoder;
 use rustc::dep_graph::DepNode;
 use rustc::hir::def_id::DefId;
-use rustc::middle::cstore::LOCAL_CRATE;
+use rustc::hir::svh::Svh;
 use rustc::session::Session;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fnv::FnvHashMap;
 use std::fs::{self, File};
 use std::path::PathBuf;
 
+use IncrementalHashesMap;
 use super::data::*;
 use super::directory::*;
 use super::hash::*;
 use super::preds::*;
-use super::util::*;
+use super::fs::*;
 
-pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                incremental_hashes_map: &IncrementalHashesMap,
+                                svh: Svh) {
     debug!("save_dep_graph()");
     let _ignore = tcx.dep_graph.in_ignore();
     let sess = tcx.sess;
     if sess.opts.incremental.is_none() {
         return;
     }
-    let mut hcx = HashContext::new(tcx);
+    let mut hcx = HashContext::new(tcx, incremental_hashes_map);
     let mut builder = DefIdDirectoryBuilder::new(tcx);
     let query = tcx.dep_graph.query();
     let preds = Predecessors::new(&query, &mut hcx);
     save_in(sess,
-            dep_graph_path(tcx),
+            dep_graph_path(sess),
             |e| encode_dep_graph(&preds, &mut builder, e));
     save_in(sess,
-            metadata_hash_path(tcx, LOCAL_CRATE),
-            |e| encode_metadata_hashes(tcx, &preds, &mut builder, e));
+            metadata_hash_export_path(sess),
+            |e| encode_metadata_hashes(tcx, svh, &preds, &mut builder, e));
 }
 
-pub fn save_work_products(sess: &Session, local_crate_name: &str) {
+pub fn save_work_products(sess: &Session) {
+    if sess.opts.incremental.is_none() {
+        return;
+    }
+
     debug!("save_work_products()");
     let _ignore = sess.dep_graph.in_ignore();
-    let path = sess_work_products_path(sess, local_crate_name);
+    let path = work_products_path(sess);
     save_in(sess, path, |e| encode_work_products(sess, e));
 }
 
-fn save_in<F>(sess: &Session, opt_path_buf: Option<PathBuf>, encode: F)
+fn save_in<F>(sess: &Session, path_buf: PathBuf, encode: F)
     where F: FnOnce(&mut Encoder) -> io::Result<()>
 {
-    let path_buf = match opt_path_buf {
-        Some(p) => p,
-        None => return,
-    };
-
-    // FIXME(#32754) lock file?
-
     // delete the old dep-graph, if any
+    // Note: It's important that we actually delete the old file and not just
+    // truncate and overwrite it, since it might be a shared hard-link, the
+    // underlying data of which we don't want to modify
     if path_buf.exists() {
         match fs::remove_file(&path_buf) {
             Ok(()) => {}
@@ -153,6 +156,7 @@ pub fn encode_dep_graph(preds: &Predecessors,
 }
 
 pub fn encode_metadata_hashes(tcx: TyCtxt,
+                              svh: Svh,
                               preds: &Predecessors,
                               builder: &mut DefIdDirectoryBuilder,
                               encoder: &mut Encoder)
@@ -218,6 +222,7 @@ pub fn encode_metadata_hashes(tcx: TyCtxt,
     }
 
     // Encode everything.
+    try!(svh.encode(encoder));
     try!(serialized_hashes.encode(encoder));
 
     Ok(())
diff --git a/src/librustc_incremental/persist/util.rs b/src/librustc_incremental/persist/util.rs
deleted file mode 100644 (file)
index f1e81fd..0000000
+++ /dev/null
@@ -1,95 +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.
-
-use rustc::middle::cstore::LOCAL_CRATE;
-use rustc::session::Session;
-use rustc::ty::TyCtxt;
-
-use std::fs;
-use std::io;
-use std::path::{Path, PathBuf};
-use syntax::ast;
-
-pub fn dep_graph_path(tcx: TyCtxt) -> Option<PathBuf> {
-    tcx_path(tcx, LOCAL_CRATE, "local")
-}
-
-pub fn metadata_hash_path(tcx: TyCtxt, cnum: ast::CrateNum) -> Option<PathBuf> {
-    tcx_path(tcx, cnum, "metadata")
-}
-
-pub fn tcx_work_products_path(tcx: TyCtxt) -> Option<PathBuf> {
-    let crate_name = tcx.crate_name(LOCAL_CRATE);
-    sess_work_products_path(tcx.sess, &crate_name)
-}
-
-pub fn sess_work_products_path(sess: &Session,
-                               local_crate_name: &str)
-                               -> Option<PathBuf> {
-    let crate_disambiguator = sess.local_crate_disambiguator();
-    path(sess, local_crate_name, &crate_disambiguator, "work-products")
-}
-
-pub fn in_incr_comp_dir(sess: &Session, file_name: &str) -> Option<PathBuf> {
-    sess.opts.incremental.as_ref().map(|incr_dir| incr_dir.join(file_name))
-}
-
-fn tcx_path(tcx: TyCtxt,
-            cnum: ast::CrateNum,
-            middle: &str)
-            -> Option<PathBuf> {
-    path(tcx.sess, &tcx.crate_name(cnum), &tcx.crate_disambiguator(cnum), middle)
-}
-
-fn path(sess: &Session,
-        crate_name: &str,
-        crate_disambiguator: &str,
-        middle: &str)
-        -> Option<PathBuf> {
-    // For now, just save/load dep-graph from
-    // directory/dep_graph.rbml
-    sess.opts.incremental.as_ref().and_then(|incr_dir| {
-        match create_dir_racy(&incr_dir) {
-            Ok(()) => {}
-            Err(err) => {
-                sess.err(
-                    &format!("could not create the directory `{}`: {}",
-                             incr_dir.display(), err));
-                return None;
-            }
-        }
-
-        let file_name = format!("{}-{}.{}.bin", crate_name, crate_disambiguator, middle);
-
-        Some(incr_dir.join(file_name))
-    })
-}
-
-// Like std::fs::create_dir_all, except handles concurrent calls among multiple
-// threads or processes.
-fn create_dir_racy(path: &Path) -> io::Result<()> {
-    match fs::create_dir(path) {
-        Ok(()) => return Ok(()),
-        Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(()),
-        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
-        Err(e) => return Err(e),
-    }
-    match path.parent() {
-        Some(p) => try!(create_dir_racy(p)),
-        None => return Err(io::Error::new(io::ErrorKind::Other,
-                                          "failed to create whole tree")),
-    }
-    match fs::create_dir(path) {
-        Ok(()) => Ok(()),
-        Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()),
-        Err(e) => Err(e),
-    }
-}
-
index c106ea8f262691ec83cfe693efaaadc6663734c2..a9ebd27ce9928fc22eec587d5420de8cf38745b1 100644 (file)
@@ -10,7 +10,7 @@
 
 //! This module contains files for saving intermediate work-products.
 
-use persist::util::*;
+use persist::fs::*;
 use rustc::dep_graph::{WorkProduct, WorkProductId};
 use rustc::session::Session;
 use rustc::session::config::OutputType;
@@ -35,7 +35,7 @@ pub fn save_trans_partition(sess: &Session,
         files.iter()
              .map(|&(kind, ref path)| {
                  let file_name = format!("cgu-{}.{}", cgu_name, kind.extension());
-                 let path_in_incr_dir = in_incr_comp_dir(sess, &file_name).unwrap();
+                 let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
                  match link_or_copy(path, &path_in_incr_dir) {
                      Ok(_) => Some((kind, file_name)),
                      Err(err) => {
index 15914838acf0db85289b97ececd3fa5c90696a4b..0e130c3bb66bfb823c88f127a214b54722f04a3c 100644 (file)
@@ -14,7 +14,7 @@
 use lint::{LintPass, LateLintPass};
 
 use syntax::ast;
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::attr;
 use syntax_pos::Span;
 
 use rustc::hir::{self, PatKind};
index 61d927239828b2124894debb7581181f9834cff7..a103386e2c9809c89c8853fda70d6d832540f476 100644 (file)
@@ -44,8 +44,8 @@
 use std::collections::HashSet;
 
 use syntax::{ast};
-use syntax::attr::{self, AttrMetaMethods, AttributeMethods};
-use syntax_pos::{self, Span};
+use syntax::attr;
+use syntax_pos::{Span};
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::intravisit::FnKind;
@@ -317,7 +317,7 @@ fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) {
         let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| {
             attr.check_name("doc") && match attr.meta_item_list() {
                 None => false,
-                Some(l) => attr::contains_name(&l[..], "hidden"),
+                Some(l) => attr::list_contains_name(&l[..], "hidden"),
             }
         });
         self.doc_hidden_stack.push(doc_hidden);
@@ -1145,7 +1145,7 @@ fn get_lints(&self) -> LintArray {
 
 impl LateLintPass for UnstableFeatures {
     fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) {
-        if attr::contains_name(&[attr.meta().clone()], "feature") {
+        if attr.meta().check_name("feature") {
             if let Some(items) = attr.meta().meta_item_list() {
                 for item in items {
                     ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature");
@@ -1154,56 +1154,3 @@ fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) {
         }
     }
 }
-
-/// Lints for attempts to impl Drop on types that have `#[repr(C)]`
-/// attribute (see issue #24585).
-#[derive(Copy, Clone)]
-pub struct DropWithReprExtern;
-
-declare_lint! {
-    DROP_WITH_REPR_EXTERN,
-    Warn,
-    "use of #[repr(C)] on a type that implements Drop"
-}
-
-impl LintPass for DropWithReprExtern {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(DROP_WITH_REPR_EXTERN)
-    }
-}
-
-impl LateLintPass for DropWithReprExtern {
-    fn check_crate(&mut self, ctx: &LateContext, _: &hir::Crate) {
-        let drop_trait = match ctx.tcx.lang_items.drop_trait() {
-            Some(id) => ctx.tcx.lookup_trait_def(id), None => { return }
-        };
-        drop_trait.for_each_impl(ctx.tcx, |drop_impl_did| {
-            if !drop_impl_did.is_local() {
-                return;
-            }
-            let dtor_self_type = ctx.tcx.lookup_item_type(drop_impl_did).ty;
-
-            match dtor_self_type.sty {
-                ty::TyEnum(self_type_def, _) |
-                ty::TyStruct(self_type_def, _) => {
-                    let self_type_did = self_type_def.did;
-                    let hints = ctx.tcx.lookup_repr_hints(self_type_did);
-                    if hints.iter().any(|attr| *attr == attr::ReprExtern) &&
-                        self_type_def.dtor_kind().has_drop_flag() {
-                        let drop_impl_span = ctx.tcx.map.def_id_span(drop_impl_did,
-                                                                     syntax_pos::DUMMY_SP);
-                        let self_defn_span = ctx.tcx.map.def_id_span(self_type_did,
-                                                                     syntax_pos::DUMMY_SP);
-                        ctx.span_lint_note(DROP_WITH_REPR_EXTERN,
-                                           drop_impl_span,
-                                           "implementing Drop adds hidden state to types, \
-                                            possibly conflicting with `#[repr(C)]`",
-                                            self_defn_span,
-                                            "the `#[repr(C)]` attribute is attached here");
-                    }
-                }
-                _ => {}
-            }
-        })
-    }
-}
index cb0036eb5b034fdefb5593defa8762ad31259cf5..0f0e9cfb3577335923d3bd0c38334815fe5beada 100644 (file)
@@ -127,7 +127,6 @@ macro_rules! add_lint_group {
                  UnconditionalRecursion,
                  InvalidNoMangleItems,
                  PluginAsLibrary,
-                 DropWithReprExtern,
                  MutableTransmutes,
                  );
 
@@ -192,14 +191,6 @@ macro_rules! add_lint_group {
             id: LintId::of(ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN),
             reference: "RFC 1445 <https://github.com/rust-lang/rfcs/pull/1445>",
         },
-        FutureIncompatibleInfo {
-            id: LintId::of(UNSIZED_IN_TUPLE),
-            reference: "issue #33242 <https://github.com/rust-lang/rust/issues/33242>",
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(OBJECT_UNSAFE_FRAGMENT),
-            reference: "issue #33243 <https://github.com/rust-lang/rust/issues/33243>",
-        },
         FutureIncompatibleInfo {
             id: LintId::of(HR_LIFETIME_IN_ASSOC_TYPE),
             reference: "issue #33685 <https://github.com/rust-lang/rust/issues/33685>",
@@ -218,4 +209,5 @@ macro_rules! add_lint_group {
     // This was renamed to raw_pointer_derive, which was then removed,
     // so it is also considered removed
     store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok");
+    store.register_removed("drop_with_repr_extern", "drop flags have been removed");
 }
index 99df5c6e5f95e591b7592d807862781e3f9a2974..40e78c007ccfd652ed9d53eae876f05b10767fc4 100644 (file)
@@ -56,7 +56,6 @@
 let y: usize = 1.wrapping_neg();
 assert_eq!(x, y);
 ```
-
 "##
 }
 
@@ -692,7 +691,7 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
         if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
             if gens.ty_params.is_empty() {  // sizes only make sense for non-generic types
                 let t = cx.tcx.node_id_to_type(it.id);
-                let layout = cx.tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
+                let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
                     let ty = cx.tcx.erase_regions(&t);
                     ty.layout(&infcx).unwrap_or_else(|e| {
                         bug!("failed to get layout for `{}`: {}", t, e)
index 57705301aab4e55b27a5edb884c7ad1d9d2e0f5e..924b768958d69433ea1867930a0ea8189a2ada43 100644 (file)
@@ -18,8 +18,9 @@
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 
 use syntax::ast;
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::attr;
 use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType};
+use syntax::parse::token::keywords;
 use syntax::ptr::P;
 use syntax_pos::Span;
 
@@ -234,10 +235,13 @@ fn get_lints(&self) -> LintArray {
 
 impl LateLintPass for UnusedAttributes {
     fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
+        debug!("checking attribute: {:?}", attr);
+
         // Note that check_name() marks the attribute as used if it matches.
         for &(ref name, ty, _) in KNOWN_ATTRIBUTES {
             match ty {
                 AttributeType::Whitelisted if attr.check_name(name) => {
+                    debug!("{:?} is Whitelisted", name);
                     break;
                 },
                 _ => ()
@@ -247,11 +251,13 @@ fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
         let plugin_attributes = cx.sess().plugin_attributes.borrow_mut();
         for &(ref name, ty) in plugin_attributes.iter() {
             if ty == AttributeType::Whitelisted && attr.check_name(&name) {
+                debug!("{:?} (plugin attr) is whitelisted with ty {:?}", name, ty);
                 break;
             }
         }
 
         if !attr::is_used(attr) {
+            debug!("Emitting warning for: {:?}", attr);
             cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
             // Is it a builtin attribute that must be used at the crate level?
             let known_crate = KNOWN_ATTRIBUTES.iter().find(|&&(name, ty, _)| {
@@ -275,6 +281,8 @@ fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
                 };
                 cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg);
             }
+        } else {
+            debug!("Attr was used: {:?}", attr);
         }
     }
 }
@@ -392,13 +400,9 @@ impl LateLintPass for UnusedImportBraces {
     fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
         if let hir::ItemUse(ref view_path) = item.node {
             if let hir::ViewPathList(_, ref items) = view_path.node {
-                if items.len() == 1 {
-                    if let hir::PathListIdent {ref name, ..} = items[0].node {
-                        let m = format!("braces around {} is unnecessary",
-                                        name);
-                        cx.span_lint(UNUSED_IMPORT_BRACES, item.span,
-                                     &m[..]);
-                    }
+                if items.len() == 1 && items[0].node.name != keywords::SelfValue.name() {
+                    let msg = format!("braces around {} is unnecessary", items[0].node.name);
+                    cx.span_lint(UNUSED_IMPORT_BRACES, item.span, &msg);
                 }
             }
         }
index 5f7a0f788ca1289e8da69b9e001289622041af8b..ac83d860b6e90a52cc6cd0bd662c37359aa8c0af 100644 (file)
@@ -66,7 +66,7 @@ fn main() {
     let host = env::var("HOST").unwrap();
     let is_crossed = target != host;
 
-    let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl"];
+    let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz"];
 
     // FIXME: surely we don't need all these components, right? Stuff like mcjit
     //        or interpreter the compiler itself never uses.
index b2ffcac365bad34760351052003f8411d7265fb0..92fe568a72c578f553fc65e4b0299ce051fba5be 100644 (file)
@@ -42,6 +42,7 @@ pub enum CallConv {
     ColdCallConv = 9,
     X86StdcallCallConv = 64,
     X86FastcallCallConv = 65,
+    X86_64_SysV = 78,
     X86_64_Win64 = 79,
     X86_VectorCall = 80
 }
@@ -1796,6 +1797,11 @@ pub fn LLVMRustDIBuilderCreateLexicalBlock(Builder: DIBuilderRef,
                                                Col: c_uint)
                                                -> DILexicalBlock;
 
+    pub fn LLVMRustDIBuilderCreateLexicalBlockFile(Builder: DIBuilderRef,
+                                                   Scope: DIScope,
+                                                   File: DIFile)
+                                                   -> DILexicalBlock;
+
     pub fn LLVMRustDIBuilderCreateStaticVariable(Builder: DIBuilderRef,
                                                  Context: DIScope,
                                                  Name: *const c_char,
index 6c4e1a54ea7281b4ff3d0ae55f9c3ac7c9337e76..eb45d3d25c5c05f5ff71a713d57c039626cac426 100644 (file)
@@ -428,6 +428,12 @@ fn init() { }
                  LLVMInitializePNaClTargetInfo,
                  LLVMInitializePNaClTarget,
                  LLVMInitializePNaClTargetMC);
+    init_target!(llvm_component = "systemz",
+                 LLVMInitializeSystemZTargetInfo,
+                 LLVMInitializeSystemZTarget,
+                 LLVMInitializeSystemZTargetMC,
+                 LLVMInitializeSystemZAsmPrinter,
+                 LLVMInitializeSystemZAsmParser);
 }
 
 pub fn last_error() -> Option<String> {
index 1ef48e6d6565fcc1c43f0570f5d3ba75bc1cefe4..0236f9c413ddc26e47662090196bda23a3ef9c57 100644 (file)
@@ -79,7 +79,6 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext,
                            ii: InlinedItemRef) {
     let id = match ii {
         InlinedItemRef::Item(_, i) => i.id,
-        InlinedItemRef::Foreign(_, i) => i.id,
         InlinedItemRef::TraitItem(_, ti) => ti.id,
         InlinedItemRef::ImplItem(_, ii) => ii.id,
     };
@@ -147,7 +146,6 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::CrateMetadata,
                                        dcx);
     let name = match *ii {
         InlinedItem::Item(_, ref i) => i.name,
-        InlinedItem::Foreign(_, ref i) => i.name,
         InlinedItem::TraitItem(_, ref ti) => ti.name,
         InlinedItem::ImplItem(_, ref ii) => ii.name
     };
@@ -357,9 +355,6 @@ fn simplify_ast(ii: InlinedItemRef) -> (InlinedItem, IdRange) {
         InlinedItemRef::ImplItem(d, ii) => {
             InlinedItem::ImplItem(d, P(fold::noop_fold_impl_item(ii.clone(), &mut fld)))
         }
-        InlinedItemRef::Foreign(d, i) => {
-            InlinedItem::Foreign(d, P(fold::noop_fold_foreign_item(i.clone(), &mut fld)))
-        }
     };
 
     (ii, fld.id_range)
@@ -522,7 +517,7 @@ pub fn encode_cast_kind(ebml_w: &mut Encoder, kind: cast::CastKind) {
 // Encoding and decoding the side tables
 
 trait rbml_writer_helpers<'tcx> {
-    fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region);
+    fn emit_region(&mut self, ecx: &e::EncodeContext, r: &'tcx ty::Region);
     fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>);
     fn emit_substs<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
                        substs: &Substs<'tcx>);
@@ -536,7 +531,7 @@ fn emit_auto_deref_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
 }
 
 impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
-    fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region) {
+    fn emit_region(&mut self, ecx: &e::EncodeContext, r: &'tcx ty::Region) {
         self.emit_opaque(|this| Ok(tyencode::enc_region(&mut this.cursor,
                                                         &ecx.ty_str_ctxt(),
                                                         r)));
@@ -622,7 +617,7 @@ fn emit_autoref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
                 &adjustment::AutoPtr(r, m) => {
                     this.emit_enum_variant("AutoPtr", 0, 2, |this| {
                         this.emit_enum_variant_arg(0,
-                            |this| Ok(this.emit_region(ecx, *r)));
+                            |this| Ok(this.emit_region(ecx, r)));
                         this.emit_enum_variant_arg(1, |this| m.encode(this))
                     })
                 }
@@ -829,7 +824,7 @@ fn read_ty_encoded<'a, 'b, F, R>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>,
                                      f: F) -> R
         where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x, 'tcx>) -> R;
 
-    fn read_region(&mut self, dcx: &DecodeContext) -> ty::Region;
+    fn read_region<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> &'tcx ty::Region;
     fn read_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Ty<'tcx>;
     fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec<Ty<'tcx>>;
     fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
@@ -840,8 +835,8 @@ fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
                               -> ty::Predicate<'tcx>;
     fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
                            -> &'tcx Substs<'tcx>;
-    fn read_upvar_capture(&mut self, dcx: &DecodeContext)
-                          -> ty::UpvarCapture;
+    fn read_upvar_capture<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
+                                  -> ty::UpvarCapture<'tcx>;
     fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
                                     -> adjustment::AutoAdjustment<'tcx>;
     fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
@@ -913,7 +908,7 @@ fn type_string(doc: rbml::Doc) -> String {
             str
         }
     }
-    fn read_region(&mut self, dcx: &DecodeContext) -> ty::Region {
+    fn read_region<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> &'tcx ty::Region {
         // Note: regions types embed local node ids.  In principle, we
         // should translate these node ids into the new decode
         // context.  However, we do not bother, because region types
@@ -953,7 +948,8 @@ fn read_substs<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
                .parse_substs())
         }).unwrap()
     }
-    fn read_upvar_capture(&mut self, dcx: &DecodeContext) -> ty::UpvarCapture {
+    fn read_upvar_capture<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
+                                  -> ty::UpvarCapture<'tcx> {
         self.read_enum("UpvarCapture", |this| {
             let variants = ["ByValue", "ByRef"];
             this.read_enum_variant(&variants, |this, i| {
@@ -1037,7 +1033,7 @@ fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
             this.read_enum_variant(&variants, |this, i| {
                 Ok(match i {
                     0 => {
-                        let r: ty::Region =
+                        let r: &'tcx ty::Region =
                             this.read_enum_variant_arg(0, |this| {
                                 Ok(this.read_region(dcx))
                             }).unwrap();
@@ -1046,7 +1042,7 @@ fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
                                 Decodable::decode(this)
                             }).unwrap();
 
-                        adjustment::AutoPtr(dcx.tcx.mk_region(r), m)
+                        adjustment::AutoPtr(r, m)
                     }
                     1 => {
                         let m: hir::Mutability =
@@ -1208,8 +1204,7 @@ fn copy_item_type(dcx: &DecodeContext,
     let item_node_id = match ii {
         &InlinedItem::Item(_, ref i) => i.id,
         &InlinedItem::TraitItem(_, ref ti) => ti.id,
-        &InlinedItem::ImplItem(_, ref ii) => ii.id,
-        &InlinedItem::Foreign(_, ref fi) => fi.id
+        &InlinedItem::ImplItem(_, ref ii) => ii.id
     };
     copy_item_type(dcx, item_node_id, orig_did);
 
index 99a3f3b00c8b0f4ca4824c8c457595a9a629b2d5..85cf41e42a2737194e583093c55dd389970e0561 100644 (file)
 pub const tag_items_closure_ty: usize = 0x2b;
 pub const tag_def_key: usize = 0x2c;
 
-// GAP 0x2d 0x2e
+// GAP 0x2d 0x34
 
 pub const tag_index: usize = 0x110; // top-level only
 pub const tag_xref_index: usize = 0x111; // top-level only
 pub const tag_xref_data: usize = 0x112; // top-level only
-
-pub const tag_meta_item_name_value: usize = 0x2f;
-
-pub const tag_meta_item_name: usize = 0x30;
-
-pub const tag_meta_item_value: usize = 0x31;
-
 pub const tag_attributes: usize = 0x101; // top-level only
 
-pub const tag_attribute: usize = 0x32;
-
-pub const tag_meta_item_word: usize = 0x33;
-
-pub const tag_meta_item_list: usize = 0x34;
-
 // The list of crates that this crate depends on
 pub const tag_crate_deps: usize = 0x102; // top-level only
 
index 4a656b180f259edc3bd05a49dd4e36f304e71327..7e1f3ea618c979f597a3f17128ad4aabfd565e74 100644 (file)
@@ -36,7 +36,6 @@
 use syntax::codemap;
 use syntax::parse;
 use syntax::attr;
-use syntax::attr::AttrMetaMethods;
 use syntax::parse::token::InternedString;
 use syntax::visit;
 use syntax_pos::{self, Span, mk_sp, Pos};
@@ -101,8 +100,10 @@ fn register_native_lib(sess: &Session,
     if name.is_empty() {
         match span {
             Some(span) => {
-                span_err!(sess, span, E0454,
-                          "#[link(name = \"\")] given with empty name");
+                struct_span_err!(sess, span, E0454,
+                                 "#[link(name = \"\")] given with empty name")
+                    .span_label(span, &format!("empty name given"))
+                    .emit();
             }
             None => {
                 sess.err("empty library name given via `-l`");
index f6d698eb969d80baa919273315ecda8a27289077..0fd7b683067b7441798446c8b5ad19c25c2c4307 100644 (file)
@@ -73,7 +73,7 @@ fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::Clos
         decoder::closure_ty(&cdata, def_id.index, tcx)
     }
 
-    fn item_variances(&self, def: DefId) -> ty::ItemVariances {
+    fn item_variances(&self, def: DefId) -> Vec<ty::Variance> {
         self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_item_variances(&cdata, def.index)
@@ -291,13 +291,6 @@ fn is_foreign_item(&self, did: DefId) -> bool {
         decoder::is_foreign_item(&cdata, did.index)
     }
 
-    fn is_static_method(&self, def: DefId) -> bool
-    {
-        self.dep_graph.read(DepNode::MetaData(def));
-        let cdata = self.get_crate_data(def.krate);
-        decoder::is_static_method(&cdata, def.index)
-    }
-
     fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool
     {
         self.do_is_statically_included_foreign_item(id)
@@ -562,11 +555,6 @@ fn maybe_get_item_ast<'a>(&'tcx self,
                 let inlined_root_node_id = find_inlined_item_root(item.id);
                 cache_inlined_item(def_id, item.id, inlined_root_node_id);
             }
-            decoder::FoundAst::Found(&InlinedItem::Foreign(d, ref item)) => {
-                assert_eq!(d, def_id);
-                let inlined_root_node_id = find_inlined_item_root(item.id);
-                cache_inlined_item(def_id, item.id, inlined_root_node_id);
-            }
             decoder::FoundAst::FoundParent(parent_did, item) => {
                 let inlined_root_node_id = find_inlined_item_root(item.id);
                 cache_inlined_item(parent_did, item.id, inlined_root_node_id);
index 5488f114db32ff610576f227ed063a70bdda421a..7117cdb731cf37ead26f56676ac61bd8854d43a0 100644 (file)
@@ -42,6 +42,7 @@
 
 use rustc::mir;
 use rustc::mir::visit::MutVisitor;
+use rustc::mir::repr::Location;
 
 use std::cell::Cell;
 use std::io;
@@ -56,7 +57,6 @@
 use syntax::ast;
 use syntax::codemap;
 use syntax::print::pprust;
-use syntax::ptr::P;
 use syntax_pos::{self, Span, BytePos, NO_EXPANSION};
 
 pub type Cmd<'a> = &'a CrateMetadata;
@@ -86,7 +86,7 @@ pub fn load_index(data: &[u8]) -> index::Index {
 
 pub fn crate_rustc_version(data: &[u8]) -> Option<String> {
     let doc = rbml::Doc::new(data);
-    reader::maybe_get_doc(doc, tag_rustc_version).map(|s| s.as_str())
+    reader::maybe_get_doc(doc, tag_rustc_version).map(|s| s.to_string())
 }
 
 pub fn load_xrefs(data: &[u8]) -> index::DenseIndex {
@@ -207,7 +207,7 @@ fn item_defaultness(item: rbml::Doc) -> hir::Defaultness {
 
 fn item_sort(item: rbml::Doc) -> Option<char> {
     reader::tagged_docs(item, tag_item_trait_item_sort).nth(0).map(|doc| {
-        doc.as_str_slice().as_bytes()[0] as char
+        doc.as_str().as_bytes()[0] as char
     })
 }
 
@@ -240,11 +240,10 @@ fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> {
     reader::tagged_docs(d, tag_items_data_item_reexport)
 }
 
-fn variant_disr_val(d: rbml::Doc) -> Option<u64> {
-    reader::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| {
-        reader::with_doc_data(val_doc, |data| {
-            str::from_utf8(data).ok().and_then(|s| s.parse().ok())
-        })
+fn variant_disr_val(d: rbml::Doc) -> u64 {
+    let val_doc = reader::get_doc(d, tag_disr_val);
+    reader::with_doc_data(val_doc, |data| {
+        str::from_utf8(data).unwrap().parse().unwrap()
     })
 }
 
@@ -283,7 +282,7 @@ fn item_name(item: rbml::Doc) -> ast::Name {
 
 fn maybe_item_name(item: rbml::Doc) -> Option<ast::Name> {
     reader::maybe_get_doc(item, tag_paths_data_name).map(|name| {
-        let string = name.as_str_slice();
+        let string = name.as_str();
         token::intern(string)
     })
 }
@@ -369,7 +368,7 @@ fn parse_polarity(item_doc: rbml::Doc) -> hir::ImplPolarity {
 fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec<ast::Name> {
     let names_doc = reader::get_doc(item_doc, tag_associated_type_names);
     reader::tagged_docs(names_doc, tag_associated_type_name)
-        .map(|name_doc| token::intern(name_doc.as_str_slice()))
+        .map(|name_doc| token::intern(name_doc.as_str()))
         .collect()
 }
 
@@ -402,17 +401,10 @@ fn expect_variant_kind(family: Family) -> ty::VariantKind {
         }
     }
     fn get_enum_variants<'tcx>(cdata: Cmd, doc: rbml::Doc) -> Vec<ty::VariantDefData<'tcx, 'tcx>> {
-        let mut disr_val = 0;
         reader::tagged_docs(doc, tag_items_data_item_variant).map(|p| {
             let did = translated_def_id(cdata, p);
             let item = cdata.lookup_item(did.index);
-
-            if let Some(disr) = variant_disr_val(item) {
-                disr_val = disr;
-            }
-            let disr = disr_val;
-            disr_val = disr_val.wrapping_add(1);
-
+            let disr = variant_disr_val(item);
             ty::VariantDefData {
                 did: did,
                 name: item_name(item),
@@ -690,7 +682,7 @@ fn each_child_of_item_or_crate<F, G>(cdata: Cmd,
 
         let name_doc = reader::get_doc(reexport_doc,
                                        tag_items_data_item_reexport_name);
-        let name = name_doc.as_str_slice();
+        let name = name_doc.as_str();
 
         // This reexport may be in yet another crate.
         let crate_data = if child_def_id.krate == cdata.cnum {
@@ -854,7 +846,7 @@ struct MirDefIdAndSpanTranslator<'cdata, 'codemap> {
     impl<'v, 'cdata, 'codemap> mir::visit::MutVisitor<'v>
         for MirDefIdAndSpanTranslator<'cdata, 'codemap>
     {
-        fn visit_def_id(&mut self, def_id: &mut DefId) {
+        fn visit_def_id(&mut self, def_id: &mut DefId, _: Location) {
             *def_id = translate_def_id(self.crate_metadata, *def_id);
         }
 
@@ -867,7 +859,8 @@ fn visit_span(&mut self, span: &mut Span) {
     }
 }
 
-fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory {
+fn get_explicit_self<'a, 'tcx>(item: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                               -> ty::ExplicitSelfCategory<'tcx> {
     fn get_mutability(ch: u8) -> hir::Mutability {
         match ch as char {
             'i' => hir::MutImmutable,
@@ -877,7 +870,7 @@ fn get_mutability(ch: u8) -> hir::Mutability {
     }
 
     let explicit_self_doc = reader::get_doc(item, tag_item_trait_method_explicit_self);
-    let string = explicit_self_doc.as_str_slice();
+    let string = explicit_self_doc.as_str();
 
     let explicit_self_kind = string.as_bytes()[0];
     match explicit_self_kind as char {
@@ -887,7 +880,7 @@ fn get_mutability(ch: u8) -> hir::Mutability {
         // FIXME(#4846) expl. region
         '&' => {
             ty::ExplicitSelfCategory::ByReference(
-                ty::ReEmpty,
+                tcx.mk_region(ty::ReEmpty),
                 get_mutability(string.as_bytes()[1]))
         }
         _ => bug!("unknown self type code: `{}`", explicit_self_kind as char)
@@ -913,16 +906,6 @@ pub fn get_trait_name(cdata: Cmd, id: DefIndex) -> ast::Name {
     item_name(doc)
 }
 
-pub fn is_static_method(cdata: Cmd, id: DefIndex) -> bool {
-    let doc = cdata.lookup_item(id);
-    match item_sort(doc) {
-        Some('r') | Some('p') => {
-            get_explicit_self(doc) == ty::ExplicitSelfCategory::Static
-        }
-        _ => false
-    }
-}
-
 pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
                                         -> Option<ty::ImplOrTraitItem<'tcx>> {
     let item_doc = cdata.lookup_item(id);
@@ -967,7 +950,7 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a
                     "the type {:?} of the method {:?} is not a function?",
                     ity, name)
             };
-            let explicit_self = get_explicit_self(item_doc);
+            let explicit_self = get_explicit_self(item_doc, tcx);
 
             ty::MethodTraitItem(Rc::new(ty::Method::new(name,
                                                         generics,
@@ -1008,7 +991,7 @@ pub fn get_trait_item_def_ids(cdata: Cmd, id: DefIndex)
     }).collect()
 }
 
-pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> ty::ItemVariances {
+pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> Vec<ty::Variance> {
     let item_doc = cdata.lookup_item(id);
     let variance_doc = reader::get_doc(item_doc, tag_item_variances);
     let mut decoder = reader::Decoder::new(variance_doc);
@@ -1129,44 +1112,20 @@ pub fn get_struct_field_names(cdata: Cmd, id: DefIndex) -> Vec<ast::Name> {
     })).collect()
 }
 
-fn get_meta_items(md: rbml::Doc) -> Vec<P<ast::MetaItem>> {
-    reader::tagged_docs(md, tag_meta_item_word).map(|meta_item_doc| {
-        let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
-        let n = token::intern_and_get_ident(nd.as_str_slice());
-        attr::mk_word_item(n)
-    }).chain(reader::tagged_docs(md, tag_meta_item_name_value).map(|meta_item_doc| {
-        let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
-        let vd = reader::get_doc(meta_item_doc, tag_meta_item_value);
-        let n = token::intern_and_get_ident(nd.as_str_slice());
-        let v = token::intern_and_get_ident(vd.as_str_slice());
-        // FIXME (#623): Should be able to decode MetaItemKind::NameValue variants,
-        // but currently the encoder just drops them
-        attr::mk_name_value_item_str(n, v)
-    })).chain(reader::tagged_docs(md, tag_meta_item_list).map(|meta_item_doc| {
-        let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
-        let n = token::intern_and_get_ident(nd.as_str_slice());
-        let subitems = get_meta_items(meta_item_doc);
-        attr::mk_list_item(n, subitems)
-    })).collect()
-}
-
 fn get_attributes(md: rbml::Doc) -> Vec<ast::Attribute> {
-    match reader::maybe_get_doc(md, tag_attributes) {
-        Some(attrs_d) => {
-            reader::tagged_docs(attrs_d, tag_attribute).map(|attr_doc| {
-                let is_sugared_doc = reader::doc_as_u8(
-                    reader::get_doc(attr_doc, tag_attribute_is_sugared_doc)
-                ) == 1;
-                let meta_items = get_meta_items(attr_doc);
-                // Currently it's only possible to have a single meta item on
-                // an attribute
-                assert_eq!(meta_items.len(), 1);
-                let meta_item = meta_items.into_iter().nth(0).unwrap();
-                attr::mk_doc_attr_outer(attr::mk_attr_id(), meta_item, is_sugared_doc)
-            }).collect()
-        },
-        None => vec![],
-    }
+    reader::maybe_get_doc(md, tag_attributes).map_or(vec![], |attrs_doc| {
+        let mut decoder = reader::Decoder::new(attrs_doc);
+        let mut attrs: Vec<ast::Attribute> = decoder.read_opaque(|opaque_decoder, _| {
+            Decodable::decode(opaque_decoder)
+        }).unwrap();
+
+        // Need new unique IDs: old thread-local IDs won't map to new threads.
+        for attr in attrs.iter_mut() {
+            attr.node.id = attr::mk_attr_id();
+        }
+
+        attrs
+    })
 }
 
 fn list_crate_attributes(md: rbml::Doc, hash: &Svh,
@@ -1199,7 +1158,7 @@ pub fn get_crate_deps(data: &[u8]) -> Vec<CrateDep> {
 
     fn docstr(doc: rbml::Doc, tag_: usize) -> String {
         let d = reader::get_doc(doc, tag_);
-        d.as_str_slice().to_string()
+        d.as_str().to_string()
     }
 
     reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| {
@@ -1241,14 +1200,14 @@ pub fn get_crate_hash(data: &[u8]) -> Svh {
 pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> {
     let cratedoc = rbml::Doc::new(data);
     reader::maybe_get_doc(cratedoc, tag_crate_crate_name).map(|doc| {
-        doc.as_str_slice()
+        doc.as_str()
     })
 }
 
 pub fn get_crate_disambiguator<'a>(data: &'a [u8]) -> &'a str {
     let crate_doc = rbml::Doc::new(data);
     let disambiguator_doc = reader::get_doc(crate_doc, tag_crate_disambiguator);
-    let slice: &'a str = disambiguator_doc.as_str_slice();
+    let slice: &'a str = disambiguator_doc.as_str();
     slice
 }
 
@@ -1454,11 +1413,12 @@ pub fn get_dylib_dependency_formats(cdata: Cmd)
                                   tag_dylib_dependency_formats);
     let mut result = Vec::new();
 
-    debug!("found dylib deps: {}", formats.as_str_slice());
-    for spec in formats.as_str_slice().split(',') {
+    debug!("found dylib deps: {}", formats.as_str());
+    for spec in formats.as_str().split(',') {
         if spec.is_empty() { continue }
-        let cnum = spec.split(':').nth(0).unwrap();
-        let link = spec.split(':').nth(1).unwrap();
+        let mut split = spec.split(':');
+        let cnum = split.next().unwrap();
+        let link = split.next().unwrap();
         let cnum: ast::CrateNum = cnum.parse().unwrap();
         let cnum = cdata.cnum_map.borrow()[cnum];
         result.push((cnum, if link == "d" {
@@ -1484,7 +1444,7 @@ pub fn get_method_arg_names(cdata: Cmd, id: DefIndex) -> Vec<String> {
     match reader::maybe_get_doc(method_doc, tag_method_argument_names) {
         Some(args_doc) => {
             reader::tagged_docs(args_doc, tag_method_argument_name).map(|name_doc| {
-                name_doc.as_str_slice().to_string()
+                name_doc.as_str().to_string()
             }).collect()
         },
         None => vec![],
@@ -1649,7 +1609,7 @@ fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey {
             let mut decoder = reader::Decoder::new(def_key_doc);
             let simple_key = def_key::DefKey::decode(&mut decoder).unwrap();
             let name = reader::maybe_get_doc(item_doc, tag_paths_data_name).map(|name| {
-                token::intern(name.as_str_slice()).as_str()
+                token::intern(name.as_str()).as_str()
             });
             def_key::recover_def_key(simple_key, name)
         }
index ae9f500c5de59113ba5165bffa00c42feca1663a..099ec62b38de715180340825420473e9ebf47288 100644 (file)
@@ -14,7 +14,7 @@
 E0454: r##"
 A link name was given with an empty name. Erroneous code example:
 
-```
+```compile_fail,E0454
 #[link(name = "")] extern {} // error: #[link(name = "")] given with empty name
 ```
 
@@ -32,7 +32,7 @@
 
 Erroneous code example:
 
-```compile_fail"
+```compile_fail,E0455
 #[link(name = "FooCoreServices",  kind = "framework")] extern {}
 // OS used to compile is Linux for example
 ```
@@ -50,7 +50,7 @@
 E0458: r##"
 An unknown "kind" was specified for a link attribute. Erroneous code example:
 
-```
+```compile_fail,E0458
 #[link(kind = "wonderful_unicorn")] extern {}
 // error: unknown kind: `wonderful_unicorn`
 ```
@@ -64,7 +64,7 @@
 E0459: r##"
 A link was used without a name parameter. Erroneous code example:
 
-```
+```compile_fail,E0459
 #[link(kind = "dylib")] extern {}
 // error: #[link(...)] specified without `name = "foo"`
 ```
@@ -80,7 +80,7 @@
 E0463: r##"
 A plugin/crate was declared but cannot be found. Erroneous code example:
 
-```
+```compile_fail,E0463
 #![feature(plugin)]
 #![plugin(cookie_monster)] // error: can't find crate for `cookie_monster`
 extern crate cake_is_a_lie; // error: can't find crate for `cake_is_a_lie`
index 320ba3c8d9dc863c9344c800cc6228cf6a247097..b3ac678d7120d276eddbaf6a68f9ede0799c8420 100644 (file)
 use tyencode;
 use index::{self, IndexData};
 
-use middle::cstore::{LOCAL_CRATE, InlinedItemRef, LinkMeta, tls};
+use middle::cstore::{InlinedItemRef, LinkMeta, tls};
 use rustc::hir::def;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use middle::dependency_format::Linkage;
-use rustc::dep_graph::{DepGraph, DepNode, DepTask};
+use rustc::dep_graph::DepNode;
 use rustc::traits::specialization_graph;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::util::IntTypeExt;
 
 use rustc::hir::svh::Svh;
 use rustc::mir::mir_map::MirMap;
@@ -41,9 +40,8 @@
 use std::io::{Cursor, SeekFrom};
 use std::rc::Rc;
 use std::u32;
-use syntax::abi::Abi;
 use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum};
-use syntax::attr::{self,AttrMetaMethods,AttributeMethods};
+use syntax::attr;
 use errors::Handler;
 use syntax;
 use syntax_pos::BytePos;
@@ -54,6 +52,8 @@
 use rustc::hir::intravisit;
 use rustc::hir::map::DefKey;
 
+use super::index_builder::{FromId, IndexBuilder, ItemContentBuilder, Untracked, XRef};
+
 pub struct EncodeContext<'a, 'tcx: 'a> {
     pub diag: &'a Handler,
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -71,35 +71,6 @@ fn local_id(&self, def_id: DefId) -> NodeId {
     }
 }
 
-/// "interned" entries referenced by id
-#[derive(PartialEq, Eq, Hash)]
-pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) }
-
-struct CrateIndex<'a, 'tcx> {
-    dep_graph: &'a DepGraph,
-    items: IndexData,
-    xrefs: FnvHashMap<XRef<'tcx>, u32>, // sequentially-assigned
-}
-
-impl<'a, 'tcx> CrateIndex<'a, 'tcx> {
-    /// Records that `id` is being emitted at the current offset.
-    /// This data is later used to construct the item index in the
-    /// metadata so we can quickly find the data for a given item.
-    ///
-    /// Returns a dep-graph task that you should keep live as long as
-    /// the data for this item is being emitted.
-    fn record(&mut self, id: DefId, rbml_w: &mut Encoder) -> DepTask<'a> {
-        let position = rbml_w.mark_stable_position();
-        self.items.record(id, position);
-        self.dep_graph.in_task(DepNode::MetaData(id))
-    }
-
-    fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 {
-        let old_len = self.xrefs.len() as u32;
-        *self.xrefs.entry(xref).or_insert(old_len)
-    }
-}
-
 fn encode_name(rbml_w: &mut Encoder, name: Name) {
     rbml_w.wr_tagged_str(tag_paths_data_name, &name.as_str());
 }
@@ -159,24 +130,20 @@ fn encode_item_variances(rbml_w: &mut Encoder,
     rbml_w.end_tag();
 }
 
-fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder,
-                                             ecx: &EncodeContext<'a, 'tcx>,
-                                             index: &mut CrateIndex<'a, 'tcx>,
-                                             id: NodeId) {
-    encode_bounds_and_type(rbml_w,
-                           ecx,
-                           index,
-                           &ecx.tcx.lookup_item_type(ecx.tcx.map.local_def_id(id)),
-                           &ecx.tcx.lookup_predicates(ecx.tcx.map.local_def_id(id)));
-}
+impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
+    fn encode_bounds_and_type_for_item(&mut self,
+                                       id: NodeId) {
+        let ecx = self.ecx();
+        self.encode_bounds_and_type(&ecx.tcx.lookup_item_type(ecx.tcx.map.local_def_id(id)),
+                                    &ecx.tcx.lookup_predicates(ecx.tcx.map.local_def_id(id)));
+    }
 
-fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder,
-                                    ecx: &EncodeContext<'a, 'tcx>,
-                                    index: &mut CrateIndex<'a, 'tcx>,
-                                    scheme: &ty::TypeScheme<'tcx>,
-                                    predicates: &ty::GenericPredicates<'tcx>) {
-    encode_generics(rbml_w, ecx, index, &scheme.generics, &predicates);
-    encode_type(ecx, rbml_w, scheme.ty);
+    fn encode_bounds_and_type(&mut self,
+                              scheme: &ty::TypeScheme<'tcx>,
+                              predicates: &ty::GenericPredicates<'tcx>) {
+        self.encode_generics(&scheme.generics, &predicates);
+        self.encode_type(scheme.ty);
+    }
 }
 
 fn encode_variant_id(rbml_w: &mut Encoder, vid: DefId) {
@@ -192,92 +159,96 @@ fn write_closure_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
     rbml_w.mark_stable_position();
 }
 
-fn encode_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                         rbml_w: &mut Encoder,
-                         typ: Ty<'tcx>) {
-    rbml_w.start_tag(tag_items_data_item_type);
-    tyencode::enc_ty(rbml_w.writer, &ecx.ty_str_ctxt(), typ);
-    rbml_w.mark_stable_position();
-    rbml_w.end_tag();
-}
+impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
+    fn encode_type(&mut self,
+                   typ: Ty<'tcx>) {
+        let ecx = self.ecx;
+        self.rbml_w.start_tag(tag_items_data_item_type);
+        tyencode::enc_ty(self.rbml_w.writer, &ecx.ty_str_ctxt(), typ);
+        self.rbml_w.mark_stable_position();
+        self.rbml_w.end_tag();
+    }
 
-fn encode_disr_val(_: &EncodeContext,
-                   rbml_w: &mut Encoder,
-                   disr_val: ty::Disr) {
-    // convert to u64 so just the number is printed, without any type info
-    rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string());
-}
+    fn encode_disr_val(&mut self,
+                       disr_val: ty::Disr) {
+        // convert to u64 so just the number is printed, without any type info
+        self.rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string());
+    }
 
-fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) {
-    rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id));
+    fn encode_parent_item(&mut self, id: DefId) {
+        self.rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id));
+    }
+
+    fn encode_struct_fields(&mut self,
+                            variant: ty::VariantDef) {
+        for f in &variant.fields {
+            if variant.kind == ty::VariantKind::Tuple {
+                self.rbml_w.start_tag(tag_item_unnamed_field);
+            } else {
+                self.rbml_w.start_tag(tag_item_field);
+                encode_name(self.rbml_w, f.name);
+            }
+            self.encode_struct_field_family(f.vis);
+            encode_def_id(self.rbml_w, f.did);
+            self.rbml_w.end_tag();
+        }
+    }
 }
 
-fn encode_struct_fields(rbml_w: &mut Encoder,
-                        variant: ty::VariantDef) {
-    for f in &variant.fields {
-        if variant.kind == ty::VariantKind::Tuple {
-            rbml_w.start_tag(tag_item_unnamed_field);
-        } else {
-            rbml_w.start_tag(tag_item_field);
-            encode_name(rbml_w, f.name);
+impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
+    fn encode_enum_variant_infos(&mut self,
+                                 enum_did: DefId) {
+        debug!("encode_enum_variant_info(enum_did={:?})", enum_did);
+        let ecx = self.ecx();
+        let def = ecx.tcx.lookup_adt_def(enum_did);
+        self.encode_fields(enum_did);
+        for (i, variant) in def.variants.iter().enumerate() {
+            self.record(variant.did,
+                        ItemContentBuilder::encode_enum_variant_info,
+                        (enum_did, Untracked(i)));
         }
-        encode_struct_field_family(rbml_w, f.vis);
-        encode_def_id(rbml_w, f.did);
-        rbml_w.end_tag();
     }
 }
 
-fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                      rbml_w: &mut Encoder,
-                                      did: DefId,
-                                      vis: &hir::Visibility,
-                                      index: &mut CrateIndex<'a, 'tcx>) {
-    debug!("encode_enum_variant_info(did={:?})", did);
-    let repr_hints = ecx.tcx.lookup_repr_hints(did);
-    let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0));
-    let mut disr_val = repr_type.initial_discriminant(ecx.tcx);
-    let def = ecx.tcx.lookup_adt_def(did);
-    for variant in &def.variants {
+impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
+    /// Encode data for the given variant of the given ADT. The
+    /// index of the variant is untracked: this is ok because we
+    /// will have to lookup the adt-def by its id, and that gives us
+    /// the right to access any information in the adt-def (including,
+    /// e.g., the length of the various vectors).
+    fn encode_enum_variant_info(&mut self,
+                                (enum_did, Untracked(index)):
+                                (DefId, Untracked<usize>)) {
+        let ecx = self.ecx;
+        let def = ecx.tcx.lookup_adt_def(enum_did);
+        let variant = &def.variants[index];
         let vid = variant.did;
         let variant_node_id = ecx.local_id(vid);
-
-        for field in &variant.fields {
-            encode_field(ecx, rbml_w, field, index);
-        }
-
-        let _task = index.record(vid, rbml_w);
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, vid);
-        encode_family(rbml_w, match variant.kind {
+        encode_def_id_and_key(ecx, self.rbml_w, vid);
+        encode_family(self.rbml_w, match variant.kind {
             ty::VariantKind::Struct => 'V',
             ty::VariantKind::Tuple => 'v',
             ty::VariantKind::Unit => 'w',
         });
-        encode_name(rbml_w, variant.name);
-        encode_parent_item(rbml_w, did);
-        encode_visibility(rbml_w, vis);
+        encode_name(self.rbml_w, variant.name);
+        self.encode_parent_item(enum_did);
+
+        let enum_id = ecx.tcx.map.as_local_node_id(enum_did).unwrap();
+        let enum_vis = &ecx.tcx.map.expect_item(enum_id).vis;
+        self.encode_visibility(enum_vis);
 
         let attrs = ecx.tcx.get_attrs(vid);
-        encode_attributes(rbml_w, &attrs);
-        encode_repr_attrs(rbml_w, ecx, &attrs);
+        encode_attributes(self.rbml_w, &attrs);
+        self.encode_repr_attrs(&attrs);
 
         let stab = ecx.tcx.lookup_stability(vid);
         let depr = ecx.tcx.lookup_deprecation(vid);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-
-        encode_struct_fields(rbml_w, variant);
-
-        let specified_disr_val = variant.disr_val;
-        if specified_disr_val != disr_val {
-            encode_disr_val(ecx, rbml_w, specified_disr_val);
-            disr_val = specified_disr_val;
-        }
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, variant_node_id);
+        encode_stability(self.rbml_w, stab);
+        encode_deprecation(self.rbml_w, depr);
 
-        rbml_w.end_tag();
-
-        disr_val = disr_val.wrap_incr();
+        self.encode_struct_fields(variant);
+        self.encode_disr_val(variant.disr_val);
+        self.encode_bounds_and_type_for_item(variant_node_id);
     }
 }
 
@@ -327,57 +298,54 @@ fn encode_reexports(ecx: &EncodeContext,
     }
 }
 
-fn encode_info_for_mod(ecx: &EncodeContext,
-                       rbml_w: &mut Encoder,
-                       md: &hir::Mod,
-                       attrs: &[ast::Attribute],
-                       id: NodeId,
-                       name: Name,
-                       vis: &hir::Visibility) {
-    rbml_w.start_tag(tag_items_data_item);
-    encode_def_id_and_key(ecx, rbml_w, ecx.tcx.map.local_def_id(id));
-    encode_family(rbml_w, 'm');
-    encode_name(rbml_w, name);
-    debug!("(encoding info for module) encoding info for module ID {}", id);
-
-    // Encode info about all the module children.
-    for item_id in &md.item_ids {
-        rbml_w.wr_tagged_u64(tag_mod_child,
-                             def_to_u64(ecx.tcx.map.local_def_id(item_id.id)));
-
-        let item = ecx.tcx.map.expect_item(item_id.id);
-        each_auxiliary_node_id(item, |auxiliary_node_id| {
-            rbml_w.wr_tagged_u64(tag_mod_child,
-                                 def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id)));
-            true
-        });
-    }
+impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
+    fn encode_info_for_mod(&mut self,
+                           FromId(id, (md, attrs, name, vis)):
+                           FromId<(&hir::Mod, &[ast::Attribute], Name, &hir::Visibility)>) {
+        let ecx = self.ecx();
+
+        encode_def_id_and_key(ecx, self.rbml_w, ecx.tcx.map.local_def_id(id));
+        encode_family(self.rbml_w, 'm');
+        encode_name(self.rbml_w, name);
+        debug!("(encoding info for module) encoding info for module ID {}", id);
+
+        // Encode info about all the module children.
+        for item_id in &md.item_ids {
+            self.rbml_w.wr_tagged_u64(tag_mod_child,
+                                 def_to_u64(ecx.tcx.map.local_def_id(item_id.id)));
+
+            let item = ecx.tcx.map.expect_item(item_id.id);
+            each_auxiliary_node_id(item, |auxiliary_node_id| {
+                self.rbml_w.wr_tagged_u64(tag_mod_child,
+                                     def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id)));
+                true
+            });
+        }
 
-    encode_visibility(rbml_w, vis);
+        self.encode_visibility(vis);
 
-    let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(id));
-    let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(id));
-    encode_stability(rbml_w, stab);
-    encode_deprecation(rbml_w, depr);
+        let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(id));
+        let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(id));
+        encode_stability(self.rbml_w, stab);
+        encode_deprecation(self.rbml_w, depr);
 
-    // Encode the reexports of this module, if this module is public.
-    if *vis == hir::Public {
-        debug!("(encoding info for module) encoding reexports for {}", id);
-        encode_reexports(ecx, rbml_w, id);
+        // Encode the reexports of this module, if this module is public.
+        if *vis == hir::Public {
+            debug!("(encoding info for module) encoding reexports for {}", id);
+            encode_reexports(ecx, self.rbml_w, id);
+        }
+        encode_attributes(self.rbml_w, attrs);
     }
-    encode_attributes(rbml_w, attrs);
 
-    rbml_w.end_tag();
-}
-
-fn encode_struct_field_family(rbml_w: &mut Encoder,
-                              visibility: ty::Visibility) {
-    encode_family(rbml_w, if visibility.is_public() { 'g' } else { 'N' });
-}
+    fn encode_struct_field_family(&mut self,
+                                  visibility: ty::Visibility) {
+        encode_family(self.rbml_w, if visibility.is_public() { 'g' } else { 'N' });
+    }
 
-fn encode_visibility<T: HasVisibility>(rbml_w: &mut Encoder, visibility: T) {
-    let ch = if visibility.is_public() { 'y' } else { 'i' };
-    rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8);
+    fn encode_visibility<T: HasVisibility>(&mut self, visibility: T) {
+        let ch = if visibility.is_public() { 'y' } else { 'i' };
+        self.rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8);
+    }
 }
 
 trait HasVisibility: Sized {
@@ -448,280 +416,402 @@ fn encode_item_sort(rbml_w: &mut Encoder, sort: char) {
     rbml_w.wr_tagged_u8(tag_item_trait_item_sort, sort as u8);
 }
 
-fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                          rbml_w: &mut Encoder,
-                          field: ty::FieldDef<'tcx>,
-                          index: &mut CrateIndex<'a, 'tcx>) {
-    let nm = field.name;
-    let id = ecx.local_id(field.did);
-
-    let _task = index.record(field.did, rbml_w);
-    rbml_w.start_tag(tag_items_data_item);
-    debug!("encode_field: encoding {} {}", nm, id);
-    encode_struct_field_family(rbml_w, field.vis);
-    encode_name(rbml_w, nm);
-    encode_bounds_and_type_for_item(rbml_w, ecx, index, id);
-    encode_def_id_and_key(ecx, rbml_w, field.did);
-
-    let stab = ecx.tcx.lookup_stability(field.did);
-    let depr = ecx.tcx.lookup_deprecation(field.did);
-    encode_stability(rbml_w, stab);
-    encode_deprecation(rbml_w, depr);
-
-    rbml_w.end_tag();
+impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
+    fn encode_fields(&mut self,
+                     adt_def_id: DefId) {
+        let def = self.ecx().tcx.lookup_adt_def(adt_def_id);
+        for (variant_index, variant) in def.variants.iter().enumerate() {
+            for (field_index, field) in variant.fields.iter().enumerate() {
+                self.record(field.did,
+                            ItemContentBuilder::encode_field,
+                            (adt_def_id, Untracked((variant_index, field_index))));
+            }
+        }
+    }
 }
 
-fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                         rbml_w: &mut Encoder,
-                                         name: Name,
-                                         struct_def: &hir::VariantData,
-                                         index: &mut CrateIndex<'a, 'tcx>,
-                                         struct_id: NodeId) {
-    let ctor_id = struct_def.id();
-    let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id);
-
-    let _task = index.record(ctor_def_id, rbml_w);
-    rbml_w.start_tag(tag_items_data_item);
-    encode_def_id_and_key(ecx, rbml_w, ctor_def_id);
-    encode_family(rbml_w, match *struct_def {
-        hir::VariantData::Struct(..) => 'S',
-        hir::VariantData::Tuple(..) => 's',
-        hir::VariantData::Unit(..) => 'u',
-    });
-    encode_bounds_and_type_for_item(rbml_w, ecx, index, ctor_id);
-    encode_name(rbml_w, name);
-    encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id));
-
-    let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(ctor_id));
-    let depr= ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(ctor_id));
-    encode_stability(rbml_w, stab);
-    encode_deprecation(rbml_w, depr);
-
-    // indicate that this is a tuple struct ctor, because downstream users will normally want
-    // the tuple struct definition, but without this there is no way for them to tell that
-    // they actually have a ctor rather than a normal function
-    rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]);
-
-    rbml_w.end_tag();
+impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
+    /// Encode data for the given field of the given variant of the
+    /// given ADT. The indices of the variant/field are untracked:
+    /// this is ok because we will have to lookup the adt-def by its
+    /// id, and that gives us the right to access any information in
+    /// the adt-def (including, e.g., the length of the various
+    /// vectors).
+    fn encode_field(&mut self,
+                    (adt_def_id, Untracked((variant_index, field_index))):
+                    (DefId, Untracked<(usize, usize)>)) {
+        let ecx = self.ecx();
+        let def = ecx.tcx.lookup_adt_def(adt_def_id);
+        let variant = &def.variants[variant_index];
+        let field = &variant.fields[field_index];
+
+        let nm = field.name;
+        let id = ecx.local_id(field.did);
+        debug!("encode_field: encoding {} {}", nm, id);
+
+        self.encode_struct_field_family(field.vis);
+        encode_name(self.rbml_w, nm);
+        self.encode_bounds_and_type_for_item(id);
+        encode_def_id_and_key(ecx, self.rbml_w, field.did);
+
+        let stab = ecx.tcx.lookup_stability(field.did);
+        let depr = ecx.tcx.lookup_deprecation(field.did);
+        encode_stability(self.rbml_w, stab);
+        encode_deprecation(self.rbml_w, depr);
+    }
 }
 
-fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
-                             ecx: &EncodeContext<'a, 'tcx>,
-                             index: &mut CrateIndex<'a, 'tcx>,
-                             generics: &ty::Generics<'tcx>,
-                             predicates: &ty::GenericPredicates<'tcx>)
-{
-    rbml_w.start_tag(tag_item_generics);
-    tyencode::enc_generics(rbml_w.writer, &ecx.ty_str_ctxt(), generics);
-    rbml_w.mark_stable_position();
-    rbml_w.end_tag();
-
-    encode_predicates(rbml_w, index, predicates, tag_item_predicates);
+impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
+    fn encode_struct_ctor(&mut self,
+                          (struct_def_id, struct_node_id, ctor_node_id):
+                          (DefId, ast::NodeId, ast::NodeId)) {
+        let ecx = self.ecx();
+        let def = ecx.tcx.lookup_adt_def(struct_def_id);
+        let variant = def.struct_variant();
+        let item = ecx.tcx.map.expect_item(struct_node_id);
+        let ctor_def_id = ecx.tcx.map.local_def_id(ctor_node_id);
+        encode_def_id_and_key(ecx, self.rbml_w, ctor_def_id);
+        encode_family(self.rbml_w, match variant.kind {
+            ty::VariantKind::Struct => 'S',
+            ty::VariantKind::Tuple => 's',
+            ty::VariantKind::Unit => 'u',
+        });
+        self.encode_bounds_and_type_for_item(ctor_node_id);
+        encode_name(self.rbml_w, item.name);
+        self.encode_parent_item(struct_def_id);
+
+        let stab = ecx.tcx.lookup_stability(ctor_def_id);
+        let depr = ecx.tcx.lookup_deprecation(ctor_def_id);
+        encode_stability(self.rbml_w, stab);
+        encode_deprecation(self.rbml_w, depr);
+
+        // indicate that this is a tuple struct ctor, because
+        // downstream users will normally want the tuple struct
+        // definition, but without this there is no way for them
+        // to tell that they actually have a ctor rather than a
+        // normal function
+        self.rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]);
+    }
 }
 
-fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder,
-                              index: &mut CrateIndex<'a, 'tcx>,
-                              predicates: &ty::GenericPredicates<'tcx>,
-                              tag: usize)
-{
-    rbml_w.start_tag(tag);
-    if let Some(def_id) = predicates.parent {
-        rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(def_id));
+impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
+    fn encode_generics(&mut self,
+                       generics: &ty::Generics<'tcx>,
+                       predicates: &ty::GenericPredicates<'tcx>)
+    {
+        let ecx = self.ecx();
+        self.rbml_w.start_tag(tag_item_generics);
+        tyencode::enc_generics(self.rbml_w.writer, &ecx.ty_str_ctxt(), generics);
+        self.rbml_w.mark_stable_position();
+        self.rbml_w.end_tag();
+        self.encode_predicates(predicates, tag_item_predicates);
     }
-    for predicate in &predicates.predicates {
-        rbml_w.wr_tagged_u32(tag_predicate,
-            index.add_xref(XRef::Predicate(predicate.clone())));
+
+    fn encode_predicates(&mut self,
+                         predicates: &ty::GenericPredicates<'tcx>,
+                         tag: usize) {
+        self.rbml_w.start_tag(tag);
+        if let Some(def_id) = predicates.parent {
+            self.rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(def_id));
+        }
+        for predicate in &predicates.predicates {
+            let xref = self.add_xref(XRef::Predicate(predicate.clone()));
+            self.rbml_w.wr_tagged_u32(tag_predicate, xref);
+        }
+        self.rbml_w.end_tag();
     }
-    rbml_w.end_tag();
-}
 
-fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                     rbml_w: &mut Encoder,
-                                     index: &mut CrateIndex<'a, 'tcx>,
-                                     method_ty: &ty::Method<'tcx>) {
-    encode_def_id_and_key(ecx, rbml_w, method_ty.def_id);
-    encode_name(rbml_w, method_ty.name);
-    encode_generics(rbml_w, ecx, index,
-                    &method_ty.generics, &method_ty.predicates);
-    encode_visibility(rbml_w, method_ty.vis);
-    encode_explicit_self(rbml_w, &method_ty.explicit_self);
-    match method_ty.explicit_self {
-        ty::ExplicitSelfCategory::Static => {
-            encode_family(rbml_w, STATIC_METHOD_FAMILY);
+    fn encode_method_ty_fields(&mut self,
+                               method_ty: &ty::Method<'tcx>) {
+        let ecx = self.ecx();
+        encode_def_id_and_key(ecx, self.rbml_w, method_ty.def_id);
+        encode_name(self.rbml_w, method_ty.name);
+        self.encode_generics(&method_ty.generics, &method_ty.predicates);
+        self.encode_visibility(method_ty.vis);
+        encode_explicit_self(self.rbml_w, &method_ty.explicit_self);
+        match method_ty.explicit_self {
+            ty::ExplicitSelfCategory::Static => {
+                encode_family(self.rbml_w, STATIC_METHOD_FAMILY);
+            }
+            _ => encode_family(self.rbml_w, METHOD_FAMILY)
         }
-        _ => encode_family(rbml_w, METHOD_FAMILY)
     }
 }
 
-fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                              rbml_w: &mut Encoder,
-                                              index: &mut CrateIndex<'a, 'tcx>,
-                                              associated_const: &ty::AssociatedConst,
-                                              parent_id: NodeId,
-                                              impl_item_opt: Option<&hir::ImplItem>) {
-    debug!("encode_info_for_associated_const({:?},{:?})",
-           associated_const.def_id,
-           associated_const.name);
+impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
+    fn encode_info_for_trait_item(&mut self,
+                                  (trait_def_id, item_def_id, trait_item):
+                                  (DefId, DefId, &hir::TraitItem)) {
+        let ecx = self.ecx;
+        let tcx = ecx.tcx;
 
-    let _task = index.record(associated_const.def_id, rbml_w);
-    rbml_w.start_tag(tag_items_data_item);
+        self.encode_parent_item(trait_def_id);
 
-    encode_def_id_and_key(ecx, rbml_w, associated_const.def_id);
-    encode_name(rbml_w, associated_const.name);
-    encode_visibility(rbml_w, associated_const.vis);
-    encode_family(rbml_w, 'C');
+        let stab = tcx.lookup_stability(item_def_id);
+        let depr = tcx.lookup_deprecation(item_def_id);
+        encode_stability(self.rbml_w, stab);
+        encode_deprecation(self.rbml_w, depr);
 
-    encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
-    encode_item_sort(rbml_w, 'C');
+        let trait_item_type =
+            tcx.impl_or_trait_item(item_def_id);
+        let is_nonstatic_method;
+        match trait_item_type {
+            ty::ConstTraitItem(associated_const) => {
+                encode_name(self.rbml_w, associated_const.name);
+                encode_def_id_and_key(ecx, self.rbml_w, associated_const.def_id);
+                self.encode_visibility(associated_const.vis);
 
-    encode_bounds_and_type_for_item(rbml_w, ecx, index,
-                                    ecx.local_id(associated_const.def_id));
+                encode_family(self.rbml_w, 'C');
 
-    let stab = ecx.tcx.lookup_stability(associated_const.def_id);
-    let depr = ecx.tcx.lookup_deprecation(associated_const.def_id);
-    encode_stability(rbml_w, stab);
-    encode_deprecation(rbml_w, depr);
+                self.encode_bounds_and_type_for_item(
+                    ecx.local_id(associated_const.def_id));
 
-    if let Some(ii) = impl_item_opt {
-        encode_attributes(rbml_w, &ii.attrs);
-        encode_defaultness(rbml_w, ii.defaultness);
-        encode_inlined_item(ecx,
-                            rbml_w,
-                            InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
-                                                     ii));
-        encode_mir(ecx, rbml_w, ii.id);
-    }
+                is_nonstatic_method = false;
+            }
+            ty::MethodTraitItem(method_ty) => {
+                let method_def_id = item_def_id;
 
-    rbml_w.end_tag();
-}
+                self.encode_method_ty_fields(&method_ty);
 
-fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                    rbml_w: &mut Encoder,
-                                    index: &mut CrateIndex<'a, 'tcx>,
-                                    m: &ty::Method<'tcx>,
-                                    is_default_impl: bool,
-                                    parent_id: NodeId,
-                                    impl_item_opt: Option<&hir::ImplItem>) {
-
-    debug!("encode_info_for_method: {:?} {:?}", m.def_id,
-           m.name);
-    let _task = index.record(m.def_id, rbml_w);
-    rbml_w.start_tag(tag_items_data_item);
-
-    encode_method_ty_fields(ecx, rbml_w, index, m);
-    encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
-    encode_item_sort(rbml_w, 'r');
-
-    let stab = ecx.tcx.lookup_stability(m.def_id);
-    let depr = ecx.tcx.lookup_deprecation(m.def_id);
-    encode_stability(rbml_w, stab);
-    encode_deprecation(rbml_w, depr);
-
-    let m_node_id = ecx.local_id(m.def_id);
-    encode_bounds_and_type_for_item(rbml_w, ecx, index, m_node_id);
-
-    if let Some(impl_item) = impl_item_opt {
-        if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
-            encode_attributes(rbml_w, &impl_item.attrs);
-            let generics = ecx.tcx.lookup_generics(m.def_id);
-            let types = generics.parent_types as usize + generics.types.len();
-            let needs_inline = types > 0 || is_default_impl ||
-                               attr::requests_inline(&impl_item.attrs);
-            if needs_inline || sig.constness == hir::Constness::Const {
-                encode_inlined_item(ecx,
-                                    rbml_w,
-                                    InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
-                                                             impl_item));
-                encode_mir(ecx, rbml_w, impl_item.id);
+                match method_ty.explicit_self {
+                    ty::ExplicitSelfCategory::Static => {
+                        encode_family(self.rbml_w,
+                                      STATIC_METHOD_FAMILY);
+                    }
+                    _ => {
+                        encode_family(self.rbml_w,
+                                      METHOD_FAMILY);
+                    }
+                }
+                self.encode_bounds_and_type_for_item(ecx.local_id(method_def_id));
+
+                is_nonstatic_method = method_ty.explicit_self !=
+                    ty::ExplicitSelfCategory::Static;
+            }
+            ty::TypeTraitItem(associated_type) => {
+                encode_name(self.rbml_w, associated_type.name);
+                encode_def_id_and_key(ecx, self.rbml_w, associated_type.def_id);
+                encode_item_sort(self.rbml_w, 't');
+                encode_family(self.rbml_w, 'y');
+
+                if let Some(ty) = associated_type.ty {
+                    self.encode_type(ty);
+                }
+
+                is_nonstatic_method = false;
             }
-            encode_constness(rbml_w, sig.constness);
-            encode_defaultness(rbml_w, impl_item.defaultness);
-            encode_method_argument_names(rbml_w, &sig.decl);
         }
-    }
 
-    rbml_w.end_tag();
-}
+        encode_attributes(self.rbml_w, &trait_item.attrs);
+        match trait_item.node {
+            hir::ConstTraitItem(_, ref default) => {
+                if default.is_some() {
+                    encode_item_sort(self.rbml_w, 'C');
+                } else {
+                    encode_item_sort(self.rbml_w, 'c');
+                }
 
-fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                             rbml_w: &mut Encoder,
-                                             index: &mut CrateIndex<'a, 'tcx>,
-                                             associated_type: &ty::AssociatedType<'tcx>,
-                                             parent_id: NodeId,
-                                             impl_item_opt: Option<&hir::ImplItem>) {
-    debug!("encode_info_for_associated_type({:?},{:?})",
-           associated_type.def_id,
-           associated_type.name);
+                encode_inlined_item(ecx, self.rbml_w,
+                                    InlinedItemRef::TraitItem(trait_def_id, trait_item));
+                self.encode_mir(trait_item.id);
+            }
+            hir::MethodTraitItem(ref sig, ref body) => {
+                // If this is a static method, we've already
+                // encoded self.
+                if is_nonstatic_method {
+                    self.encode_bounds_and_type_for_item(
+                        ecx.local_id(item_def_id));
+                }
 
-    let _task = index.record(associated_type.def_id, rbml_w);
-    rbml_w.start_tag(tag_items_data_item);
+                if body.is_some() {
+                    encode_item_sort(self.rbml_w, 'p');
+                    self.encode_mir(trait_item.id);
+                } else {
+                    encode_item_sort(self.rbml_w, 'r');
+                }
+                self.encode_method_argument_names(&sig.decl);
+            }
 
-    encode_def_id_and_key(ecx, rbml_w, associated_type.def_id);
-    encode_name(rbml_w, associated_type.name);
-    encode_visibility(rbml_w, associated_type.vis);
-    encode_family(rbml_w, 'y');
-    encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
-    encode_item_sort(rbml_w, 't');
+            hir::TypeTraitItem(..) => {}
+        }
+    }
 
-    let stab = ecx.tcx.lookup_stability(associated_type.def_id);
-    let depr = ecx.tcx.lookup_deprecation(associated_type.def_id);
-    encode_stability(rbml_w, stab);
-    encode_deprecation(rbml_w, depr);
+    fn encode_info_for_impl_item(&mut self,
+                                 (impl_id, impl_item_def_id, ast_item):
+                                 (NodeId, DefId, Option<&hir::ImplItem>)) {
+        match self.ecx.tcx.impl_or_trait_item(impl_item_def_id) {
+            ty::ConstTraitItem(ref associated_const) => {
+                self.encode_info_for_associated_const(&associated_const,
+                                                      impl_id,
+                                                      ast_item)
+            }
+            ty::MethodTraitItem(ref method_type) => {
+                self.encode_info_for_method(&method_type,
+                                            false,
+                                            impl_id,
+                                            ast_item)
+            }
+            ty::TypeTraitItem(ref associated_type) => {
+                self.encode_info_for_associated_type(&associated_type,
+                                                     impl_id,
+                                                     ast_item)
+            }
+        }
+    }
 
-    if let Some(ii) = impl_item_opt {
-        encode_attributes(rbml_w, &ii.attrs);
-        encode_defaultness(rbml_w, ii.defaultness);
-    } else {
-        encode_predicates(rbml_w, index,
-                          &ecx.tcx.lookup_predicates(associated_type.def_id),
-                          tag_item_generics);
+    fn encode_info_for_associated_const(&mut self,
+                                        associated_const: &ty::AssociatedConst,
+                                        parent_id: NodeId,
+                                        impl_item_opt: Option<&hir::ImplItem>) {
+        let ecx = self.ecx();
+        debug!("encode_info_for_associated_const({:?},{:?})",
+               associated_const.def_id,
+               associated_const.name);
+
+        encode_def_id_and_key(ecx, self.rbml_w, associated_const.def_id);
+        encode_name(self.rbml_w, associated_const.name);
+        self.encode_visibility(associated_const.vis);
+        encode_family(self.rbml_w, 'C');
+
+        self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id));
+        encode_item_sort(self.rbml_w, 'C');
+
+        self.encode_bounds_and_type_for_item(ecx.local_id(associated_const.def_id));
+
+        let stab = ecx.tcx.lookup_stability(associated_const.def_id);
+        let depr = ecx.tcx.lookup_deprecation(associated_const.def_id);
+        encode_stability(self.rbml_w, stab);
+        encode_deprecation(self.rbml_w, depr);
+
+        if let Some(ii) = impl_item_opt {
+            encode_attributes(self.rbml_w, &ii.attrs);
+            encode_defaultness(self.rbml_w, ii.defaultness);
+            encode_inlined_item(ecx,
+                                self.rbml_w,
+                                InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
+                                                         ii));
+            self.encode_mir(ii.id);
+        }
     }
 
-    if let Some(ty) = associated_type.ty {
-        encode_type(ecx, rbml_w, ty);
+    fn encode_info_for_method(&mut self,
+                              m: &ty::Method<'tcx>,
+                              is_default_impl: bool,
+                              parent_id: NodeId,
+                              impl_item_opt: Option<&hir::ImplItem>) {
+        let ecx = self.ecx();
+
+        debug!("encode_info_for_method: {:?} {:?}", m.def_id,
+               m.name);
+        self.encode_method_ty_fields(m);
+        self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id));
+        encode_item_sort(self.rbml_w, 'r');
+
+        let stab = ecx.tcx.lookup_stability(m.def_id);
+        let depr = ecx.tcx.lookup_deprecation(m.def_id);
+        encode_stability(self.rbml_w, stab);
+        encode_deprecation(self.rbml_w, depr);
+
+        let m_node_id = ecx.local_id(m.def_id);
+        self.encode_bounds_and_type_for_item(m_node_id);
+
+        if let Some(impl_item) = impl_item_opt {
+            if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
+                encode_attributes(self.rbml_w, &impl_item.attrs);
+                let generics = ecx.tcx.lookup_generics(m.def_id);
+                let types = generics.parent_types as usize + generics.types.len();
+                let needs_inline = types > 0 || is_default_impl ||
+                    attr::requests_inline(&impl_item.attrs);
+                if sig.constness == hir::Constness::Const {
+                    encode_inlined_item(
+                        ecx,
+                        self.rbml_w,
+                        InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
+                                                 impl_item));
+                }
+                if needs_inline || sig.constness == hir::Constness::Const {
+                    self.encode_mir(impl_item.id);
+                }
+                encode_constness(self.rbml_w, sig.constness);
+                encode_defaultness(self.rbml_w, impl_item.defaultness);
+                self.encode_method_argument_names(&sig.decl);
+            }
+        }
     }
 
-    rbml_w.end_tag();
-}
+    fn encode_info_for_associated_type(&mut self,
+                                       associated_type: &ty::AssociatedType<'tcx>,
+                                       parent_id: NodeId,
+                                       impl_item_opt: Option<&hir::ImplItem>) {
+        let ecx = self.ecx();
+        debug!("encode_info_for_associated_type({:?},{:?})",
+               associated_type.def_id,
+               associated_type.name);
+
+        encode_def_id_and_key(ecx, self.rbml_w, associated_type.def_id);
+        encode_name(self.rbml_w, associated_type.name);
+        self.encode_visibility(associated_type.vis);
+        encode_family(self.rbml_w, 'y');
+        self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id));
+        encode_item_sort(self.rbml_w, 't');
+
+        let stab = ecx.tcx.lookup_stability(associated_type.def_id);
+        let depr = ecx.tcx.lookup_deprecation(associated_type.def_id);
+        encode_stability(self.rbml_w, stab);
+        encode_deprecation(self.rbml_w, depr);
+
+        if let Some(ii) = impl_item_opt {
+            encode_attributes(self.rbml_w, &ii.attrs);
+            encode_defaultness(self.rbml_w, ii.defaultness);
+        }
 
-fn encode_method_argument_names(rbml_w: &mut Encoder,
-                                decl: &hir::FnDecl) {
-    rbml_w.start_tag(tag_method_argument_names);
-    for arg in &decl.inputs {
-        let tag = tag_method_argument_name;
-        if let PatKind::Binding(_, ref path1, _) = arg.pat.node {
-            let name = path1.node.as_str();
-            rbml_w.wr_tagged_bytes(tag, name.as_bytes());
-        } else {
-            rbml_w.wr_tagged_bytes(tag, &[]);
+        if let Some(ty) = associated_type.ty {
+            self.encode_type(ty);
         }
     }
-    rbml_w.end_tag();
 }
 
-fn encode_repr_attrs(rbml_w: &mut Encoder,
-                     ecx: &EncodeContext,
-                     attrs: &[ast::Attribute]) {
-    let mut repr_attrs = Vec::new();
-    for attr in attrs {
-        repr_attrs.extend(attr::find_repr_attrs(ecx.tcx.sess.diagnostic(),
-                                                attr));
+impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
+    fn encode_method_argument_names(&mut self,
+                                    decl: &hir::FnDecl) {
+        self.rbml_w.start_tag(tag_method_argument_names);
+        for arg in &decl.inputs {
+            let tag = tag_method_argument_name;
+            if let PatKind::Binding(_, ref path1, _) = arg.pat.node {
+                let name = path1.node.as_str();
+                self.rbml_w.wr_tagged_bytes(tag, name.as_bytes());
+            } else {
+                self.rbml_w.wr_tagged_bytes(tag, &[]);
+            }
+        }
+        self.rbml_w.end_tag();
     }
-    rbml_w.start_tag(tag_items_data_item_repr);
-    repr_attrs.encode(rbml_w);
-    rbml_w.end_tag();
-}
 
-fn encode_mir(ecx: &EncodeContext, rbml_w: &mut Encoder, node_id: NodeId) {
-    let def_id = ecx.tcx.map.local_def_id(node_id);
-    if let Some(mir) = ecx.mir_map.map.get(&def_id) {
-        rbml_w.start_tag(tag_mir as usize);
-        rbml_w.emit_opaque(|opaque_encoder| {
-            tls::enter_encoding_context(ecx, opaque_encoder, |_, opaque_encoder| {
-                Encodable::encode(mir, opaque_encoder)
-            })
-        }).unwrap();
-        rbml_w.end_tag();
+    fn encode_repr_attrs(&mut self,
+                         attrs: &[ast::Attribute]) {
+        let ecx = self.ecx();
+        let mut repr_attrs = Vec::new();
+        for attr in attrs {
+            repr_attrs.extend(attr::find_repr_attrs(ecx.tcx.sess.diagnostic(),
+                                                    attr));
+        }
+        self.rbml_w.start_tag(tag_items_data_item_repr);
+        repr_attrs.encode(self.rbml_w);
+        self.rbml_w.end_tag();
+    }
+
+    fn encode_mir(&mut self, node_id: NodeId) {
+        let ecx = self.ecx();
+        let def_id = ecx.tcx.map.local_def_id(node_id);
+        if let Some(mir) = ecx.mir_map.map.get(&def_id) {
+            self.rbml_w.start_tag(tag_mir as usize);
+            self.rbml_w.emit_opaque(|opaque_encoder| {
+                tls::enter_encoding_context(ecx, opaque_encoder, |_, opaque_encoder| {
+                    Encodable::encode(mir, opaque_encoder)
+                })
+            }).unwrap();
+            self.rbml_w.end_tag();
+        }
     }
 }
 
@@ -772,8 +862,13 @@ fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                           xrefs: FnvHashMap<XRef<'tcx>, u32>)
 {
     let mut xref_positions = vec![0; xrefs.len()];
+
+    // Encode XRefs sorted by their ID
+    let mut sorted_xrefs: Vec<_> = xrefs.into_iter().collect();
+    sorted_xrefs.sort_by_key(|&(_, id)| id);
+
     rbml_w.start_tag(tag_xref_data);
-    for (xref, id) in xrefs.into_iter() {
+    for (xref, id) in sorted_xrefs.into_iter() {
         xref_positions[id as usize] = rbml_w.mark_stable_position() as u32;
         match xref {
             XRef::Predicate(p) => {
@@ -789,623 +884,531 @@ fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
     rbml_w.end_tag();
 }
 
-fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                  rbml_w: &mut Encoder,
-                                  item: &hir::Item,
-                                  index: &mut CrateIndex<'a, 'tcx>) {
-    let tcx = ecx.tcx;
-
-    debug!("encoding info for item at {}",
-           tcx.sess.codemap().span_to_string(item.span));
-
-    let vis = &item.vis;
-    let def_id = ecx.tcx.map.local_def_id(item.id);
-
-    let (stab, depr) = tcx.dep_graph.with_task(DepNode::MetaData(def_id), || {
-        (tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id)),
-         tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id)))
-    });
-
-    match item.node {
-      hir::ItemStatic(_, m, _) => {
-        let _task = index.record(def_id, rbml_w);
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        if m == hir::MutMutable {
-            encode_family(rbml_w, 'b');
-        } else {
-            encode_family(rbml_w, 'c');
-        }
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-        encode_name(rbml_w, item.name);
-        encode_visibility(rbml_w, vis);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        encode_attributes(rbml_w, &item.attrs);
-        rbml_w.end_tag();
-      }
-      hir::ItemConst(_, _) => {
-        let _task = index.record(def_id, rbml_w);
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, 'C');
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-        encode_name(rbml_w, item.name);
-        encode_attributes(rbml_w, &item.attrs);
-        encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
-        encode_mir(ecx, rbml_w, item.id);
-        encode_visibility(rbml_w, vis);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        rbml_w.end_tag();
-      }
-      hir::ItemFn(ref decl, _, constness, _, ref generics, _) => {
-        let _task = index.record(def_id, rbml_w);
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, FN_FAMILY);
-        let tps_len = generics.ty_params.len();
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-        encode_name(rbml_w, item.name);
-        encode_attributes(rbml_w, &item.attrs);
-        let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs);
-        if needs_inline || constness == hir::Constness::Const {
-            encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
-            encode_mir(ecx, rbml_w, item.id);
-        }
-        encode_constness(rbml_w, constness);
-        encode_visibility(rbml_w, vis);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        encode_method_argument_names(rbml_w, &decl);
-        rbml_w.end_tag();
-      }
-      hir::ItemMod(ref m) => {
-        let _task = index.record(def_id, rbml_w);
-        encode_info_for_mod(ecx,
-                            rbml_w,
-                            m,
-                            &item.attrs,
-                            item.id,
-                            item.name,
-                            &item.vis);
-      }
-      hir::ItemForeignMod(ref fm) => {
-        let _task = index.record(def_id, rbml_w);
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, 'n');
-        encode_name(rbml_w, item.name);
-
-        // Encode all the items in this module.
-        for foreign_item in &fm.items {
-            rbml_w.wr_tagged_u64(tag_mod_child,
-                                 def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id)));
-        }
-        encode_visibility(rbml_w, vis);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        rbml_w.end_tag();
-      }
-      hir::ItemTy(..) => {
-        let _task = index.record(def_id, rbml_w);
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, 'y');
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-        encode_name(rbml_w, item.name);
-        encode_visibility(rbml_w, vis);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        rbml_w.end_tag();
-      }
-      hir::ItemEnum(ref enum_definition, _) => {
-        let _task = index.record(def_id, rbml_w);
-
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, 't');
-        encode_item_variances(rbml_w, ecx, item.id);
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-        encode_name(rbml_w, item.name);
-        encode_attributes(rbml_w, &item.attrs);
-        encode_repr_attrs(rbml_w, ecx, &item.attrs);
-        for v in &enum_definition.variants {
-            encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id()));
-        }
-        encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
-        encode_mir(ecx, rbml_w, item.id);
-
-        // Encode inherent implementations for this enumeration.
-        encode_inherent_implementations(ecx, rbml_w, def_id);
-
-        encode_visibility(rbml_w, vis);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        rbml_w.end_tag();
+impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
+    fn encode_info_for_item(&mut self,
+                            (def_id, item): (DefId, &hir::Item)) {
+        let ecx = self.ecx();
+        let tcx = ecx.tcx;
 
-        encode_enum_variant_info(ecx,
-                                 rbml_w,
-                                 def_id,
-                                 vis,
-                                 index);
-      }
-      hir::ItemStruct(ref struct_def, _) => {
-        /* Index the class*/
-        let _task = index.record(def_id, rbml_w);
+        debug!("encoding info for item at {}",
+               tcx.sess.codemap().span_to_string(item.span));
 
-        let def = ecx.tcx.lookup_adt_def(def_id);
-        let variant = def.struct_variant();
+        let vis = &item.vis;
 
-        /* Now, make an item for the class itself */
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, match *struct_def {
-            hir::VariantData::Struct(..) => 'S',
-            hir::VariantData::Tuple(..) => 's',
-            hir::VariantData::Unit(..) => 'u',
+        let (stab, depr) = tcx.dep_graph.with_task(DepNode::MetaData(def_id), || {
+            (tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id)),
+             tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id)))
         });
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-
-        encode_item_variances(rbml_w, ecx, item.id);
-        encode_name(rbml_w, item.name);
-        encode_attributes(rbml_w, &item.attrs);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        encode_visibility(rbml_w, vis);
-        encode_repr_attrs(rbml_w, ecx, &item.attrs);
-
-        /* Encode def_ids for each field and method
-         for methods, write all the stuff get_trait_method
-        needs to know*/
-        encode_struct_fields(rbml_w, variant);
-
-        encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
-        encode_mir(ecx, rbml_w, item.id);
-
-        // Encode inherent implementations for this structure.
-        encode_inherent_implementations(ecx, rbml_w, def_id);
-
-        if !struct_def.is_struct() {
-            let ctor_did = ecx.tcx.map.local_def_id(struct_def.id());
-            rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor,
-                                 def_to_u64(ctor_did));
-        }
-
-        rbml_w.end_tag();
 
-        for field in &variant.fields {
-            encode_field(ecx, rbml_w, field, index);
-        }
-
-        // If this is a tuple-like struct, encode the type of the constructor.
-        if !struct_def.is_struct() {
-            encode_info_for_struct_ctor(ecx, rbml_w, item.name, struct_def, index, item.id);
-        }
-      }
-      hir::ItemDefaultImpl(unsafety, _) => {
-          let _task = index.record(def_id, rbml_w);
-          rbml_w.start_tag(tag_items_data_item);
-          encode_def_id_and_key(ecx, rbml_w, def_id);
-          encode_family(rbml_w, 'd');
-          encode_name(rbml_w, item.name);
-          encode_unsafety(rbml_w, unsafety);
-
-          let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap();
-          encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref);
-          rbml_w.end_tag();
-      }
-      hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => {
-        let _task = index.record(def_id, rbml_w);
-
-        // We need to encode information about the default methods we
-        // have inherited, so we drive this based on the impl structure.
-        let impl_items = tcx.impl_items.borrow();
-        let items = impl_items.get(&def_id).unwrap();
-
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, 'i');
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-        encode_name(rbml_w, item.name);
-        encode_attributes(rbml_w, &item.attrs);
-        encode_unsafety(rbml_w, unsafety);
-        encode_polarity(rbml_w, polarity);
-
-        match tcx.custom_coerce_unsized_kinds.borrow().get(&ecx.tcx.map.local_def_id(item.id)) {
-            Some(&kind) => {
-                rbml_w.start_tag(tag_impl_coerce_unsized_kind);
-                kind.encode(rbml_w);
-                rbml_w.end_tag();
+        match item.node {
+            hir::ItemStatic(_, m, _) => {
+                encode_def_id_and_key(ecx, self.rbml_w, def_id);
+                if m == hir::MutMutable {
+                    encode_family(self.rbml_w, 'b');
+                } else {
+                    encode_family(self.rbml_w, 'c');
+                }
+                self.encode_bounds_and_type_for_item(item.id);
+                encode_name(self.rbml_w, item.name);
+                self.encode_visibility(vis);
+                encode_stability(self.rbml_w, stab);
+                encode_deprecation(self.rbml_w, depr);
+                encode_attributes(self.rbml_w, &item.attrs);
             }
-            None => {}
-        }
-
-        for &item_def_id in items {
-            rbml_w.start_tag(tag_item_impl_item);
-            match item_def_id {
-                ty::ConstTraitItemId(item_def_id) => {
-                    encode_def_id(rbml_w, item_def_id);
-                    encode_item_sort(rbml_w, 'C');
+            hir::ItemConst(_, _) => {
+                encode_def_id_and_key(ecx, self.rbml_w, def_id);
+                encode_family(self.rbml_w, 'C');
+                self.encode_bounds_and_type_for_item(item.id);
+                encode_name(self.rbml_w, item.name);
+                encode_attributes(self.rbml_w, &item.attrs);
+                encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item));
+                self.encode_mir(item.id);
+                self.encode_visibility(vis);
+                encode_stability(self.rbml_w, stab);
+                encode_deprecation(self.rbml_w, depr);
+            }
+            hir::ItemFn(ref decl, _, constness, _, ref generics, _) => {
+                encode_def_id_and_key(ecx, self.rbml_w, def_id);
+                encode_family(self.rbml_w, FN_FAMILY);
+                let tps_len = generics.ty_params.len();
+                self.encode_bounds_and_type_for_item(item.id);
+                encode_name(self.rbml_w, item.name);
+                encode_attributes(self.rbml_w, &item.attrs);
+                let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs);
+                if constness == hir::Constness::Const {
+                    encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item));
                 }
-                ty::MethodTraitItemId(item_def_id) => {
-                    encode_def_id(rbml_w, item_def_id);
-                    encode_item_sort(rbml_w, 'r');
+                if needs_inline || constness == hir::Constness::Const {
+                    self.encode_mir(item.id);
                 }
-                ty::TypeTraitItemId(item_def_id) => {
-                    encode_def_id(rbml_w, item_def_id);
-                    encode_item_sort(rbml_w, 't');
+                encode_constness(self.rbml_w, constness);
+                self.encode_visibility(vis);
+                encode_stability(self.rbml_w, stab);
+                encode_deprecation(self.rbml_w, depr);
+                self.encode_method_argument_names(&decl);
+            }
+            hir::ItemMod(ref m) => {
+                self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, item.name, &item.vis)));
+            }
+            hir::ItemForeignMod(ref fm) => {
+                encode_def_id_and_key(ecx, self.rbml_w, def_id);
+                encode_family(self.rbml_w, 'n');
+                encode_name(self.rbml_w, item.name);
+
+                // Encode all the items in self module.
+                for foreign_item in &fm.items {
+                    self.rbml_w.wr_tagged_u64(
+                        tag_mod_child,
+                        def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id)));
                 }
+                self.encode_visibility(vis);
+                encode_stability(self.rbml_w, stab);
+                encode_deprecation(self.rbml_w, depr);
             }
-            rbml_w.end_tag();
-        }
-        let did = ecx.tcx.map.local_def_id(item.id);
-        if let Some(trait_ref) = tcx.impl_trait_ref(did) {
-            encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref);
-
-            let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
-            let parent = trait_def.ancestors(did)
-                .skip(1)
-                .next()
-                .and_then(|node| match node {
-                    specialization_graph::Node::Impl(parent) => Some(parent),
-                    _ => None,
-                });
-            encode_parent_impl(rbml_w, parent);
-        }
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        rbml_w.end_tag();
+            hir::ItemTy(..) => {
+                encode_def_id_and_key(ecx, self.rbml_w, def_id);
+                encode_family(self.rbml_w, 'y');
+                self.encode_bounds_and_type_for_item(item.id);
+                encode_name(self.rbml_w, item.name);
+                self.encode_visibility(vis);
+                encode_stability(self.rbml_w, stab);
+                encode_deprecation(self.rbml_w, depr);
+            }
+            hir::ItemEnum(ref enum_definition, _) => {
+                encode_def_id_and_key(ecx, self.rbml_w, def_id);
+                encode_family(self.rbml_w, 't');
+                encode_item_variances(self.rbml_w, ecx, item.id);
+                self.encode_bounds_and_type_for_item(item.id);
+                encode_name(self.rbml_w, item.name);
+                encode_attributes(self.rbml_w, &item.attrs);
+                self.encode_repr_attrs(&item.attrs);
+                for v in &enum_definition.variants {
+                    encode_variant_id(self.rbml_w, ecx.tcx.map.local_def_id(v.node.data.id()));
+                }
 
-        // Iterate down the trait items, emitting them. We rely on the
-        // assumption that all of the actually implemented trait items
-        // appear first in the impl structure, in the same order they do
-        // in the ast. This is a little sketchy.
-        let num_implemented_methods = ast_items.len();
-        for (i, &trait_item_def_id) in items.iter().enumerate() {
-            let ast_item = if i < num_implemented_methods {
-                Some(&ast_items[i])
-            } else {
-                None
-            };
+                // Encode inherent implementations for self enumeration.
+                encode_inherent_implementations(ecx, self.rbml_w, def_id);
 
-            match tcx.impl_or_trait_item(trait_item_def_id.def_id()) {
-                ty::ConstTraitItem(ref associated_const) => {
-                    encode_info_for_associated_const(ecx,
-                                                     rbml_w,
-                                                     index,
-                                                     &associated_const,
-                                                     item.id,
-                                                     ast_item)
-                }
-                ty::MethodTraitItem(ref method_type) => {
-                    encode_info_for_method(ecx,
-                                           rbml_w,
-                                           index,
-                                           &method_type,
-                                           false,
-                                           item.id,
-                                           ast_item)
-                }
-                ty::TypeTraitItem(ref associated_type) => {
-                    encode_info_for_associated_type(ecx,
-                                                    rbml_w,
-                                                    index,
-                                                    &associated_type,
-                                                    item.id,
-                                                    ast_item)
-                }
+                self.encode_visibility(vis);
+                encode_stability(self.rbml_w, stab);
+                encode_deprecation(self.rbml_w, depr);
             }
-        }
-      }
-      hir::ItemTrait(_, _, _, ref ms) => {
-        let _task = index.record(def_id, rbml_w);
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, 'I');
-        encode_item_variances(rbml_w, ecx, item.id);
-        let trait_def = tcx.lookup_trait_def(def_id);
-        let trait_predicates = tcx.lookup_predicates(def_id);
-        encode_unsafety(rbml_w, trait_def.unsafety);
-        encode_paren_sugar(rbml_w, trait_def.paren_sugar);
-        encode_defaulted(rbml_w, tcx.trait_has_default_impl(def_id));
-        encode_associated_type_names(rbml_w, &trait_def.associated_type_names);
-        encode_generics(rbml_w, ecx, index,
-                        &trait_def.generics, &trait_predicates);
-        encode_predicates(rbml_w, index,
-                          &tcx.lookup_super_predicates(def_id),
-                          tag_item_super_predicates);
-        encode_trait_ref(rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref);
-        encode_name(rbml_w, item.name);
-        encode_attributes(rbml_w, &item.attrs);
-        encode_visibility(rbml_w, vis);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        for &method_def_id in tcx.trait_item_def_ids(def_id).iter() {
-            rbml_w.start_tag(tag_item_trait_item);
-            match method_def_id {
-                ty::ConstTraitItemId(const_def_id) => {
-                    encode_def_id(rbml_w, const_def_id);
-                    encode_item_sort(rbml_w, 'C');
-                }
-                ty::MethodTraitItemId(method_def_id) => {
-                    encode_def_id(rbml_w, method_def_id);
-                    encode_item_sort(rbml_w, 'r');
-                }
-                ty::TypeTraitItemId(type_def_id) => {
-                    encode_def_id(rbml_w, type_def_id);
-                    encode_item_sort(rbml_w, 't');
+            hir::ItemStruct(ref struct_def, _) => {
+                /* Index the class*/
+                let def = ecx.tcx.lookup_adt_def(def_id);
+                let variant = def.struct_variant();
+
+                /* Now, make an item for the class itself */
+                encode_def_id_and_key(ecx, self.rbml_w, def_id);
+                encode_family(self.rbml_w, match *struct_def {
+                    hir::VariantData::Struct(..) => 'S',
+                    hir::VariantData::Tuple(..) => 's',
+                    hir::VariantData::Unit(..) => 'u',
+                });
+                self.encode_bounds_and_type_for_item(item.id);
+
+                encode_item_variances(self.rbml_w, ecx, item.id);
+                encode_name(self.rbml_w, item.name);
+                encode_attributes(self.rbml_w, &item.attrs);
+                encode_stability(self.rbml_w, stab);
+                encode_deprecation(self.rbml_w, depr);
+                self.encode_visibility(vis);
+                self.encode_repr_attrs(&item.attrs);
+
+                /* Encode def_ids for each field and method
+                for methods, write all the stuff get_trait_method
+                needs to know*/
+                self.encode_struct_fields(variant);
+
+                // Encode inherent implementations for self structure.
+                encode_inherent_implementations(ecx, self.rbml_w, def_id);
+
+                if !struct_def.is_struct() {
+                    let ctor_did = ecx.tcx.map.local_def_id(struct_def.id());
+                    self.rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor,
+                                              def_to_u64(ctor_did));
                 }
             }
-            rbml_w.end_tag();
-
-            rbml_w.wr_tagged_u64(tag_mod_child,
-                                 def_to_u64(method_def_id.def_id()));
-        }
-
-        // Encode inherent implementations for this trait.
-        encode_inherent_implementations(ecx, rbml_w, def_id);
-
-        rbml_w.end_tag();
-
-        // Now output the trait item info for each trait item.
-        let r = tcx.trait_item_def_ids(def_id);
-        for (i, &item_def_id) in r.iter().enumerate() {
-            assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE);
-
-            let _task = index.record(item_def_id.def_id(), rbml_w);
-            rbml_w.start_tag(tag_items_data_item);
-
-            encode_parent_item(rbml_w, def_id);
-
-            let stab = tcx.lookup_stability(item_def_id.def_id());
-            let depr = tcx.lookup_deprecation(item_def_id.def_id());
-            encode_stability(rbml_w, stab);
-            encode_deprecation(rbml_w, depr);
-
-            let trait_item_type =
-                tcx.impl_or_trait_item(item_def_id.def_id());
-            let is_nonstatic_method;
-            match trait_item_type {
-                ty::ConstTraitItem(associated_const) => {
-                    encode_name(rbml_w, associated_const.name);
-                    encode_def_id_and_key(ecx, rbml_w, associated_const.def_id);
-                    encode_visibility(rbml_w, associated_const.vis);
-
-                    encode_family(rbml_w, 'C');
-
-                    encode_bounds_and_type_for_item(rbml_w, ecx, index,
-                                                    ecx.local_id(associated_const.def_id));
-
-                    is_nonstatic_method = false;
+            hir::ItemDefaultImpl(unsafety, _) => {
+                encode_def_id_and_key(ecx, self.rbml_w, def_id);
+                encode_family(self.rbml_w, 'd');
+                encode_name(self.rbml_w, item.name);
+                encode_unsafety(self.rbml_w, unsafety);
+
+                let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap();
+                encode_trait_ref(self.rbml_w, ecx, trait_ref, tag_item_trait_ref);
+            }
+            hir::ItemImpl(unsafety, polarity, _, _, _, _) => {
+                // We need to encode information about the default methods we
+                // have inherited, so we drive self based on the impl structure.
+                let impl_items = tcx.impl_items.borrow();
+                let items = &impl_items[&def_id];
+
+                encode_def_id_and_key(ecx, self.rbml_w, def_id);
+                encode_family(self.rbml_w, 'i');
+                self.encode_bounds_and_type_for_item(item.id);
+                encode_name(self.rbml_w, item.name);
+                encode_attributes(self.rbml_w, &item.attrs);
+                encode_unsafety(self.rbml_w, unsafety);
+                encode_polarity(self.rbml_w, polarity);
+
+                match
+                    tcx.custom_coerce_unsized_kinds
+                       .borrow()
+                       .get(&ecx.tcx.map.local_def_id(item.id))
+                {
+                    Some(&kind) => {
+                        self.rbml_w.start_tag(tag_impl_coerce_unsized_kind);
+                        kind.encode(self.rbml_w);
+                        self.rbml_w.end_tag();
+                    }
+                    None => {}
                 }
-                ty::MethodTraitItem(method_ty) => {
-                    let method_def_id = item_def_id.def_id();
 
-                    encode_method_ty_fields(ecx, rbml_w, index, &method_ty);
-
-                    match method_ty.explicit_self {
-                        ty::ExplicitSelfCategory::Static => {
-                            encode_family(rbml_w,
-                                          STATIC_METHOD_FAMILY);
+                for &item_def_id in items {
+                    self.rbml_w.start_tag(tag_item_impl_item);
+                    match item_def_id {
+                        ty::ConstTraitItemId(item_def_id) => {
+                            encode_def_id(self.rbml_w, item_def_id);
+                            encode_item_sort(self.rbml_w, 'C');
+                        }
+                        ty::MethodTraitItemId(item_def_id) => {
+                            encode_def_id(self.rbml_w, item_def_id);
+                            encode_item_sort(self.rbml_w, 'r');
                         }
-                        _ => {
-                            encode_family(rbml_w,
-                                          METHOD_FAMILY);
+                        ty::TypeTraitItemId(item_def_id) => {
+                            encode_def_id(self.rbml_w, item_def_id);
+                            encode_item_sort(self.rbml_w, 't');
                         }
                     }
-                    encode_bounds_and_type_for_item(rbml_w, ecx, index,
-                                                    ecx.local_id(method_def_id));
-
-                    is_nonstatic_method = method_ty.explicit_self !=
-                        ty::ExplicitSelfCategory::Static;
+                    self.rbml_w.end_tag();
                 }
-                ty::TypeTraitItem(associated_type) => {
-                    encode_name(rbml_w, associated_type.name);
-                    encode_def_id_and_key(ecx, rbml_w, associated_type.def_id);
-                    encode_item_sort(rbml_w, 't');
-                    encode_family(rbml_w, 'y');
-
-                    if let Some(ty) = associated_type.ty {
-                        encode_type(ecx, rbml_w, ty);
-                    }
 
-                    is_nonstatic_method = false;
+                let did = ecx.tcx.map.local_def_id(item.id);
+                if let Some(trait_ref) = tcx.impl_trait_ref(did) {
+                    encode_trait_ref(self.rbml_w, ecx, trait_ref, tag_item_trait_ref);
+
+                    let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
+                    let parent = trait_def.ancestors(did)
+                                          .skip(1)
+                                          .next()
+                                          .and_then(|node| match node {
+                                              specialization_graph::Node::Impl(parent) =>
+                                                  Some(parent),
+                                              _ => None,
+                                          });
+                    encode_parent_impl(self.rbml_w, parent);
                 }
+                encode_stability(self.rbml_w, stab);
+                encode_deprecation(self.rbml_w, depr);
             }
-
-            let trait_item = &ms[i];
-            encode_attributes(rbml_w, &trait_item.attrs);
-            match trait_item.node {
-                hir::ConstTraitItem(_, ref default) => {
-                    if default.is_some() {
-                        encode_item_sort(rbml_w, 'C');
-                    } else {
-                        encode_item_sort(rbml_w, 'c');
+            hir::ItemTrait(_, _, _, _) => {
+                encode_def_id_and_key(ecx, self.rbml_w, def_id);
+                encode_family(self.rbml_w, 'I');
+                encode_item_variances(self.rbml_w, ecx, item.id);
+                let trait_def = tcx.lookup_trait_def(def_id);
+                let trait_predicates = tcx.lookup_predicates(def_id);
+                encode_unsafety(self.rbml_w, trait_def.unsafety);
+                encode_paren_sugar(self.rbml_w, trait_def.paren_sugar);
+                encode_defaulted(self.rbml_w, tcx.trait_has_default_impl(def_id));
+                encode_associated_type_names(self.rbml_w, &trait_def.associated_type_names);
+                self.encode_generics(&trait_def.generics, &trait_predicates);
+                self.encode_predicates(&tcx.lookup_super_predicates(def_id),
+                                       tag_item_super_predicates);
+                encode_trait_ref(self.rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref);
+                encode_name(self.rbml_w, item.name);
+                encode_attributes(self.rbml_w, &item.attrs);
+                self.encode_visibility(vis);
+                encode_stability(self.rbml_w, stab);
+                encode_deprecation(self.rbml_w, depr);
+                for &method_def_id in tcx.trait_item_def_ids(def_id).iter() {
+                    self.rbml_w.start_tag(tag_item_trait_item);
+                    match method_def_id {
+                        ty::ConstTraitItemId(const_def_id) => {
+                            encode_def_id(self.rbml_w, const_def_id);
+                            encode_item_sort(self.rbml_w, 'C');
+                        }
+                        ty::MethodTraitItemId(method_def_id) => {
+                            encode_def_id(self.rbml_w, method_def_id);
+                            encode_item_sort(self.rbml_w, 'r');
+                        }
+                        ty::TypeTraitItemId(type_def_id) => {
+                            encode_def_id(self.rbml_w, type_def_id);
+                            encode_item_sort(self.rbml_w, 't');
+                        }
                     }
+                    self.rbml_w.end_tag();
 
-                    encode_inlined_item(ecx, rbml_w,
-                                        InlinedItemRef::TraitItem(def_id, trait_item));
-                    encode_mir(ecx, rbml_w, trait_item.id);
+                    self.rbml_w.wr_tagged_u64(tag_mod_child,
+                                              def_to_u64(method_def_id.def_id()));
                 }
-                hir::MethodTraitItem(ref sig, ref body) => {
-                    // If this is a static method, we've already
-                    // encoded this.
-                    if is_nonstatic_method {
-                        // FIXME: I feel like there is something funny
-                        // going on.
-                        encode_bounds_and_type_for_item(rbml_w, ecx, index,
-                                                        ecx.local_id(item_def_id.def_id()));
-                    }
 
-                    if body.is_some() {
-                        encode_item_sort(rbml_w, 'p');
-                        encode_inlined_item(ecx, rbml_w,
-                                            InlinedItemRef::TraitItem(def_id, trait_item));
-                        encode_mir(ecx, rbml_w, trait_item.id);
-                    } else {
-                        encode_item_sort(rbml_w, 'r');
-                    }
-                    encode_method_argument_names(rbml_w, &sig.decl);
-                }
-
-                hir::TypeTraitItem(..) => {}
+                // Encode inherent implementations for self trait.
+                encode_inherent_implementations(ecx, self.rbml_w, def_id);
+            }
+            hir::ItemExternCrate(_) | hir::ItemUse(_) => {
+                bug!("cannot encode info for item {:?}", item)
             }
-
-            rbml_w.end_tag();
-        }
-      }
-      hir::ItemExternCrate(_) | hir::ItemUse(_) => {
-        // these are encoded separately
-      }
-    }
-}
-
-fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                          rbml_w: &mut Encoder,
-                                          nitem: &hir::ForeignItem,
-                                          index: &mut CrateIndex<'a, 'tcx>) {
-    debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id));
-    let def_id = ecx.tcx.map.local_def_id(nitem.id);
-    let abi = ecx.tcx.map.get_foreign_abi(nitem.id);
-
-    let _task = index.record(def_id, rbml_w);
-    rbml_w.start_tag(tag_items_data_item);
-    encode_def_id_and_key(ecx, rbml_w, def_id);
-    let parent_id = ecx.tcx.map.get_parent(nitem.id);
-    encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
-    encode_visibility(rbml_w, &nitem.vis);
-    match nitem.node {
-      hir::ForeignItemFn(ref fndecl, _) => {
-        encode_family(rbml_w, FN_FAMILY);
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id);
-        encode_name(rbml_w, nitem.name);
-        if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
-            encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(def_id, nitem));
-            encode_mir(ecx, rbml_w, nitem.id);
-        }
-        encode_attributes(rbml_w, &nitem.attrs);
-        let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id));
-        let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id));
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        encode_method_argument_names(rbml_w, &fndecl);
-      }
-      hir::ForeignItemStatic(_, mutbl) => {
-        if mutbl {
-            encode_family(rbml_w, 'b');
-        } else {
-            encode_family(rbml_w, 'c');
         }
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id);
-        encode_attributes(rbml_w, &nitem.attrs);
-        let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id));
-        let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id));
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        encode_name(rbml_w, nitem.name);
-      }
     }
-    rbml_w.end_tag();
 }
 
-fn my_visit_expr(expr: &hir::Expr,
-                 rbml_w: &mut Encoder,
-                 ecx: &EncodeContext,
-                 index: &mut CrateIndex) {
-    match expr.node {
-        hir::ExprClosure(..) => {
-            let def_id = ecx.tcx.map.local_def_id(expr.id);
+impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
+    /// In some cases, along with the item itself, we also
+    /// encode some sub-items. Usually we want some info from the item
+    /// so it's easier to do that here then to wait until we would encounter
+    /// normally in the visitor walk.
+    fn encode_addl_info_for_item(&mut self,
+                                 item: &hir::Item) {
+        let def_id = self.ecx().tcx.map.local_def_id(item.id);
+        match item.node {
+            hir::ItemStatic(..) |
+            hir::ItemConst(..) |
+            hir::ItemFn(..) |
+            hir::ItemMod(..) |
+            hir::ItemForeignMod(..) |
+            hir::ItemExternCrate(..) |
+            hir::ItemUse(..) |
+            hir::ItemDefaultImpl(..) |
+            hir::ItemTy(..) => {
+                // no sub-item recording needed in these cases
+            }
+            hir::ItemEnum(..) => {
+                self.encode_enum_variant_infos(def_id);
+            }
+            hir::ItemStruct(ref struct_def, _) => {
+                self.encode_addl_struct_info(def_id, struct_def.id(), item);
+            }
+            hir::ItemImpl(_, _, _, _, _, ref ast_items) => {
+                self.encode_addl_impl_info(def_id, item.id, ast_items);
+            }
+            hir::ItemTrait(_, _, _, ref trait_items) => {
+                self.encode_addl_trait_info(def_id, trait_items);
+            }
+        }
+    }
 
-            let _task = index.record(def_id, rbml_w);
+    fn encode_addl_struct_info(&mut self,
+                               def_id: DefId,
+                               struct_node_id: ast::NodeId,
+                               item: &hir::Item) {
+        let ecx = self.ecx();
+        let def = ecx.tcx.lookup_adt_def(def_id);
+        let variant = def.struct_variant();
 
-            rbml_w.start_tag(tag_items_data_item);
-            encode_def_id_and_key(ecx, rbml_w, def_id);
-            encode_name(rbml_w, syntax::parse::token::intern("<closure>"));
+        self.encode_fields(def_id);
 
-            rbml_w.start_tag(tag_items_closure_ty);
-            write_closure_type(ecx, rbml_w, &ecx.tcx.tables.borrow().closure_tys[&def_id]);
-            rbml_w.end_tag();
+        // If this is a tuple-like struct, encode the type of the constructor.
+        match variant.kind {
+            ty::VariantKind::Struct => {
+                // no value for structs like struct Foo { ... }
+            }
+            ty::VariantKind::Tuple | ty::VariantKind::Unit => {
+                // there is a value for structs like `struct
+                // Foo()` and `struct Foo`
+                let ctor_def_id = ecx.tcx.map.local_def_id(struct_node_id);
+                self.record(ctor_def_id,
+                            ItemContentBuilder::encode_struct_ctor,
+                            (def_id, item.id, struct_node_id));
+            }
+        }
+    }
+
+    fn encode_addl_impl_info(&mut self,
+                             def_id: DefId,
+                             impl_id: ast::NodeId,
+                             ast_items: &[hir::ImplItem]) {
+        let ecx = self.ecx();
+        let impl_items = ecx.tcx.impl_items.borrow();
+        let items = &impl_items[&def_id];
+
+        // Iterate down the trait items, emitting them. We rely on the
+        // assumption that all of the actually implemented trait items
+        // appear first in the impl structure, in the same order they do
+        // in the ast. This is a little sketchy.
+        let num_implemented_methods = ast_items.len();
+        for (i, &trait_item_def_id) in items.iter().enumerate() {
+            let ast_item = if i < num_implemented_methods {
+                Some(&ast_items[i])
+            } else {
+                None
+            };
 
-            rbml_w.start_tag(tag_items_closure_kind);
-            ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap();
-            rbml_w.end_tag();
+            let trait_item_def_id = trait_item_def_id.def_id();
+            self.record(trait_item_def_id,
+                        ItemContentBuilder::encode_info_for_impl_item,
+                        (impl_id, trait_item_def_id, ast_item));
+        }
+    }
 
-            assert!(ecx.mir_map.map.contains_key(&def_id));
-            encode_mir(ecx, rbml_w, expr.id);
+    fn encode_addl_trait_info(&mut self,
+                              def_id: DefId,
+                              trait_items: &[hir::TraitItem]) {
+        // Now output the trait item info for each trait item.
+        let tcx = self.ecx().tcx;
+        let r = tcx.trait_item_def_ids(def_id);
+        for (item_def_id, trait_item) in r.iter().zip(trait_items) {
+            let item_def_id = item_def_id.def_id();
+            assert!(item_def_id.is_local());
+            self.record(item_def_id,
+                        ItemContentBuilder::encode_info_for_trait_item,
+                        (def_id, item_def_id, trait_item));
+        }
+    }
+}
 
-            rbml_w.end_tag();
+impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
+    fn encode_info_for_foreign_item(&mut self,
+                                    (def_id, nitem): (DefId, &hir::ForeignItem)) {
+        let ecx = self.ecx();
+
+        debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id));
+
+        encode_def_id_and_key(ecx, self.rbml_w, def_id);
+        let parent_id = ecx.tcx.map.get_parent(nitem.id);
+        self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id));
+        self.encode_visibility(&nitem.vis);
+        match nitem.node {
+            hir::ForeignItemFn(ref fndecl, _) => {
+                encode_family(self.rbml_w, FN_FAMILY);
+                self.encode_bounds_and_type_for_item(nitem.id);
+                encode_name(self.rbml_w, nitem.name);
+                encode_attributes(self.rbml_w, &nitem.attrs);
+                let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id));
+                let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id));
+                encode_stability(self.rbml_w, stab);
+                encode_deprecation(self.rbml_w, depr);
+                self.encode_method_argument_names(&fndecl);
+            }
+            hir::ForeignItemStatic(_, mutbl) => {
+                if mutbl {
+                    encode_family(self.rbml_w, 'b');
+                } else {
+                    encode_family(self.rbml_w, 'c');
+                }
+                self.encode_bounds_and_type_for_item(nitem.id);
+                encode_attributes(self.rbml_w, &nitem.attrs);
+                let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id));
+                let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id));
+                encode_stability(self.rbml_w, stab);
+                encode_deprecation(self.rbml_w, depr);
+                encode_name(self.rbml_w, nitem.name);
+            }
         }
-        _ => { }
     }
 }
 
-struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> {
-    rbml_w_for_visit_item: &'a mut Encoder<'b>,
-    ecx: &'a EncodeContext<'c, 'tcx>,
-    index: &'a mut CrateIndex<'c, 'tcx>,
+struct EncodeVisitor<'a, 'ecx: 'a, 'tcx: 'ecx, 'encoder: 'ecx> {
+    index: &'a mut IndexBuilder<'ecx, 'tcx, 'encoder>,
 }
 
-impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> {
+impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, 'encoder> {
     fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
         intravisit::walk_expr(self, ex);
-        my_visit_expr(ex, self.rbml_w_for_visit_item, self.ecx, self.index);
+        self.index.encode_info_for_expr(ex);
     }
-    fn visit_item(&mut self, i: &'tcx hir::Item) {
-        intravisit::walk_item(self, i);
-        encode_info_for_item(self.ecx, self.rbml_w_for_visit_item, i, self.index);
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
+        intravisit::walk_item(self, item);
+        let def_id = self.index.ecx().tcx.map.local_def_id(item.id);
+        match item.node {
+            hir::ItemExternCrate(_) | hir::ItemUse(_) => (), // ignore these
+            _ => self.index.record(def_id,
+                                   ItemContentBuilder::encode_info_for_item,
+                                   (def_id, item)),
+        }
+        self.index.encode_addl_info_for_item(item);
     }
     fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) {
         intravisit::walk_foreign_item(self, ni);
-        encode_info_for_foreign_item(self.ecx, self.rbml_w_for_visit_item, ni, self.index);
+        let def_id = self.index.ecx().tcx.map.local_def_id(ni.id);
+        self.index.record(def_id,
+                          ItemContentBuilder::encode_info_for_foreign_item,
+                          (def_id, ni));
     }
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
         intravisit::walk_ty(self, ty);
+        self.index.encode_info_for_ty(ty);
+    }
+}
 
+impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
+    fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
+        let ecx = self.ecx();
         if let hir::TyImplTrait(_) = ty.node {
-            let rbml_w = &mut *self.rbml_w_for_visit_item;
-            let def_id = self.ecx.tcx.map.local_def_id(ty.id);
-            let _task = self.index.record(def_id, rbml_w);
-            rbml_w.start_tag(tag_items_data_item);
-            encode_def_id_and_key(self.ecx, rbml_w, def_id);
-            encode_family(rbml_w, 'y');
-            encode_bounds_and_type_for_item(rbml_w, self.ecx, self.index, ty.id);
-            rbml_w.end_tag();
+            let def_id = ecx.tcx.map.local_def_id(ty.id);
+            self.record(def_id,
+                        ItemContentBuilder::encode_info_for_anon_ty,
+                        (def_id, ty.id));
+        }
+    }
+
+    fn encode_info_for_expr(&mut self, expr: &hir::Expr) {
+        let ecx = self.ecx();
+
+        match expr.node {
+            hir::ExprClosure(..) => {
+                let def_id = ecx.tcx.map.local_def_id(expr.id);
+                self.record(def_id,
+                            ItemContentBuilder::encode_info_for_closure,
+                            (def_id, expr.id));
+            }
+            _ => { }
         }
     }
 }
 
+impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
+    fn encode_info_for_anon_ty(&mut self, (def_id, ty_id): (DefId, NodeId)) {
+        let ecx = self.ecx;
+        encode_def_id_and_key(ecx, self.rbml_w, def_id);
+        encode_family(self.rbml_w, 'y');
+        self.encode_bounds_and_type_for_item(ty_id);
+    }
+
+    fn encode_info_for_closure(&mut self, (def_id, expr_id): (DefId, NodeId)) {
+        let ecx = self.ecx;
+        encode_def_id_and_key(ecx, self.rbml_w, def_id);
+        encode_name(self.rbml_w, syntax::parse::token::intern("<closure>"));
+
+        self.rbml_w.start_tag(tag_items_closure_ty);
+        write_closure_type(ecx,
+                           self.rbml_w,
+                           &ecx.tcx.tables.borrow().closure_tys[&def_id]);
+        self.rbml_w.end_tag();
+
+        self.rbml_w.start_tag(tag_items_closure_kind);
+        ecx.tcx.closure_kind(def_id).encode(self.rbml_w).unwrap();
+        self.rbml_w.end_tag();
+
+        assert!(ecx.mir_map.map.contains_key(&def_id));
+        self.encode_mir(expr_id);
+    }
+}
+
 fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                    rbml_w: &mut Encoder)
-                                   -> CrateIndex<'a, 'tcx> {
+                                   -> (IndexData, FnvHashMap<XRef<'tcx>, u32>) {
     let krate = ecx.tcx.map.krate();
 
-    let mut index = CrateIndex {
-        dep_graph: &ecx.tcx.dep_graph,
-        items: IndexData::new(ecx.tcx.map.num_local_def_ids()),
-        xrefs: FnvHashMap()
-    };
     rbml_w.start_tag(tag_items_data);
 
-    {
-        let _task = index.record(DefId::local(CRATE_DEF_INDEX), rbml_w);
-        encode_info_for_mod(ecx,
-                            rbml_w,
-                            &krate.module,
-                            &[],
-                            CRATE_NODE_ID,
-                            syntax::parse::token::intern(&ecx.link_meta.crate_name),
-                            &hir::Public);
-    }
-
-    krate.visit_all_items(&mut EncodeVisitor {
-        index: &mut index,
-        ecx: ecx,
-        rbml_w_for_visit_item: &mut *rbml_w,
-    });
+    let fields = {
+        let mut index = IndexBuilder::new(ecx, rbml_w);
+        index.record(DefId::local(CRATE_DEF_INDEX),
+                     ItemContentBuilder::encode_info_for_mod,
+                     FromId(CRATE_NODE_ID, (&krate.module,
+                                            &[],
+                                            syntax::parse::token::intern(&ecx.link_meta.crate_name),
+                                            &hir::Public)));
+        krate.visit_all_items(&mut EncodeVisitor {
+            index: &mut index,
+        });
+        index.into_fields()
+    };
 
     rbml_w.end_tag();
-    index
+
+    fields
 }
 
 fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) {
@@ -1414,40 +1417,11 @@ fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) {
     rbml_w.end_tag();
 }
 
-fn encode_meta_item(rbml_w: &mut Encoder, mi: &ast::MetaItem) {
-    if mi.is_word() {
-        let name = mi.name();
-        rbml_w.start_tag(tag_meta_item_word);
-        rbml_w.wr_tagged_str(tag_meta_item_name, &name);
-        rbml_w.end_tag();
-    } else if mi.is_value_str() {
-        let name = mi.name();
-        /* FIXME (#623): support other literal kinds */
-        let value = mi.value_str().unwrap();
-        rbml_w.start_tag(tag_meta_item_name_value);
-        rbml_w.wr_tagged_str(tag_meta_item_name, &name);
-        rbml_w.wr_tagged_str(tag_meta_item_value, &value);
-        rbml_w.end_tag();
-    } else { // it must be a list
-        let name = mi.name();
-        let items = mi.meta_item_list().unwrap();
-        rbml_w.start_tag(tag_meta_item_list);
-        rbml_w.wr_tagged_str(tag_meta_item_name, &name);
-        for inner_item in items {
-            encode_meta_item(rbml_w, &inner_item);
-        }
-        rbml_w.end_tag();
-    }
-}
-
 fn encode_attributes(rbml_w: &mut Encoder, attrs: &[ast::Attribute]) {
     rbml_w.start_tag(tag_attributes);
-    for attr in attrs {
-        rbml_w.start_tag(tag_attribute);
-        rbml_w.wr_tagged_u8(tag_attribute_is_sugared_doc, attr.node.is_sugared_doc as u8);
-        encode_meta_item(rbml_w, attr.meta());
-        rbml_w.end_tag();
-    }
+    rbml_w.emit_opaque(|opaque_encoder| {
+        attrs.encode(opaque_encoder)
+    }).unwrap();
     rbml_w.end_tag();
 }
 
@@ -1925,16 +1899,16 @@ struct Stats {
     // Encode and index the items.
     rbml_w.start_tag(tag_items);
     i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    let index = encode_info_for_items(&ecx, rbml_w);
+    let (items, xrefs) = encode_info_for_items(&ecx, rbml_w);
     stats.item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
     rbml_w.end_tag();
 
     i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_item_index(rbml_w, index.items);
+    encode_item_index(rbml_w, items);
     stats.index_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
 
     i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_xrefs(&ecx, rbml_w, index.xrefs);
+    encode_xrefs(&ecx, rbml_w, xrefs);
     stats.xref_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
 
     encode_struct_field_attrs(&ecx, rbml_w, krate);
diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs
new file mode 100644 (file)
index 0000000..1d3d09d
--- /dev/null
@@ -0,0 +1,253 @@
+// 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.
+
+//! Builder types for generating the "item data" section of the
+//! metadata. This section winds up looking like this:
+//!
+//! ```
+//! <common::data> // big list of item-like things...
+//!    <common::data_item> // ...for most def-ids, there is an entry.
+//!    </common::data_item>
+//! </common::data>
+//! ```
+//!
+//! As we generate this listing, we collect the offset of each
+//! `data_item` entry and store it in an index. Then, when we load the
+//! metadata, we can skip right to the metadata for a particular item.
+//!
+//! In addition to the offset, we need to track the data that was used
+//! to generate the contents of each `data_item`. This is so that we
+//! can figure out which HIR nodes contributed to that data for
+//! incremental compilation purposes.
+//!
+//! The `IndexBuilder` facilitates both of these. It is created
+//! with an RBML encoder isntance (`rbml_w`) along with an
+//! `EncodingContext` (`ecx`), which it encapsulates. It has one main
+//! method, `record()`. You invoke `record` like so to create a new
+//! `data_item` element in the list:
+//!
+//! ```
+//! index.record(some_def_id, callback_fn, data)
+//! ```
+//!
+//! What record will do is to (a) record the current offset, (b) emit
+//! the `common::data_item` tag, and then call `callback_fn` with the
+//! given data as well as an `ItemContentBuilder`. Once `callback_fn`
+//! returns, the `common::data_item` tag will be closed.
+//!
+//! The `ItemContentBuilder` is another type that just offers access
+//! to the `ecx` and `rbml_w` that were given in, as well as
+//! maintaining a list of `xref` instances, which are used to extract
+//! common data so it is not re-serialized.
+//!
+//! `ItemContentBuilder` is a distinct type which does not offer the
+//! `record` method, so that we can ensure that `common::data_item` elements
+//! are never nested.
+//!
+//! In addition, while the `callback_fn` is executing, we will push a
+//! task `MetaData(some_def_id)`, which can then observe the
+//! reads/writes that occur in the task. For this reason, the `data`
+//! argument that is given to the `callback_fn` must implement the
+//! trait `DepGraphRead`, which indicates how to register reads on the
+//! data in this new task (note that many types of data, such as
+//! `DefId`, do not currently require any reads to be registered,
+//! since they are not derived from a HIR node). This is also why we
+//! give a callback fn, rather than taking a closure: it allows us to
+//! easily control precisely what data is given to that fn.
+
+use common::tag_items_data_item;
+use encoder::EncodeContext;
+use index::IndexData;
+use rbml::writer::Encoder;
+use rustc::dep_graph::DepNode;
+use rustc::hir;
+use rustc::hir::def_id::DefId;
+use rustc::ty::{self, TyCtxt};
+use rustc_data_structures::fnv::FnvHashMap;
+use syntax::ast;
+
+/// Builder that can encode new items, adding them into the index.
+/// Item encoding cannot be nested.
+pub struct IndexBuilder<'a, 'tcx: 'a, 'encoder: 'a> {
+    items: IndexData,
+    builder: ItemContentBuilder<'a, 'tcx, 'encoder>,
+}
+
+/// Builder that can encode the content of items, but can't start a
+/// new item itself. Most code is attached to here.
+pub struct ItemContentBuilder<'a, 'tcx: 'a, 'encoder: 'a> {
+    xrefs: FnvHashMap<XRef<'tcx>, u32>, // sequentially-assigned
+    pub ecx: &'a EncodeContext<'a, 'tcx>,
+    pub rbml_w: &'a mut Encoder<'encoder>,
+}
+
+/// "interned" entries referenced by id
+#[derive(PartialEq, Eq, Hash)]
+pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) }
+
+impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
+    pub fn new(ecx: &'a EncodeContext<'a, 'tcx>,
+               rbml_w: &'a mut Encoder<'encoder>)
+               -> Self {
+        IndexBuilder {
+            items: IndexData::new(ecx.tcx.map.num_local_def_ids()),
+            builder: ItemContentBuilder {
+                ecx: ecx,
+                xrefs: FnvHashMap(),
+                rbml_w: rbml_w,
+            },
+        }
+    }
+
+    pub fn ecx(&self) -> &'a EncodeContext<'a, 'tcx> {
+        self.builder.ecx()
+    }
+
+    /// Emit the data for a def-id to the metadata. The function to
+    /// emit the data is `op`, and it will be given `data` as
+    /// arguments. This `record` function will start/end an RBML tag
+    /// and record the current offset for use in the index, calling
+    /// `op` to generate the data in the RBML tag.
+    ///
+    /// In addition, it will setup a dep-graph task to track what data
+    /// `op` accesses to generate the metadata, which is later used by
+    /// incremental compilation to compute a hash for the metadata and
+    /// track changes.
+    ///
+    /// The reason that `op` is a function pointer, and not a closure,
+    /// is that we want to be able to completely track all data it has
+    /// access to, so that we can be sure that `DATA: DepGraphRead`
+    /// holds, and that it is therefore not gaining "secret" access to
+    /// bits of HIR or other state that would not be trackd by the
+    /// content system.
+    pub fn record<DATA>(&mut self,
+                        id: DefId,
+                        op: fn(&mut ItemContentBuilder<'a, 'tcx, 'encoder>, DATA),
+                        data: DATA)
+        where DATA: DepGraphRead
+    {
+        let position = self.builder.rbml_w.mark_stable_position();
+        self.items.record(id, position);
+        let _task = self.ecx().tcx.dep_graph.in_task(DepNode::MetaData(id));
+        self.builder.rbml_w.start_tag(tag_items_data_item).unwrap();
+        data.read(self.ecx().tcx);
+        op(&mut self.builder, data);
+        self.builder.rbml_w.end_tag().unwrap();
+    }
+
+    pub fn into_fields(self) -> (IndexData, FnvHashMap<XRef<'tcx>, u32>) {
+        (self.items, self.builder.xrefs)
+    }
+}
+
+impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
+    pub fn ecx(&self) -> &'a EncodeContext<'a, 'tcx> {
+        self.ecx
+    }
+
+    pub fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 {
+        let old_len = self.xrefs.len() as u32;
+        *self.xrefs.entry(xref).or_insert(old_len)
+    }
+}
+
+/// Trait used for data that can be passed from outside a dep-graph
+/// task.  The data must either be of some safe type, such as a
+/// `DefId` index, or implement the `read` method so that it can add
+/// a read of whatever dep-graph nodes are appropriate.
+pub trait DepGraphRead {
+    fn read(&self, tcx: TyCtxt);
+}
+
+impl DepGraphRead for DefId {
+    fn read(&self, _tcx: TyCtxt) { }
+}
+
+impl DepGraphRead for ast::NodeId {
+    fn read(&self, _tcx: TyCtxt) { }
+}
+
+impl<T> DepGraphRead for Option<T>
+    where T: DepGraphRead
+{
+    fn read(&self, tcx: TyCtxt) {
+        match *self {
+            Some(ref v) => v.read(tcx),
+            None => (),
+        }
+    }
+}
+
+impl<T> DepGraphRead for [T]
+    where T: DepGraphRead
+{
+    fn read(&self, tcx: TyCtxt) {
+        for i in self {
+            i.read(tcx);
+        }
+    }
+}
+
+macro_rules! read_tuple {
+    ($($name:ident),*) => {
+        impl<$($name),*> DepGraphRead for ($($name),*)
+            where $($name: DepGraphRead),*
+        {
+            #[allow(non_snake_case)]
+            fn read(&self, tcx: TyCtxt) {
+                let &($(ref $name),*) = self;
+                $($name.read(tcx);)*
+            }
+        }
+    }
+}
+read_tuple!(A,B);
+read_tuple!(A,B,C);
+
+macro_rules! read_hir {
+    ($t:ty) => {
+        impl<'tcx> DepGraphRead for &'tcx $t {
+            fn read(&self, tcx: TyCtxt) {
+                tcx.map.read(self.id);
+            }
+        }
+    }
+}
+read_hir!(hir::Item);
+read_hir!(hir::ImplItem);
+read_hir!(hir::TraitItem);
+read_hir!(hir::ForeignItem);
+
+/// Leaks access to a value of type T without any tracking. This is
+/// suitable for ambiguous types like `usize`, which *could* represent
+/// tracked data (e.g., if you read it out of a HIR node) or might not
+/// (e.g., if it's an index). Adding in an `Untracked` is an
+/// assertion, essentially, that the data does not need to be tracked
+/// (or that read edges will be added by some other way).
+///
+/// A good idea is to add to each use of `Untracked` an explanation of
+/// why this value is ok.
+pub struct Untracked<T>(pub T);
+
+impl<T> DepGraphRead for Untracked<T> {
+    fn read(&self, _tcx: TyCtxt) { }
+}
+
+/// Newtype that can be used to package up misc data extracted from a
+/// HIR node that doesn't carry its own id. This will allow an
+/// arbitrary `T` to be passed in, but register a read on the given
+/// node-id.
+pub struct FromId<T>(pub ast::NodeId, pub T);
+
+impl<T> DepGraphRead for FromId<T> {
+    fn read(&self, tcx: TyCtxt) {
+        tcx.map.read(self.0);
+    }
+}
index cd92493e3db703adc8e7931d51357fbc6292406f..a96fa8a006d8967bb4039147d0104c255c1d0993 100644 (file)
@@ -54,6 +54,7 @@
 pub mod tyencode;
 pub mod tydecode;
 pub mod encoder;
+mod index_builder;
 pub mod decoder;
 pub mod creader;
 pub mod csearch;
index 2345cd9a92aea2792c0cc77cedc90726370fb5c9..44d7861066da3a84108e2b00841bd60d37507c1d 100644 (file)
 use rustc::session::filesearch::{FileSearch, FileMatches, FileDoesntMatch};
 use rustc::session::search_paths::PathKind;
 use rustc::util::common;
+use rustc::util::nodemap::FnvHashMap;
 
 use rustc_llvm as llvm;
 use rustc_llvm::{False, ObjectFile, mk_section_iter};
 use rustc_back::target::Target;
 
 use std::cmp;
-use std::collections::HashMap;
 use std::fmt;
 use std::fs;
 use std::io;
@@ -342,9 +342,11 @@ pub fn report_load_errs(&mut self) -> ! {
                              "found crate `{}` compiled by an incompatible version of rustc{}",
                              self.ident, add)
         } else {
-            struct_span_err!(self.sess, self.span, E0463,
-                             "can't find crate for `{}`{}",
-                             self.ident, add)
+            let mut err = struct_span_err!(self.sess, self.span, E0463,
+                                           "can't find crate for `{}`{}",
+                                           self.ident, add);
+            err.span_label(self.span, &format!("can't find crate"));
+            err
         };
 
         if !self.rejected_via_triple.is_empty() {
@@ -413,7 +415,7 @@ fn find_library_crate(&mut self) -> Option<Library> {
         let rlib_prefix = format!("lib{}", self.crate_name);
         let staticlib_prefix = format!("{}{}", staticpair.0, self.crate_name);
 
-        let mut candidates = HashMap::new();
+        let mut candidates = FnvHashMap();
         let mut staticlibs = vec!();
 
         // First, find all possible candidate rlibs and dylibs purely based on
@@ -456,7 +458,7 @@ fn find_library_crate(&mut self) -> Option<Library> {
 
             let hash_str = hash.to_string();
             let slot = candidates.entry(hash_str)
-                                 .or_insert_with(|| (HashMap::new(), HashMap::new()));
+                                 .or_insert_with(|| (FnvHashMap(), FnvHashMap()));
             let (ref mut rlibs, ref mut dylibs) = *slot;
             fs::canonicalize(path).map(|p| {
                 if rlib {
@@ -477,7 +479,7 @@ fn find_library_crate(&mut self) -> Option<Library> {
         // A Library candidate is created if the metadata for the set of
         // libraries corresponds to the crate id and hash criteria that this
         // search is being performed for.
-        let mut libraries = HashMap::new();
+        let mut libraries = FnvHashMap();
         for (_hash, (rlibs, dylibs)) in candidates {
             let mut slot = None;
             let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot);
@@ -527,7 +529,7 @@ fn find_library_crate(&mut self) -> Option<Library> {
     // read the metadata from it if `*slot` is `None`. If the metadata couldn't
     // be read, it is assumed that the file isn't a valid rust library (no
     // errors are emitted).
-    fn extract_one(&mut self, m: HashMap<PathBuf, PathKind>, flavor: CrateFlavor,
+    fn extract_one(&mut self, m: FnvHashMap<PathBuf, PathKind>, flavor: CrateFlavor,
                    slot: &mut Option<(Svh, MetadataBlob)>) -> Option<(PathBuf, PathKind)> {
         let mut ret: Option<(PathBuf, PathKind)> = None;
         let mut error = 0;
@@ -669,8 +671,8 @@ fn find_commandline_library<'b, LOCS> (&mut self, locs: LOCS) -> Option<Library>
         // rlibs/dylibs.
         let sess = self.sess;
         let dylibname = self.dylibname();
-        let mut rlibs = HashMap::new();
-        let mut dylibs = HashMap::new();
+        let mut rlibs = FnvHashMap();
+        let mut dylibs = FnvHashMap();
         {
             let locs = locs.map(|l| PathBuf::from(l)).filter(|loc| {
                 if !loc.exists() {
index b2a2dcf90fa4b65fe4f3a1f981ede966b79e702a..fa31b6f4c7224e0ae7e899b41ea422dfe59d7296 100644 (file)
 use cstore::CStore;
 
 use rustc::session::Session;
+use rustc::util::nodemap::{FnvHashSet, FnvHashMap};
 
-use std::collections::{HashSet, HashMap};
 use syntax::parse::token;
 use syntax::ast;
 use syntax::attr;
-use syntax::attr::AttrMetaMethods;
 use syntax::ext;
 use syntax_pos::Span;
 
@@ -45,13 +44,13 @@ pub fn call_bad_macro_reexport(a: &Session, b: Span) {
     span_err!(a, b, E0467, "bad macro reexport");
 }
 
-pub type MacroSelection = HashMap<token::InternedString, Span>;
+pub type MacroSelection = FnvHashMap<token::InternedString, Span>;
 
 impl<'a> ext::base::MacroLoader for MacroLoader<'a> {
     fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<ast::MacroDef> {
         // Parse the attributes relating to macros.
-        let mut import = Some(HashMap::new());  // None => load all
-        let mut reexport = HashMap::new();
+        let mut import = Some(FnvHashMap());  // None => load all
+        let mut reexport = FnvHashMap();
 
         for attr in &extern_crate.attrs {
             let mut used = true;
@@ -64,8 +63,8 @@ fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<a
                     }
                     if let (Some(sel), Some(names)) = (import.as_mut(), names) {
                         for attr in names {
-                            if attr.is_word() {
-                                sel.insert(attr.name().clone(), attr.span());
+                            if let Some(word) = attr.word() {
+                                sel.insert(word.name().clone(), attr.span());
                             } else {
                                 span_err!(self.sess, attr.span(), E0466, "bad macro import");
                             }
@@ -82,8 +81,8 @@ fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<a
                     };
 
                     for attr in names {
-                        if attr.is_word() {
-                            reexport.insert(attr.name().clone(), attr.span());
+                        if let Some(word) = attr.word() {
+                            reexport.insert(word.name().clone(), attr.span());
                         } else {
                             call_bad_macro_reexport(self.sess, attr.span());
                         }
@@ -120,7 +119,7 @@ fn load_macros<'b>(&mut self,
         }
 
         let mut macros = Vec::new();
-        let mut seen = HashSet::new();
+        let mut seen = FnvHashSet();
 
         for mut def in self.reader.read_exported_macros(vi) {
             let name = def.ident.name.as_str();
index c76cf2363923741b12a2db7c2e1421fe2fe61c78..f51299226fe7da904ff2f689e194d4eb8ad36cd6 100644 (file)
@@ -20,7 +20,7 @@
 
 use rustc::hir::def_id::{DefId, DefIndex};
 use middle::region;
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Kind, Substs};
 use rustc::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
 
 use rbml;
@@ -129,19 +129,19 @@ fn parse_size(&mut self) -> Option<usize> {
     }
 
     pub fn parse_substs(&mut self) -> &'tcx Substs<'tcx> {
-        let mut regions = vec![];
-        let mut types = vec![];
+        let mut params = vec![];
         assert_eq!(self.next(), '[');
-        while self.peek() != '|' {
-            regions.push(self.parse_region());
-        }
-        assert_eq!(self.next(), '|');
         while self.peek() != ']' {
-            types.push(self.parse_ty());
+            let k = match self.next() {
+                'r' => Kind::from(self.parse_region()),
+                't' => Kind::from(self.parse_ty()),
+                _ => bug!()
+            };
+            params.push(k);
         }
         assert_eq!(self.next(), ']');
 
-        Substs::new(self.tcx, types, regions)
+        Substs::new(self.tcx, params)
     }
 
     pub fn parse_generics(&mut self) -> &'tcx ty::Generics<'tcx> {
@@ -207,8 +207,8 @@ fn parse_bound_region(&mut self) -> ty::BoundRegion {
         }
     }
 
-    pub fn parse_region(&mut self) -> ty::Region {
-        match self.next() {
+    pub fn parse_region(&mut self) -> &'tcx ty::Region {
+        self.tcx.mk_region(match self.next() {
             'b' => {
                 assert_eq!(self.next(), '[');
                 let id = ty::DebruijnIndex::new(self.parse_u32());
@@ -245,7 +245,7 @@ pub fn parse_region(&mut self) -> ty::Region {
             'e' => ty::ReEmpty,
             'E' => ty::ReErased,
             _ => bug!("parse_region: bad input")
-        }
+        })
     }
 
     fn parse_scope(&mut self) -> region::CodeExtent {
@@ -403,9 +403,7 @@ pub fn parse_ty(&mut self) -> Ty<'tcx> {
             '~' => return tcx.mk_box(self.parse_ty()),
             '*' => return tcx.mk_ptr(self.parse_mt()),
             '&' => {
-                let r = self.parse_region();
-                let mt = self.parse_mt();
-                return tcx.mk_ref(tcx.mk_region(r), mt);
+                return tcx.mk_ref(self.parse_region(), self.parse_mt());
             }
             'V' => {
                 let t = self.parse_ty();
@@ -657,7 +655,7 @@ fn parse_type_param_def(&mut self) -> ty::TypeParameterDef<'tcx> {
         }
     }
 
-    fn parse_region_param_def(&mut self) -> ty::RegionParameterDef {
+    fn parse_region_param_def(&mut self) -> ty::RegionParameterDef<'tcx> {
         let name = self.parse_name(':');
         let def_id = self.parse_def();
         let index = self.parse_u32();
@@ -681,7 +679,7 @@ fn parse_region_param_def(&mut self) -> ty::RegionParameterDef {
     }
 
 
-    fn parse_object_lifetime_default(&mut self) -> ty::ObjectLifetimeDefault {
+    fn parse_object_lifetime_default(&mut self) -> ty::ObjectLifetimeDefault<'tcx> {
         match self.next() {
             'a' => ty::ObjectLifetimeDefault::Ambiguous,
             'b' => ty::ObjectLifetimeDefault::BaseDefault,
index 90fd8a0eb2f654f2fa69e25c3b10ab5b426eb831..954ca878c01ef7919ea945681528fbca1af3448d 100644 (file)
@@ -133,7 +133,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx
         ty::TyRawPtr(mt) => { write!(w, "*"); enc_mt(w, cx, mt); }
         ty::TyRef(r, mt) => {
             write!(w, "&");
-            enc_region(w, cx, *r);
+            enc_region(w, cx, r);
             enc_mt(w, cx, mt);
         }
         ty::TyArray(t, sz) => {
@@ -251,12 +251,16 @@ fn enc_opt<T, F>(w: &mut Cursor<Vec<u8>>, t: Option<T>, enc_f: F) where
 pub fn enc_substs<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
                             substs: &Substs<'tcx>) {
     write!(w, "[");
-    for &r in &substs.regions {
-        enc_region(w, cx, r);
-    }
-    write!(w, "|");
-    for &ty in &substs.types {
-        enc_ty(w, cx, ty);
+    for &k in substs.params() {
+        if let Some(ty) = k.as_type() {
+            write!(w, "t");
+            enc_ty(w, cx, ty);
+        } else if let Some(r) = k.as_region() {
+            write!(w, "r");
+            enc_region(w, cx, r);
+        } else {
+            bug!()
+        }
     }
     write!(w, "]");
 }
@@ -286,8 +290,8 @@ pub fn enc_generics<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
     }
 }
 
-pub fn enc_region(w: &mut Cursor<Vec<u8>>, cx: &ctxt, r: ty::Region) {
-    match r {
+pub fn enc_region(w: &mut Cursor<Vec<u8>>, cx: &ctxt, r: &ty::Region) {
+    match *r {
         ty::ReLateBound(id, br) => {
             write!(w, "b[{}|", id.depth);
             enc_bound_region(w, cx, br);
@@ -475,9 +479,6 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor<Vec<u8>>,
                                p: &ty::Predicate<'tcx>)
 {
     match *p {
-        ty::Predicate::Rfc1592(..) => {
-            bug!("RFC1592 predicate in metadata `{:?}`", p);
-        }
         ty::Predicate::Trait(ref trait_ref) => {
             write!(w, "t");
             enc_trait_ref(w, cx, trait_ref.0.trait_ref);
index 83f8c3b42c850a1eb52d28f78daed875f71a0749..026a79b32b8f735680af4685e7646bded4ff28c7 100644 (file)
@@ -13,7 +13,7 @@
 
 //! Routines for manipulating the control-flow graph.
 
-use build::{CFG, Location};
+use build::CFG;
 use rustc::mir::repr::*;
 
 impl<'tcx> CFG<'tcx> {
index ec390704d078976df454152ab796dba0a014fbfe..1b64b4d0b5317861712ebae924b4fec20e60fa32 100644 (file)
@@ -278,7 +278,7 @@ struct Binding<'tcx> {
     var_id: NodeId,
     var_ty: Ty<'tcx>,
     mutability: Mutability,
-    binding_mode: BindingMode,
+    binding_mode: BindingMode<'tcx>,
 }
 
 #[derive(Clone, Debug)]
index 8c9ed53c8ab4de2794b1c5ce499af946d38d29f7..bf43bfb326a581a3bc7980776e9977264e639acc 100644 (file)
@@ -293,7 +293,7 @@ pub fn perform_test(&mut self,
                     assert!(ty.is_slice());
                     let eq_def_id = self.hir.tcx().lang_items.eq_trait().unwrap();
                     let ty = mt.ty;
-                    let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, vec![ty]);
+                    let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]);
 
                     let bool_ty = self.hir.bool_ty();
                     let eq_result = self.temp(bool_ty);
index 26eb782a73b0031c656e5353801828d421726502..59d6cf118596990bbe8db97410b6e6febdd3ae2c 100644 (file)
@@ -101,16 +101,6 @@ pub struct ScopeAuxiliary {
     pub postdoms: Vec<Location>,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
-pub struct Location {
-    /// the location is within this block
-    pub block: BasicBlock,
-
-    /// the location is the start of the this statement; or, if `statement_index`
-    /// == num-statements, then the start of the terminator.
-    pub statement_index: usize,
-}
-
 pub type ScopeAuxiliaryVec = IndexVec<ScopeId, ScopeAuxiliary>;
 
 ///////////////////////////////////////////////////////////////////////////
index 5e4053a82ad8a3ce22a7c6b093733073d08864e5..0b33e5a145083fabc58475ea20d0f153480413cb 100644 (file)
 use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary, ScopeId};
 use rustc::middle::region::{CodeExtent, CodeExtentData};
 use rustc::middle::lang_items;
-use rustc::ty::subst::{Substs, Subst};
+use rustc::ty::subst::{Kind, Substs, Subst};
 use rustc::ty::{Ty, TyCtxt};
 use rustc::mir::repr::*;
 use syntax_pos::Span;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::fnv::FnvHashMap;
 
+use std::iter;
+
 pub struct Scope<'tcx> {
     /// the scope-id within the scope_auxiliary
     id: ScopeId,
@@ -198,8 +200,11 @@ impl<'tcx> Scope<'tcx> {
     ///
     /// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a
     /// larger extent of code.
-    fn invalidate_cache(&mut self) {
-        self.cached_exits = FnvHashMap();
+    ///
+    /// `unwind` controls whether caches for the unwind branch are also invalidated.
+    fn invalidate_cache(&mut self, unwind: bool) {
+        self.cached_exits.clear();
+        if !unwind { return; }
         for dropdata in &mut self.drops {
             if let DropKind::Value { ref mut cached_block } = dropdata.kind {
                 *cached_block = None;
@@ -455,25 +460,65 @@ pub fn schedule_drop(&mut self,
         };
 
         for scope in self.scopes.iter_mut().rev() {
-            if scope.extent == extent {
+            let this_scope = scope.extent == extent;
+            // When building drops, we try to cache chains of drops in such a way so these drops
+            // could be reused by the drops which would branch into the cached (already built)
+            // blocks.  This, however, means that whenever we add a drop into a scope which already
+            // had some blocks built (and thus, cached) for it, we must invalidate all caches which
+            // might branch into the scope which had a drop just added to it. This is necessary,
+            // because otherwise some other code might use the cache to branch into already built
+            // chain of drops, essentially ignoring the newly added drop.
+            //
+            // For example consider there’s two scopes with a drop in each. These are built and
+            // thus the caches are filled:
+            //
+            // +--------------------------------------------------------+
+            // | +---------------------------------+                    |
+            // | | +--------+     +-------------+  |  +---------------+ |
+            // | | | return | <-+ | drop(outer) | <-+ |  drop(middle) | |
+            // | | +--------+     +-------------+  |  +---------------+ |
+            // | +------------|outer_scope cache|--+                    |
+            // +------------------------------|middle_scope cache|------+
+            //
+            // Now, a new, inner-most scope is added along with a new drop into both inner-most and
+            // outer-most scopes:
+            //
+            // +------------------------------------------------------------+
+            // | +----------------------------------+                       |
+            // | | +--------+      +-------------+  |   +---------------+   | +-------------+
+            // | | | return | <+   | drop(new)   | <-+  |  drop(middle) | <--+| drop(inner) |
+            // | | +--------+  |   | drop(outer) |  |   +---------------+   | +-------------+
+            // | |             +-+ +-------------+  |                       |
+            // | +---|invalid outer_scope cache|----+                       |
+            // +----=----------------|invalid middle_scope cache|-----------+
+            //
+            // If, when adding `drop(new)` we do not invalidate the cached blocks for both
+            // outer_scope and middle_scope, then, when building drops for the inner (right-most)
+            // scope, the old, cached blocks, without `drop(new)` will get used, producing the
+            // wrong results.
+            //
+            // The cache and its invalidation for unwind branch is somewhat special. The cache is
+            // per-drop, rather than per scope, which has a several different implications. Adding
+            // a new drop into a scope will not invalidate cached blocks of the prior drops in the
+            // scope. That is true, because none of the already existing drops will have an edge
+            // into a block with the newly added drop.
+            //
+            // Note that this code iterates scopes from the inner-most to the outer-most,
+            // invalidating caches of each scope visited. This way bare minimum of the
+            // caches gets invalidated. i.e. if a new drop is added into the middle scope, the
+            // cache of outer scpoe stays intact.
+            let invalidate_unwind = needs_drop && !this_scope;
+            scope.invalidate_cache(invalidate_unwind);
+            if this_scope {
                 if let DropKind::Value { .. } = drop_kind {
                     scope.needs_cleanup = true;
                 }
-
-                // No need to invalidate any caches here. The just-scheduled drop will branch into
-                // the drop that comes before it in the vector.
                 scope.drops.push(DropData {
                     span: span,
                     location: lvalue.clone(),
                     kind: drop_kind
                 });
                 return;
-            } else {
-                // We must invalidate all the cached_blocks leading up to the scope we’re
-                // looking for, because all of the blocks in the chain will become incorrect.
-                if let DropKind::Value { .. } = drop_kind {
-                    scope.invalidate_cache()
-                }
             }
         }
         span_bug!(span, "extent {:?} not in scope to drop {:?}", extent, lvalue);
@@ -490,11 +535,12 @@ pub fn schedule_box_free(&mut self,
                              value: &Lvalue<'tcx>,
                              item_ty: Ty<'tcx>) {
         for scope in self.scopes.iter_mut().rev() {
+            // See the comment in schedule_drop above. The primary difference is that we invalidate
+            // the unwind blocks unconditionally. That’s because the box free may be considered
+            // outer-most cleanup within the scope.
+            scope.invalidate_cache(true);
             if scope.extent == extent {
                 assert!(scope.free.is_none(), "scope already has a scheduled free!");
-                // We also must invalidate the caches in the scope for which the free is scheduled
-                // because the drops must branch into the free we schedule here.
-                scope.invalidate_cache();
                 scope.needs_cleanup = true;
                 scope.free = Some(FreeData {
                     span: span,
@@ -503,11 +549,6 @@ pub fn schedule_box_free(&mut self,
                     cached_block: None
                 });
                 return;
-            } else {
-                // We must invalidate all the cached_blocks leading up to the scope we’re looking
-                // for, because otherwise some/most of the blocks in the chain will become
-                // incorrect.
-                scope.invalidate_cache();
             }
         }
         span_bug!(span, "extent {:?} not in scope to free {:?}", extent, value);
@@ -750,7 +791,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                               -> TerminatorKind<'tcx> {
     let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem)
                        .unwrap_or_else(|e| tcx.sess.fatal(&e));
-    let substs = Substs::new(tcx, vec![data.item_ty], vec![]);
+    let substs = Substs::new(tcx, iter::once(Kind::from(data.item_ty)));
     TerminatorKind::Call {
         func: Operand::Constant(Constant {
             span: data.span,
index 4a731d898a937d8edabcce09e07e6834febcce96..eb16812af9b0225fa5714dcca15928b114e859a1 100644 (file)
@@ -18,7 +18,7 @@
 the heap at runtime, and therefore cannot be done at compile time. Erroneous
 code example:
 
-```compile_fail
+```compile_fail,E0010
 #![feature(box_syntax)]
 
 const CON : Box<i32> = box 0;
@@ -30,7 +30,7 @@
 variable cannot refer to a static variable. For example, `Y` cannot refer to
 `X` here:
 
-```compile_fail
+```compile_fail,E0013
 static X: i32 = 42;
 const Y: i32 = X;
 ```
@@ -66,7 +66,7 @@ struct Bar {x: u8}
 Blocks in constants may only contain items (such as constant, function
 definition, etc...) and a tail expression. Erroneous code example:
 
-```compile_fail
+```compile_fail,E0016
 const FOO: i32 = { let x = 0; x }; // 'x' isn't an item!
 ```
 
@@ -81,7 +81,7 @@ struct Bar {x: u8}
 References in statics and constants may only refer to immutable values.
 Erroneous code example:
 
-```compile_fail
+```compile_fail,E0017
 static X: i32 = 1;
 const C: i32 = 2;
 
@@ -107,7 +107,7 @@ struct Bar {x: u8}
 
 For example, if you write:
 
-```compile_fail
+```compile_fail,E0018
 static MY_STATIC: u32 = 42;
 static MY_STATIC_ADDR: usize = &MY_STATIC as *const _ as usize;
 static WHAT: usize = (MY_STATIC_ADDR^17) + MY_STATIC_ADDR;
@@ -152,7 +152,7 @@ fn test(&self) -> i32 {
 fn main() {
     const FOO: Test = Test::V1;
 
-    const A: i32 = FOO.test(); // You can't call Test::func() here !
+    const A: i32 = FOO.test(); // You can't call Test::func() here!
 }
 ```
 
@@ -214,14 +214,13 @@ const fn foo(mut x: u8) {
 ```
 "##,
 
-
 E0395: r##"
 The value assigned to a constant scalar must be known at compile time,
 which is not the case when comparing raw pointers.
 
 Erroneous code example:
 
-```compile_fail
+```compile_fail,E0395
 static FOO: i32 = 42;
 static BAR: i32 = 42;
 
@@ -250,7 +249,7 @@ const fn foo(mut x: u8) {
 (or even link-time), which means it can't be used in a constant
 expression. Erroneous code example:
 
-```compile_fail
+```compile_fail,E0396
 const REG_ADDR: *const u8 = 0x5f3759df as *const u8;
 
 const VALUE: u8 = unsafe { *REG_ADDR };
@@ -272,7 +271,7 @@ const fn foo(mut x: u8) {
 A borrow of a constant containing interior mutability was attempted. Erroneous
 code example:
 
-```compile_fail
+```compile_fail,E0492
 use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
 
 const A: AtomicUsize = ATOMIC_USIZE_INIT;
@@ -299,7 +298,7 @@ const fn foo(mut x: u8) {
 
 You can also have this error while using a cell type:
 
-```compile_fail
+```compile_fail,E0492
 #![feature(const_fn)]
 
 use std::cell::Cell;
@@ -351,7 +350,7 @@ unsafe impl<T> Sync for NotThreadSafe<T> {}
 A type with a destructor was assigned to an invalid type of variable. Erroneous
 code example:
 
-```compile_fail
+```compile_fail,E0493
 struct Foo {
     a: u32
 }
@@ -374,7 +373,7 @@ fn drop(&mut self) {}
 A reference of an interior static was assigned to another const/static.
 Erroneous code example:
 
-```compile_fail
+```compile_fail,E0494
 struct Foo {
     a: u32
 }
index a61fdb79df822588fb61ca54dbd456f686ea4ff0..6e8a5771eea949a1ad4ea2af600e8548120d0b07 100644 (file)
@@ -108,7 +108,7 @@ fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
                                 region, ty::TypeAndMut { ty: expr.ty, mutbl: mutbl }),
                             span: expr.span,
                             kind: ExprKind::Borrow {
-                                region: *region,
+                                region: region,
                                 borrow_kind: to_borrow_kind(mutbl),
                                 arg: expr.to_ref()
                             }
@@ -137,7 +137,7 @@ fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
                                 ty: adjusted_ty,
                                 span: self.span,
                                 kind: ExprKind::Borrow {
-                                    region: *r,
+                                    region: r,
                                     borrow_kind: to_borrow_kind(m),
                                     arg: expr.to_ref(),
                                 },
@@ -154,7 +154,7 @@ fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
                                 ty: cx.tcx.mk_ref(region, ty::TypeAndMut { ty: expr.ty, mutbl: m }),
                                 span: self.span,
                                 kind: ExprKind::Borrow {
-                                    region: *region,
+                                    region: region,
                                     borrow_kind: to_borrow_kind(m),
                                     arg: expr.to_ref(),
                                 },
@@ -310,7 +310,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 _ => span_bug!(expr.span, "type of & not region"),
             };
             ExprKind::Borrow {
-                region: *region,
+                region: region,
                 borrow_kind: to_borrow_kind(mutbl),
                 arg: expr.to_ref(),
             }
@@ -842,8 +842,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     ExprKind::Deref {
                         arg: Expr {
                             temp_lifetime: temp_lifetime,
-                            ty: cx.tcx.mk_ref(
-                                cx.tcx.mk_region(borrow.region),
+                            ty: cx.tcx.mk_ref(borrow.region,
                                 ty::TypeAndMut {
                                     ty: var_ty,
                                     mutbl: borrow.kind.to_mutbl_lossy()
@@ -907,8 +906,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         PassArgs::ByRef => {
-            let scope = cx.tcx.region_maps.node_extent(expr.id);
-            let region = cx.tcx.mk_region(ty::ReScope(scope));
+            let region = cx.tcx.node_scope_region(expr.id);
             let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
             argrefs.extend(
                 args.iter()
@@ -922,7 +920,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                             temp_lifetime: temp_lifetime,
                             ty: adjusted_ty,
                             span: expr.span,
-                            kind: ExprKind::Borrow { region: *region,
+                            kind: ExprKind::Borrow { region: region,
                                                      borrow_kind: BorrowKind::Shared,
                                                      arg: arg.to_ref() }
                         }.to_ref()
index 972e7f5be7075ed339a7cba7754e5f5bfb42d692..1767630b81b1a14b897ac59b227637b4be9fbf58 100644 (file)
@@ -32,7 +32,6 @@
 use syntax::parse::token;
 use rustc::hir;
 use rustc_const_math::{ConstInt, ConstUsize};
-use syntax::attr::AttrMetaMethods;
 
 #[derive(Copy, Clone)]
 pub struct Cx<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
@@ -144,10 +143,10 @@ pub fn trait_method(&mut self,
                         trait_def_id: DefId,
                         method_name: &str,
                         self_ty: Ty<'tcx>,
-                        params: Vec<Ty<'tcx>>)
+                        params: &[Ty<'tcx>])
                         -> (Ty<'tcx>, Literal<'tcx>) {
         let method_name = token::intern(method_name);
-        let substs = Substs::new_trait(self.tcx, params, vec![], self_ty);
+        let substs = Substs::new_trait(self.tcx, self_ty, params);
         for trait_item in self.tcx.trait_items(trait_def_id).iter() {
             match *trait_item {
                 ty::ImplOrTraitItem::MethodTraitItem(ref method) => {
index c54c8bfb5981ed6d8469510cc76c47a212992f36..0bd22cd2d9308c4a35b9cee16b9d88b2b10d9ee0 100644 (file)
@@ -161,7 +161,7 @@ fn to_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
                 let id = self.cx.tcx.expect_def(pat.id).var_id();
                 let var_ty = self.cx.tcx.node_id_to_type(pat.id);
                 let region = match var_ty.sty {
-                    ty::TyRef(&r, _) => Some(r),
+                    ty::TyRef(r, _) => Some(r),
                     _ => None,
                 };
                 let (mutability, mode) = match bm {
index 2a5b7d0fb29024950cc727c92a407532a4810324..353f2433353028198f42c9a137600218f0368dac 100644 (file)
@@ -193,7 +193,7 @@ pub enum ExprKind<'tcx> {
         id: DefId,
     },
     Borrow {
-        region: Region,
+        region: &'tcx Region,
         borrow_kind: BorrowKind,
         arg: ExprRef<'tcx>,
     },
@@ -284,7 +284,7 @@ pub enum PatternKind<'tcx> {
     Binding {
         mutability: Mutability,
         name: ast::Name,
-        mode: BindingMode,
+        mode: BindingMode<'tcx>,
         var: ast::NodeId,
         ty: Ty<'tcx>,
         subpattern: Option<Pattern<'tcx>>,
@@ -332,9 +332,9 @@ pub enum PatternKind<'tcx> {
 }
 
 #[derive(Copy, Clone, Debug)]
-pub enum BindingMode {
+pub enum BindingMode<'tcx> {
     ByValue,
-    ByRef(Region, BorrowKind),
+    ByRef(&'tcx Region, BorrowKind),
 }
 
 #[derive(Clone, Debug)]
index c58491096b94f0d3957442e3738f9c14c19e3b80..d46a7b2bb9506fe22c446e414ad5fd92431446b3 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use build::{Location, ScopeAuxiliaryVec, ScopeId};
+use build::{ScopeAuxiliaryVec, ScopeId};
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::mir::repr::*;
index 818f060ed445ccff0404d04554de1508991a515b..32fddd293cacd770c4cef456f372e2d45e2e31e2 100644 (file)
 pub struct NoLandingPads;
 
 impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
-    fn visit_terminator(&mut self, bb: BasicBlock, terminator: &mut Terminator<'tcx>) {
+    fn visit_terminator(&mut self,
+                        bb: BasicBlock,
+                        terminator: &mut Terminator<'tcx>,
+                        location: Location) {
         match terminator.kind {
             TerminatorKind::Goto { .. } |
             TerminatorKind::Resume |
@@ -37,7 +40,7 @@ fn visit_terminator(&mut self, bb: BasicBlock, terminator: &mut Terminator<'tcx>
                 unwind.take();
             },
         }
-        self.super_terminator(bb, terminator);
+        self.super_terminator(bb, terminator, location);
     }
 }
 
index 21b406c3bf5c99ba1e26d2822d62a3d356c1760e..f864f1678f23690747f3ab055006063d95732363 100644 (file)
 use rustc::ty::TyCtxt;
 use syntax_pos::Span;
 
-use build::Location;
-
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
 use std::mem;
+use std::usize;
 
 /// State of a temporary during collection and promotion.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -77,13 +76,12 @@ pub enum Candidate {
 
 struct TempCollector {
     temps: IndexVec<Temp, TempState>,
-    location: Location,
     span: Span
 }
 
 impl<'tcx> Visitor<'tcx> for TempCollector {
-    fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) {
-        self.super_lvalue(lvalue, context);
+    fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) {
+        self.super_lvalue(lvalue, context, location);
         if let Lvalue::Temp(index) = *lvalue {
             // Ignore drops, if the temp gets promoted,
             // then it's constant and thus drop is noop.
@@ -101,7 +99,7 @@ fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) {
                     LvalueContext::Store |
                     LvalueContext::Call => {
                         *temp = TempState::Defined {
-                            location: self.location,
+                            location: location,
                             uses: 0
                         };
                         return;
@@ -126,27 +124,11 @@ fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) {
     fn visit_source_info(&mut self, source_info: &SourceInfo) {
         self.span = source_info.span;
     }
-
-    fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>) {
-        assert_eq!(self.location.block, bb);
-        self.super_statement(bb, statement);
-        self.location.statement_index += 1;
-    }
-
-    fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) {
-        self.location.statement_index = 0;
-        self.location.block = bb;
-        self.super_basic_block_data(bb, data);
-    }
 }
 
 pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Temp, TempState> {
     let mut collector = TempCollector {
         temps: IndexVec::from_elem(TempState::Undefined, &mir.temp_decls),
-        location: Location {
-            block: START_BLOCK,
-            statement_index: 0
-        },
         span: mir.span
     };
     for (bb, data) in rpo {
@@ -266,9 +248,15 @@ fn promote_temp(&mut self, temp: Temp) -> Temp {
 
         // Then, recurse for components in the Rvalue or Call.
         if stmt_idx < no_stmts {
-            self.visit_rvalue(rvalue.as_mut().unwrap());
+            self.visit_rvalue(rvalue.as_mut().unwrap(), Location {
+                block: bb,
+                statement_index: stmt_idx
+            });
         } else {
-            self.visit_terminator_kind(bb, call.as_mut().unwrap());
+            self.visit_terminator_kind(bb, call.as_mut().unwrap(), Location {
+                block: bb,
+                statement_index: no_stmts
+            });
         }
 
         let new_temp = self.promoted.temp_decls.push(TempDecl {
@@ -327,7 +315,10 @@ fn promote_candidate(mut self, candidate: Candidate) {
                 }
             }
         };
-        self.visit_rvalue(&mut rvalue);
+        self.visit_rvalue(&mut rvalue, Location{
+            block: BasicBlock::new(0),
+            statement_index: usize::MAX
+        });
         self.assign(Lvalue::ReturnPointer, rvalue, span);
         self.source.promoted.push(self.promoted);
     }
@@ -335,11 +326,14 @@ fn promote_candidate(mut self, candidate: Candidate) {
 
 /// Replaces all temporaries with their promoted counterparts.
 impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
-    fn visit_lvalue(&mut self, lvalue: &mut Lvalue<'tcx>, context: LvalueContext) {
+    fn visit_lvalue(&mut self,
+                    lvalue: &mut Lvalue<'tcx>,
+                    context: LvalueContext,
+                    location: Location) {
         if let Lvalue::Temp(ref mut temp) = *lvalue {
             *temp = self.promote_temp(*temp);
         }
-        self.super_lvalue(lvalue, context);
+        self.super_lvalue(lvalue, context, location);
     }
 }
 
index 1de67922b1b3a19e9ab3523885baa424946eaf03..2fc90ab27a08559c5db46346635ac0e8b3c265a5 100644 (file)
@@ -36,8 +36,7 @@
 
 use std::collections::hash_map::Entry;
 use std::fmt;
-
-use build::Location;
+use std::usize;
 
 use super::promote_consts::{self, Candidate, TempState};
 
@@ -147,7 +146,6 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     return_qualif: Option<Qualif>,
     qualif: Qualif,
     const_fn_arg_vars: BitVector,
-    location: Location,
     temp_promotion_state: IndexVec<Temp, TempState>,
     promotion_candidates: Vec<Candidate>
 }
@@ -178,10 +176,6 @@ fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             return_qualif: None,
             qualif: Qualif::empty(),
             const_fn_arg_vars: BitVector::new(mir.var_decls.len()),
-            location: Location {
-                block: START_BLOCK,
-                statement_index: 0
-            },
             temp_promotion_state: temps,
             promotion_candidates: vec![]
         }
@@ -293,7 +287,7 @@ fn try_consume(&mut self) -> bool {
     }
 
     /// Assign the current qualification to the given destination.
-    fn assign(&mut self, dest: &Lvalue<'tcx>) {
+    fn assign(&mut self, dest: &Lvalue<'tcx>, location: Location) {
         let qualif = self.qualif;
         let span = self.span;
         let store = |slot: &mut Option<Qualif>| {
@@ -331,7 +325,7 @@ fn assign(&mut self, dest: &Lvalue<'tcx>) {
             // This must be an explicit assignment.
             _ => {
                 // Catch more errors in the destination.
-                self.visit_lvalue(dest, LvalueContext::Store);
+                self.visit_lvalue(dest, LvalueContext::Store, location);
                 self.statement_like();
             }
         }
@@ -399,7 +393,10 @@ fn qualify_const(&mut self) -> Qualif {
                     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)));
+                            self.assign(&Lvalue::Var(Var::new(index)), Location {
+                                block: bb,
+                                statement_index: usize::MAX,
+                            });
                         }
                     }
 
@@ -445,7 +442,7 @@ fn qualify_const(&mut self) -> Qualif {
 /// For functions (constant or not), it also records
 /// candidates for promotion in promotion_candidates.
 impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
-    fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) {
+    fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) {
         match *lvalue {
             Lvalue::Arg(_) => {
                 self.add(Qualif::FN_ARGUMENT);
@@ -477,7 +474,7 @@ fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) {
             }
             Lvalue::Projection(ref proj) => {
                 self.nest(|this| {
-                    this.super_lvalue(lvalue, context);
+                    this.super_lvalue(lvalue, context, location);
                     match proj.elem {
                         ProjectionElem::Deref => {
                             if !this.try_consume() {
@@ -493,9 +490,13 @@ fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) {
                             if let ty::TyRawPtr(_) = base_ty.sty {
                                 this.add(Qualif::NOT_CONST);
                                 if this.mode != Mode::Fn {
-                                    span_err!(this.tcx.sess, this.span, E0396,
-                                              "raw pointers cannot be dereferenced in {}s",
-                                              this.mode);
+                                    struct_span_err!(this.tcx.sess,
+                                        this.span, E0396,
+                                        "raw pointers cannot be dereferenced in {}s",
+                                        this.mode)
+                                    .span_label(this.span,
+                                        &format!("dereference of raw pointer in constant"))
+                                    .emit();
                                 }
                             }
                         }
@@ -523,11 +524,11 @@ fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) {
         }
     }
 
-    fn visit_operand(&mut self, operand: &Operand<'tcx>) {
+    fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
         match *operand {
             Operand::Consume(_) => {
                 self.nest(|this| {
-                    this.super_operand(operand);
+                    this.super_operand(operand, location);
                     this.try_consume();
                 });
             }
@@ -539,7 +540,7 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>) {
 
                 if let Literal::Item { def_id, substs } = constant.literal {
                     // Don't peek inside generic (associated) constants.
-                    if !substs.types.is_empty() {
+                    if substs.types().next().is_some() {
                         self.add_type(constant.ty);
                     } else {
                         let qualif = qualify_const_item_cached(self.tcx,
@@ -566,9 +567,9 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>) {
         }
     }
 
-    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
+    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
         // Recurse through operands and lvalues.
-        self.super_rvalue(rvalue);
+        self.super_rvalue(rvalue, location);
 
         match *rvalue {
             Rvalue::Use(_) |
@@ -644,7 +645,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
                 }
 
                 // We might have a candidate for promotion.
-                let candidate = Candidate::Ref(self.location);
+                let candidate = Candidate::Ref(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.
@@ -681,9 +682,14 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
 
                     self.add(Qualif::NOT_CONST);
                     if self.mode != Mode::Fn {
-                        span_err!(self.tcx.sess, self.span, E0395,
-                                  "raw pointers cannot be compared in {}s",
-                                  self.mode);
+                        struct_span_err!(
+                            self.tcx.sess, self.span, E0395,
+                            "raw pointers cannot be compared in {}s",
+                            self.mode)
+                        .span_label(
+                            self.span,
+                            &format!("comparing raw pointers in static"))
+                        .emit();
                     }
                 }
             }
@@ -724,9 +730,12 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
         }
     }
 
-    fn visit_terminator_kind(&mut self, bb: BasicBlock, kind: &TerminatorKind<'tcx>) {
+    fn visit_terminator_kind(&mut self,
+                             bb: BasicBlock,
+                             kind: &TerminatorKind<'tcx>,
+                             location: Location) {
         if let TerminatorKind::Call { ref func, ref args, ref destination, .. } = *kind {
-            self.visit_operand(func);
+            self.visit_operand(func, location);
 
             let fn_ty = func.ty(self.mir, self.tcx);
             let (is_shuffle, is_const_fn) = match fn_ty.sty {
@@ -740,7 +749,7 @@ fn visit_terminator_kind(&mut self, bb: BasicBlock, kind: &TerminatorKind<'tcx>)
 
             for (i, arg) in args.iter().enumerate() {
                 self.nest(|this| {
-                    this.visit_operand(arg);
+                    this.visit_operand(arg, location);
                     if is_shuffle && i == 2 && this.mode == Mode::Fn {
                         let candidate = Candidate::ShuffleIndices(bb);
                         if !this.qualif.intersects(Qualif::NEVER_PROMOTE) {
@@ -818,16 +827,20 @@ struct and enum constructors",
                         self.deny_drop();
                     }
                 }
-                self.assign(dest);
+                self.assign(dest, location);
             }
         } else {
             // Qualify any operands inside other terminators.
-            self.super_terminator_kind(bb, kind);
+            self.super_terminator_kind(bb, kind, location);
         }
     }
 
-    fn visit_assign(&mut self, _: BasicBlock, dest: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) {
-        self.visit_rvalue(rvalue);
+    fn visit_assign(&mut self,
+                    _: BasicBlock,
+                    dest: &Lvalue<'tcx>,
+                    rvalue: &Rvalue<'tcx>,
+                    location: Location) {
+        self.visit_rvalue(rvalue, location);
 
         // Check the allowed const fn argument forms.
         if let (Mode::ConstFn, &Lvalue::Var(index)) = (self.mode, dest) {
@@ -848,38 +861,32 @@ fn visit_assign(&mut self, _: BasicBlock, dest: &Lvalue<'tcx>, rvalue: &Rvalue<'
             }
         }
 
-        self.assign(dest);
+        self.assign(dest, location);
     }
 
     fn visit_source_info(&mut self, source_info: &SourceInfo) {
         self.span = source_info.span;
     }
 
-    fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>) {
-        assert_eq!(self.location.block, bb);
+    fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>, location: Location) {
         self.nest(|this| {
             this.visit_source_info(&statement.source_info);
             match statement.kind {
                 StatementKind::Assign(ref lvalue, ref rvalue) => {
-                    this.visit_assign(bb, lvalue, rvalue);
+                    this.visit_assign(bb, lvalue, rvalue, location);
                 }
                 StatementKind::SetDiscriminant { .. } |
                 StatementKind::StorageLive(_) |
                 StatementKind::StorageDead(_) => {}
             }
         });
-        self.location.statement_index += 1;
-    }
-
-    fn visit_terminator(&mut self, bb: BasicBlock, terminator: &Terminator<'tcx>) {
-        assert_eq!(self.location.block, bb);
-        self.nest(|this| this.super_terminator(bb, terminator));
     }
 
-    fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) {
-        self.location.statement_index = 0;
-        self.location.block = bb;
-        self.super_basic_block_data(bb, data);
+    fn visit_terminator(&mut self,
+                        bb: BasicBlock,
+                        terminator: &Terminator<'tcx>,
+                        location: Location) {
+        self.nest(|this| this.super_terminator(bb, terminator, location));
     }
 }
 
@@ -1012,10 +1019,6 @@ fn run_pass<'a>(&mut self,
                     if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
                         infcx.report_fulfillment_errors(&err);
                     }
-
-                    if let Err(errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) {
-                        infcx.report_fulfillment_errors_as_warnings(&errors, id);
-                    }
                 });
             }
         }
index bbd2a93659b0aff480d70a5ba03d7113c597083c..21d4ae595e8ac2462023fdca6fe34b0a81cd9419 100644 (file)
@@ -68,17 +68,20 @@ fn visit_span(&mut self, span: &Span) {
         }
     }
 
-    fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, _context: visit::LvalueContext) {
-        self.sanitize_lvalue(lvalue);
+    fn visit_lvalue(&mut self,
+                    lvalue: &Lvalue<'tcx>,
+                    _context: visit::LvalueContext,
+                    location: Location) {
+        self.sanitize_lvalue(lvalue, location);
     }
 
-    fn visit_constant(&mut self, constant: &Constant<'tcx>) {
-        self.super_constant(constant);
+    fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
+        self.super_constant(constant, location);
         self.sanitize_type(constant, constant.ty);
     }
 
-    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
-        self.super_rvalue(rvalue);
+    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
+        self.super_rvalue(rvalue, location);
         if let Some(ty) = rvalue.ty(self.mir, self.tcx()) {
             self.sanitize_type(rvalue, ty);
         }
@@ -124,7 +127,7 @@ fn sanitize_type(&mut self, parent: &fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
 
-    fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>) -> LvalueTy<'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 },
@@ -136,14 +139,14 @@ fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>) -> LvalueTy<'tcx> {
                 LvalueTy::Ty { ty: self.mir.return_ty }
             }
             Lvalue::Projection(ref proj) => {
-                let base_ty = self.sanitize_lvalue(&proj.base);
+                let base_ty = self.sanitize_lvalue(&proj.base, location);
                 if let LvalueTy::Ty { ty } = base_ty {
                     if ty.references_error() {
                         assert!(self.errors_reported);
                         return LvalueTy::Ty { ty: self.tcx().types.err };
                     }
                 }
-                self.sanitize_projection(base_ty, &proj.elem, lvalue)
+                self.sanitize_projection(base_ty, &proj.elem, lvalue, location)
             }
         }
     }
@@ -151,7 +154,8 @@ fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>) -> LvalueTy<'tcx> {
     fn sanitize_projection(&mut self,
                            base: LvalueTy<'tcx>,
                            pi: &LvalueElem<'tcx>,
-                           lvalue: &Lvalue<'tcx>)
+                           lvalue: &Lvalue<'tcx>,
+                           location: Location)
                            -> LvalueTy<'tcx> {
         debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, lvalue);
         let tcx = self.tcx();
@@ -168,7 +172,7 @@ fn sanitize_projection(&mut self,
                 }
             }
             ProjectionElem::Index(ref i) => {
-                self.visit_operand(i);
+                self.visit_operand(i, location);
                 let index_ty = i.ty(self.mir, tcx);
                 if index_ty != tcx.types.usize {
                     LvalueTy::Ty {
index 46124d0f97359e65338234f0a61d81b7b9eb8455..dde1a4a759563dffd179aa7ede1cfe538cfb911f 100644 (file)
@@ -20,6 +20,7 @@
 use rustc::session::Session;
 use syntax::ast::*;
 use syntax::attr;
+use syntax::codemap::Spanned;
 use syntax::parse::token::{self, keywords};
 use syntax::visit::{self, Visitor};
 use syntax_pos::Span;
@@ -69,6 +70,18 @@ fn check_decl_no_pat<ReportFn: Fn(Span, bool)>(&self, decl: &FnDecl, report_err:
             }
         }
     }
+
+    fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) {
+        match constness.node {
+            Constness::Const => {
+                struct_span_err!(self.session, constness.span, E0379,
+                                 "trait fns cannot be declared const")
+                    .span_label(constness.span, &format!("trait fns cannot be const"))
+                    .emit();
+            }
+            _ => {}
+        }
+    }
 }
 
 impl<'a> Visitor for AstValidator<'a> {
@@ -146,6 +159,9 @@ fn visit_item(&mut self, item: &Item) {
                 self.invalid_visibility(&item.vis, item.span, None);
                 for impl_item in impl_items {
                     self.invalid_visibility(&impl_item.vis, impl_item.span, None);
+                    if let ImplItemKind::Method(ref sig, _) = impl_item.node {
+                        self.check_trait_fn_not_const(sig.constness);
+                    }
                 }
             }
             ItemKind::Impl(_, _, _, None, _, _) => {
@@ -169,6 +185,13 @@ fn visit_item(&mut self, item: &Item) {
                     }
                 }
             }
+            ItemKind::Trait(_, _, _, ref trait_items) => {
+                for trait_item in trait_items {
+                    if let TraitItemKind::Method(ref sig, _) = trait_item.node {
+                        self.check_trait_fn_not_const(sig.constness);
+                    }
+                }
+            }
             ItemKind::Mod(_) => {
                 // Ensure that `path` attributes on modules are recorded as used (c.f. #35584).
                 attr::first_attr_value_str_by_name(&item.attrs, "path");
index b116ab7b3161abf628712357973b2d0b023a45b2..2d1b6e1315f8bc810722d68e637a4eae3247afb1 100644 (file)
@@ -147,7 +147,8 @@ fn fn_like(&mut self,
         }
 
         let mode = match fk {
-            FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _, _) => Mode::ConstFn,
+            FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _, _)
+                => Mode::ConstFn,
             FnKind::Method(_, m, _, _) => {
                 if m.constness == hir::Constness::Const {
                     Mode::ConstFn
@@ -683,7 +684,7 @@ fn borrow(&mut self,
               borrow_id: ast::NodeId,
               _borrow_span: Span,
               cmt: mc::cmt<'tcx>,
-              _loan_region: ty::Region,
+              _loan_region: &'tcx ty::Region,
               bk: ty::BorrowKind,
               loan_cause: euv::LoanCause) {
         // Kind of hacky, but we allow Unsafe coercions in constants.
index 7049040678e39f706499e9a7cc920dfe89f797aa..89b8aa81411b381ed7b1de79470440acb81e2be0 100644 (file)
@@ -176,6 +176,13 @@ fn some_func() {
 ```
 "##,
 
+E0379: r##"
+Trait methods cannot be declared `const` by design. For more information, see
+[RFC 911].
+
+[RFC 911]: https://github.com/rust-lang/rfcs/pull/911
+"##,
+
 E0449: r##"
 A visibility qualifier was used when it was unnecessary. Erroneous code
 examples:
index 782ee34edd4f98ec90c45b2716b332bd2e19b79f..c3ef5a72a2944e8b2c2a092e69d8535599679c88 100644 (file)
@@ -88,7 +88,7 @@ fn borrow(&mut self,
               _borrow_id: ast::NodeId,
               _borrow_span: Span,
               _cmt: mc::cmt,
-              _loan_region: ty::Region,
+              _loan_region: &'tcx ty::Region,
               _bk: ty::BorrowKind,
               _loan_cause: euv::LoanCause) {
     }
index 8b2943a33c006aaced7fd7cee377a241ff187467..d23f77af321552683c4f07b052f6f9142866f6fa 100644 (file)
@@ -126,7 +126,7 @@ fn new(v: &'a CheckCrateVisitor<'a, 'ast>,
             idstack: Vec::new(),
         }
     }
-    fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F)
+    fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F, span: Span)
         where F: Fn(&mut Self)
     {
         if self.idstack.iter().any(|&x| x == id) {
@@ -150,7 +150,9 @@ fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F)
                                      "recursive static");
                 }
             } else {
-                span_err!(self.sess, *self.root_span, E0265, "recursive constant");
+                struct_span_err!(self.sess, span, E0265, "recursive constant")
+                    .span_label(span, &format!("recursion not allowed in constant"))
+                    .emit();
             }
             return;
         }
@@ -203,7 +205,7 @@ fn populate_enum_discriminants(&self, enum_definition: &'ast hir::EnumDef) {
 
 impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
     fn visit_item(&mut self, it: &'ast hir::Item) {
-        self.with_item_id_pushed(it.id, |v| intravisit::walk_item(v, it));
+        self.with_item_id_pushed(it.id, |v| intravisit::walk_item(v, it), it.span);
     }
 
     fn visit_enum_def(&mut self,
@@ -233,16 +235,16 @@ fn visit_variant(&mut self,
         // If `maybe_expr` is `None`, that's because no discriminant is
         // specified that affects this variant. Thus, no risk of recursion.
         if let Some(expr) = maybe_expr {
-            self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr));
+            self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr), expr.span);
         }
     }
 
     fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
-        self.with_item_id_pushed(ti.id, |v| intravisit::walk_trait_item(v, ti));
+        self.with_item_id_pushed(ti.id, |v| intravisit::walk_trait_item(v, ti), ti.span);
     }
 
     fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
-        self.with_item_id_pushed(ii.id, |v| intravisit::walk_impl_item(v, ii));
+        self.with_item_id_pushed(ii.id, |v| intravisit::walk_impl_item(v, ii), ii.span);
     }
 
     fn visit_expr(&mut self, e: &'ast hir::Expr) {
index e60a657ba193d9829e9844b586c825c3c138629f..91e0fd636c9c153d41bc5cfc67df4726a95524c8 100644 (file)
@@ -27,7 +27,7 @@
 //!
 //! extern crate rustc;
 //!
-//! use rustc::plugin::Registry;
+//! use rustc_plugin::Registry;
 //!
 //! #[plugin_registrar]
 //! pub fn plugin_registrar(reg: &mut Registry) {
index fb68eae96476f718d3bd19976e80ddb989b3952a..9e56397bc99e9ff6bb8031cd0d4f1f047cf0c4e4 100644 (file)
@@ -20,8 +20,6 @@
 use std::mem;
 use std::path::PathBuf;
 use syntax::ast;
-use syntax::ptr::P;
-use syntax::attr::AttrMetaMethods;
 use syntax_pos::{Span, COMMAND_LINE_SP};
 
 /// Pointer to a registrar function.
@@ -30,7 +28,7 @@
 
 pub struct PluginRegistrar {
     pub fun: PluginRegistrarFun,
-    pub args: Vec<P<ast::MetaItem>>,
+    pub args: Vec<ast::NestedMetaItem>,
 }
 
 struct PluginLoader<'a> {
@@ -69,13 +67,14 @@ pub fn load_plugins(sess: &Session,
             };
 
             for plugin in plugins {
-                if plugin.value_str().is_some() {
-                    call_malformed_plugin_attribute(sess, attr.span);
-                    continue;
+                // plugins must have a name and can't be key = value
+                match plugin.name() {
+                    Some(ref name) if !plugin.is_value_str() => {
+                        let args = plugin.meta_item_list().map(ToOwned::to_owned);
+                        loader.load_plugin(plugin.span, name, args.unwrap_or_default());
+                    },
+                    _ => call_malformed_plugin_attribute(sess, attr.span),
                 }
-
-                let args = plugin.meta_item_list().map(ToOwned::to_owned).unwrap_or_default();
-                loader.load_plugin(plugin.span, &plugin.name(), args);
             }
         }
     }
@@ -102,7 +101,7 @@ fn new(sess: &'a Session,
         }
     }
 
-    fn load_plugin(&mut self, span: Span, name: &str, args: Vec<P<ast::MetaItem>>) {
+    fn load_plugin(&mut self, span: Span, name: &str, args: Vec<ast::NestedMetaItem>) {
         let registrar = self.reader.find_plugin_registrar(span, name);
 
         if let Some((lib, svh, index)) = registrar {
index 54fa0197de4fe0fcf2ee7013308ce69a3cb45701..5ae6584aed4259ed204fd71bf96a67fa6a1a103c 100644 (file)
@@ -19,7 +19,6 @@
 use syntax::ext::base::{IdentTT, MultiModifier, MultiDecorator};
 use syntax::ext::base::{MacroExpanderFn, MacroRulesTT};
 use syntax::parse::token;
-use syntax::ptr::P;
 use syntax::ast;
 use syntax::feature_gate::AttributeType;
 use syntax_pos::Span;
@@ -41,7 +40,7 @@ pub struct Registry<'a> {
     pub sess: &'a Session,
 
     #[doc(hidden)]
-    pub args_hidden: Option<Vec<P<ast::MetaItem>>>,
+    pub args_hidden: Option<Vec<ast::NestedMetaItem>>,
 
     #[doc(hidden)]
     pub krate_span: Span,
@@ -95,7 +94,7 @@ pub fn new(sess: &'a Session, krate: &ast::Crate) -> Registry<'a> {
     ///
     /// Returns empty slice in case the plugin was loaded
     /// with `--extra-plugins`
-    pub fn args<'b>(&'b self) -> &'b [P<ast::MetaItem>] {
+    pub fn args<'b>(&'b self) -> &'b [ast::NestedMetaItem] {
         self.args_hidden.as_ref().map(|v| &v[..]).unwrap_or(&[])
     }
 
index de9ddcd934216e4cbcecf16de4c0cbdffc8a6d05..41b7c51e3009026dae4162849c2a5aa042b0b83e 100644 (file)
@@ -384,8 +384,10 @@ fn item_is_accessible(&self, did: DefId) -> bool {
     fn check_field(&mut self, span: Span, def: ty::AdtDef<'tcx>, field: ty::FieldDef<'tcx>) {
         if def.adt_kind() == ty::AdtKind::Struct &&
            !field.vis.is_accessible_from(self.curitem, &self.tcx.map) {
-            span_err!(self.tcx.sess, span, E0451, "field `{}` of struct `{}` is private",
-                      field.name, self.tcx.item_path_str(def.did));
+            struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of struct `{}` is private",
+                      field.name, self.tcx.item_path_str(def.did))
+                .span_label(span, &format!("field `{}` is private", field.name))
+                .emit();
         }
     }
 
@@ -425,14 +427,19 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
                 let method = self.tcx.tables.borrow().method_map[&method_call];
                 self.check_method(expr.span, method.def_id);
             }
-            hir::ExprStruct(..) => {
+            hir::ExprStruct(_, ref fields, _) => {
                 let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap();
                 let variant = adt.variant_of_def(self.tcx.expect_def(expr.id));
                 // RFC 736: ensure all unmentioned fields are visible.
                 // Rather than computing the set of unmentioned fields
                 // (i.e. `all_fields - fields`), just check them all.
-                for field in &variant.fields {
-                    self.check_field(expr.span, adt, field);
+                for field in variant.fields.iter() {
+                    let span = if let Some(f) = fields.iter().find(|f| f.name.node == field.name) {
+                        f.span
+                    } else {
+                        expr.span
+                    };
+                    self.check_field(span, adt, field);
                 }
             }
             hir::ExprPath(..) => {
@@ -444,13 +451,32 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
                         }), ..}) => ty,
                         _ => expr_ty
                     }.ty_adt_def().unwrap();
-                    let any_priv = def.struct_variant().fields.iter().any(|f| {
-                        !f.vis.is_accessible_from(self.curitem, &self.tcx.map)
-                    });
-                    if any_priv {
-                        span_err!(self.tcx.sess, expr.span, E0450,
-                                  "cannot invoke tuple struct constructor with private \
-                                   fields");
+
+                    let private_indexes : Vec<_> = def.struct_variant().fields.iter().enumerate()
+                        .filter(|&(_,f)| {
+                            !f.vis.is_accessible_from(self.curitem, &self.tcx.map)
+                    }).map(|(n,&_)|n).collect();
+
+                    if !private_indexes.is_empty() {
+
+                        let mut error = struct_span_err!(self.tcx.sess, expr.span, E0450,
+                                                         "cannot invoke tuple struct constructor \
+                                                         with private fields");
+                        error.span_label(expr.span,
+                                         &format!("cannot construct with a private field"));
+
+                        if let Some(def_id) = self.tcx.map.as_local_node_id(def.did) {
+                            if let Some(hir::map::NodeItem(node)) = self.tcx.map.find(def_id) {
+                                if let hir::Item_::ItemStruct(ref tuple_data, _) = node.node {
+
+                                    for i in private_indexes {
+                                        error.span_label(tuple_data.fields()[i].span,
+                                                         &format!("private field declared here"));
+                                    }
+                                }
+                            }
+                        }
+                        error.emit();
                     }
                 }
             }
@@ -472,7 +498,7 @@ fn visit_pat(&mut self, pattern: &hir::Pat) {
                 let adt = self.tcx.pat_ty(pattern).ty_adt_def().unwrap();
                 let variant = adt.variant_of_def(self.tcx.expect_def(pattern.id));
                 for field in fields {
-                    self.check_field(pattern.span, adt, variant.field_named(field.node.name));
+                    self.check_field(field.span, adt, variant.field_named(field.node.name));
                 }
             }
             PatKind::TupleStruct(_, ref fields, ddpos) => {
@@ -964,8 +990,11 @@ fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) {
             if !vis.is_at_least(self.required_visibility, &self.tcx.map) {
                 if self.tcx.sess.features.borrow().pub_restricted ||
                    self.old_error_set.contains(&trait_ref.ref_id) {
-                    span_err!(self.tcx.sess, trait_ref.path.span, E0445,
-                              "private trait in public interface");
+                    struct_span_err!(self.tcx.sess, trait_ref.path.span, E0445,
+                                     "private trait in public interface")
+                        .span_label(trait_ref.path.span, &format!(
+                                    "private trait can't be public"))
+                        .emit();
                 } else {
                     self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
                                            node_id,
index 70e566de8a7be5ab9a53900cd82678e7268329fe..a9e3c6ffe9ed887d028208dab5d64fa7e49d70e3 100644 (file)
@@ -10,6 +10,7 @@
 
 use Resolver;
 use rustc::session::Session;
+use rustc::util::nodemap::FnvHashMap;
 use syntax::ast;
 use syntax::ext::hygiene::Mark;
 use syntax::fold::{self, Folder};
@@ -17,7 +18,6 @@
 use syntax::util::move_map::MoveMap;
 use syntax::util::small_vector::SmallVector;
 
-use std::collections::HashMap;
 use std::mem;
 
 impl<'a> Resolver<'a> {
@@ -31,7 +31,7 @@ pub fn assign_node_ids(&mut self, krate: ast::Crate) -> ast::Crate {
 
 struct NodeIdAssigner<'a> {
     sess: &'a Session,
-    macros_at_scope: &'a mut HashMap<ast::NodeId, Vec<Mark>>,
+    macros_at_scope: &'a mut FnvHashMap<ast::NodeId, Vec<Mark>>,
 }
 
 impl<'a> Folder for NodeIdAssigner<'a> {
index 116c1b7a6d06f811eb29829e316cfedfe093d1e6..3e9b37f0a95a713dcbec1414b417ef8185a4463c 100644 (file)
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use rustc::ty::{self, VariantKind};
 
+use std::cell::Cell;
+
 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::{Mutability, PathListItemKind};
-use syntax::ast::{StmtKind, TraitItemKind};
+use syntax::ast::{Mutability, StmtKind, TraitItemKind};
 use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
+use syntax::parse::token::keywords;
 use syntax::visit::{self, Visitor};
 
 use syntax_pos::{Span, DUMMY_SP};
@@ -56,12 +58,7 @@ impl<'b> Resolver<'b> {
     pub fn build_reduced_graph(&mut self, krate: &Crate) {
         let no_implicit_prelude = attr::contains_name(&krate.attrs, "no_implicit_prelude");
         self.graph_root.no_implicit_prelude.set(no_implicit_prelude);
-
-        let mut visitor = BuildReducedGraphVisitor {
-            parent: self.graph_root,
-            resolver: self,
-        };
-        visit::walk_crate(&mut visitor, krate);
+        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;
@@ -84,11 +81,10 @@ fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
     }
 
     /// Constructs the reduced graph for one item.
-    fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<'b>) {
-        let parent = *parent_ref;
+    fn build_reduced_graph_for_item(&mut self, item: &Item) {
+        let parent = self.current_module;
         let name = item.ident.name;
         let sp = item.span;
-        self.current_module = parent;
         let vis = self.resolve_visibility(&item.vis);
 
         match item.node {
@@ -130,15 +126,15 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<
 
                         let subclass = ImportDirectiveSubclass::single(binding.name, source_name);
                         let span = view_path.span;
-                        parent.add_import_directive(module_path, subclass, span, item.id, vis);
-                        self.unresolved_imports += 1;
+                        self.add_import_directive(module_path, subclass, span, item.id, vis);
                     }
                     ViewPathList(_, ref source_items) => {
                         // Make sure there's at most one `mod` import in the list.
                         let mod_spans = source_items.iter().filter_map(|item| {
-                            match item.node {
-                                PathListItemKind::Mod { .. } => Some(item.span),
-                                _ => None,
+                            if item.node.name.name == keywords::SelfValue.name() {
+                                Some(item.span)
+                            } else {
+                                None
                             }
                         }).collect::<Vec<Span>>();
 
@@ -153,10 +149,12 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<
                         }
 
                         for source_item in source_items {
-                            let (module_path, name, rename) = match source_item.node {
-                                PathListItemKind::Ident { name, rename, .. } =>
-                                    (module_path.clone(), name.name, rename.unwrap_or(name).name),
-                                PathListItemKind::Mod { rename, .. } => {
+                            let node = source_item.node;
+                            let (module_path, name, rename) = {
+                                if node.name.name != keywords::SelfValue.name() {
+                                    let rename = node.rename.unwrap_or(node.name).name;
+                                    (module_path.clone(), node.name.name, rename)
+                                } else {
                                     let name = match module_path.last() {
                                         Some(name) => *name,
                                         None => {
@@ -170,21 +168,22 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<
                                         }
                                     };
                                     let module_path = module_path.split_last().unwrap().1;
-                                    let rename = rename.map(|i| i.name).unwrap_or(name);
+                                    let rename = node.rename.map(|i| i.name).unwrap_or(name);
                                     (module_path.to_vec(), name, rename)
                                 }
                             };
                             let subclass = ImportDirectiveSubclass::single(rename, name);
-                            let (span, id) = (source_item.span, source_item.node.id());
-                            parent.add_import_directive(module_path, subclass, span, id, vis);
-                            self.unresolved_imports += 1;
+                            let (span, id) = (source_item.span, source_item.node.id);
+                            self.add_import_directive(module_path, subclass, span, id, vis);
                         }
                     }
                     ViewPathGlob(_) => {
-                        let subclass = GlobImport { is_prelude: is_prelude };
+                        let subclass = GlobImport {
+                            is_prelude: is_prelude,
+                            max_vis: Cell::new(ty::Visibility::PrivateExternal),
+                        };
                         let span = view_path.span;
-                        parent.add_import_directive(module_path, subclass, span, item.id, vis);
-                        self.unresolved_imports += 1;
+                        self.add_import_directive(module_path, subclass, span, item.id, vis);
                     }
                 }
             }
@@ -209,14 +208,16 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<
             ItemKind::Mod(..) => {
                 let parent_link = ModuleParentLink(parent, name);
                 let def = Def::Mod(self.definitions.local_def_id(item.id));
-                let module = self.new_module(parent_link, Some(def), false);
+                let module = self.new_module(parent_link, Some(def), Some(item.id));
                 module.no_implicit_prelude.set({
                     parent.no_implicit_prelude.get() ||
                         attr::contains_name(&item.attrs, "no_implicit_prelude")
                 });
                 self.define(parent, name, TypeNS, (module, sp, vis));
                 self.module_map.insert(item.id, module);
-                *parent_ref = module;
+
+                // Descend into the module.
+                self.current_module = module;
             }
 
             ItemKind::ForeignMod(..) => {}
@@ -245,7 +246,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<
             ItemKind::Enum(ref enum_definition, _) => {
                 let parent_link = ModuleParentLink(parent, name);
                 let def = Def::Enum(self.definitions.local_def_id(item.id));
-                let module = self.new_module(parent_link, Some(def), false);
+                let module = self.new_module(parent_link, Some(def), parent.normal_ancestor_id);
                 self.define(parent, name, TypeNS, (module, sp, vis));
 
                 for variant in &(*enum_definition).variants {
@@ -277,6 +278,8 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<
                 self.structs.insert(item_def_id, field_names);
             }
 
+            ItemKind::Union(..) => panic!("`union` is not yet implemented"),
+
             ItemKind::DefaultImpl(_, _) | ItemKind::Impl(..) => {}
 
             ItemKind::Trait(_, _, _, ref items) => {
@@ -285,7 +288,8 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<
                 // Add all the items within to a new module.
                 let parent_link = ModuleParentLink(parent, name);
                 let def = Def::Trait(def_id);
-                let module_parent = self.new_module(parent_link, Some(def), false);
+                let module_parent =
+                    self.new_module(parent_link, Some(def), parent.normal_ancestor_id);
                 self.define(parent, name, TypeNS, (module_parent, sp, vis));
 
                 // Add the names of all the items to the trait info.
@@ -309,6 +313,9 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<
             }
             ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"),
         }
+
+        visit::walk_item(&mut BuildReducedGraphVisitor { resolver: self }, item);
+        self.current_module = parent;
     }
 
     // Constructs the reduced graph for one variant. Variants exist in the
@@ -333,9 +340,8 @@ fn build_reduced_graph_for_variant(&mut self,
     }
 
     /// Constructs the reduced graph for one foreign item.
-    fn build_reduced_graph_for_foreign_item(&mut self,
-                                            foreign_item: &ForeignItem,
-                                            parent: Module<'b>) {
+    fn build_reduced_graph_for_foreign_item(&mut self, foreign_item: &ForeignItem) {
+        let parent = self.current_module;
         let name = foreign_item.ident.name;
 
         let def = match foreign_item.node {
@@ -346,12 +352,12 @@ fn build_reduced_graph_for_foreign_item(&mut self,
                 Def::Static(self.definitions.local_def_id(foreign_item.id), m)
             }
         };
-        self.current_module = parent;
         let vis = self.resolve_visibility(&foreign_item.vis);
         self.define(parent, name, ValueNS, (def, foreign_item.span, vis));
     }
 
-    fn build_reduced_graph_for_block(&mut self, block: &Block, parent: &mut Module<'b>) {
+    fn build_reduced_graph_for_block(&mut self, block: &Block) {
+        let parent = self.current_module;
         if self.block_needs_anonymous_module(block) {
             let block_id = block.id;
 
@@ -360,10 +366,13 @@ fn build_reduced_graph_for_block(&mut self, block: &Block, parent: &mut Module<'
                    block_id);
 
             let parent_link = BlockParentLink(parent, block_id);
-            let new_module = self.new_module(parent_link, None, false);
+            let new_module = self.new_module(parent_link, None, parent.normal_ancestor_id);
             self.module_map.insert(block_id, new_module);
-            *parent = new_module;
+            self.current_module = new_module; // Descend into the block.
         }
+
+        visit::walk_block(&mut BuildReducedGraphVisitor { resolver: self }, block);
+        self.current_module = parent;
     }
 
     /// Builds the reduced graph for a single item in an external crate.
@@ -389,7 +398,7 @@ fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, xcd
                 debug!("(building reduced graph for external crate) building module {} {:?}",
                        name, vis);
                 let parent_link = ModuleParentLink(parent, name);
-                let module = self.new_module(parent_link, Some(def), true);
+                let module = self.new_module(parent_link, Some(def), None);
                 let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis));
             }
             Def::Variant(_, variant_id) => {
@@ -431,7 +440,7 @@ fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, xcd
                 }
 
                 let parent_link = ModuleParentLink(parent, name);
-                let module = self.new_module(parent_link, Some(def), true);
+                let module = self.new_module(parent_link, Some(def), None);
                 let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis));
             }
             Def::TyAlias(..) | Def::AssociatedTy(..) => {
@@ -487,25 +496,18 @@ pub fn populate_module_if_necessary(&mut self, module: Module<'b>) {
 
 struct BuildReducedGraphVisitor<'a, 'b: 'a> {
     resolver: &'a mut Resolver<'b>,
-    parent: Module<'b>,
 }
 
 impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
     fn visit_item(&mut self, item: &Item) {
-        let old_parent = self.parent;
-        self.resolver.build_reduced_graph_for_item(item, &mut self.parent);
-        visit::walk_item(self, item);
-        self.parent = old_parent;
+        self.resolver.build_reduced_graph_for_item(item);
     }
 
     fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
-        self.resolver.build_reduced_graph_for_foreign_item(foreign_item, &self.parent);
+        self.resolver.build_reduced_graph_for_foreign_item(foreign_item);
     }
 
     fn visit_block(&mut self, block: &Block) {
-        let old_parent = self.parent;
-        self.resolver.build_reduced_graph_for_block(block, &mut self.parent);
-        visit::walk_block(self, block);
-        self.parent = old_parent;
+        self.resolver.build_reduced_graph_for_block(block);
     }
 }
index 3084d9abbe1e4f8cab3a93f271145c4ad03a8f9e..bc923ba29ca475356bae86488580d516c736ecdc 100644 (file)
@@ -101,7 +101,7 @@ fn visit_item(&mut self, item: &ast::Item) {
 
                     ViewPathList(_, ref list) => {
                         for i in list {
-                            self.check_import(i.node.id(), i.span);
+                            self.check_import(i.node.id, i.span);
                         }
                     }
                     ViewPathGlob(_) => {
index 11ef75ee6a8fc4fcc90596feebccca7687c16fb0..f8f90bdb4e7f5d561a0f5fc1208840dbfabe4c30 100644 (file)
@@ -891,7 +891,7 @@ fn main () {
 Erroneous code example:
 
 ```compile_fail,E0423
-struct Foo { a: bool};
+struct Foo { a: bool };
 
 let f = Foo();
 // error: `Foo` is a struct variant name, but this expression uses
@@ -1270,7 +1270,42 @@ trait Foo {}
 
 impl Foo for i32 {}
 ```
-"##
+"##,
+
+E0530: r##"
+A binding shadowed something it shouldn't.
+
+Erroneous code example:
+
+```compile_fail,E0530
+static TEST: i32 = 0;
+
+let r: (i32, i32) = (0, 0);
+match r {
+    TEST => {} // error: match bindings cannot shadow statics
+}
+```
+
+To fix this error, just change the binding's name in order to avoid shadowing
+one of the following:
+
+* struct name
+* struct/enum variant
+* static
+* const
+* associated const
+
+Fixed example:
+
+```
+static TEST: i32 = 0;
+
+let r: (i32, i32) = (0, 0);
+match r {
+    something => {} // ok!
+}
+```
+"##,
 
 }
 
@@ -1289,7 +1324,6 @@ impl Foo for i32 {}
 //  E0419, merged into 531
 //  E0420, merged into 532
 //  E0421, merged into 531
-    E0530, // X bindings cannot shadow Ys
     E0531, // unresolved pattern path kind `name`
     E0532, // expected pattern path kind, found another pattern path kind
 //  E0427, merged into 530
index d90a932a63d86081ae540569329326eb1ffe9902..1224c694a4e6e6e218083c67c031c996a8fccc99 100644 (file)
 use syntax::ast::{Local, Mutability, Pat, PatKind, Path};
 use syntax::ast::{PathSegment, PathParameters, QSelf, TraitItemKind, TraitRef, Ty, TyKind};
 
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 use errors::DiagnosticBuilder;
 
-use std::collections::{HashMap, HashSet};
 use std::cell::{Cell, RefCell};
 use std::fmt;
 use std::mem::replace;
@@ -102,7 +101,7 @@ enum ResolutionError<'a> {
     /// error E0402: cannot use an outer type parameter in this context
     OuterTypeParameterContext,
     /// error E0403: the name is already used for a type parameter in this type parameter list
-    NameAlreadyUsedInTypeParameterList(Name),
+    NameAlreadyUsedInTypeParameterList(Name, &'a Span),
     /// error E0404: is not a trait
     IsNotATrait(&'a str),
     /// error E0405: use of undeclared trait name
@@ -209,13 +208,17 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
                              E0402,
                              "cannot use an outer type parameter in this context")
         }
-        ResolutionError::NameAlreadyUsedInTypeParameterList(name) => {
-            struct_span_err!(resolver.session,
-                             span,
-                             E0403,
-                             "the name `{}` is already used for a type parameter in this type \
-                              parameter list",
-                             name)
+        ResolutionError::NameAlreadyUsedInTypeParameterList(name, first_use_span) => {
+             let mut err = struct_span_err!(resolver.session,
+                                            span,
+                                            E0403,
+                                            "the name `{}` is already used for a type parameter \
+                                            in this type parameter list",
+                                            name);
+             err.span_label(span, &format!("already used"));
+             err.span_label(first_use_span.clone(), &format!("first use of `{}`", name));
+             err
+
         }
         ResolutionError::IsNotATrait(name) => {
             let mut err = struct_span_err!(resolver.session,
@@ -237,28 +240,34 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
             err
         }
         ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
-            struct_span_err!(resolver.session,
-                             span,
-                             E0407,
-                             "method `{}` is not a member of trait `{}`",
-                             method,
-                             trait_)
+            let mut err = struct_span_err!(resolver.session,
+                                           span,
+                                           E0407,
+                                           "method `{}` is not a member of trait `{}`",
+                                           method,
+                                           trait_);
+            err.span_label(span, &format!("not a member of `{}`", trait_));
+            err
         }
         ResolutionError::TypeNotMemberOfTrait(type_, trait_) => {
-            struct_span_err!(resolver.session,
+            let mut err = struct_span_err!(resolver.session,
                              span,
                              E0437,
                              "type `{}` is not a member of trait `{}`",
                              type_,
-                             trait_)
+                             trait_);
+            err.span_label(span, &format!("not a member of trait `Foo`"));
+            err
         }
         ResolutionError::ConstNotMemberOfTrait(const_, trait_) => {
-            struct_span_err!(resolver.session,
+            let mut err = struct_span_err!(resolver.session,
                              span,
                              E0438,
                              "const `{}` is not a member of trait `{}`",
                              const_,
-                             trait_)
+                             trait_);
+            err.span_label(span, &format!("not a member of trait `Foo`"));
+            err
         }
         ResolutionError::VariableNotBoundInPattern(variable_name, from, to) => {
             struct_span_err!(resolver.session,
@@ -330,19 +339,23 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
             err
         }
         ResolutionError::StructVariantUsedAsFunction(path_name) => {
-            struct_span_err!(resolver.session,
+            let mut err = struct_span_err!(resolver.session,
                              span,
                              E0423,
                              "`{}` is the name of a struct or struct variant, but this expression \
                              uses it like a function name",
-                             path_name)
+                             path_name);
+            err.span_label(span, &format!("struct called like a function"));
+            err
         }
         ResolutionError::SelfNotAvailableInStaticMethod => {
-            struct_span_err!(resolver.session,
+            let mut err = struct_span_err!(resolver.session,
                              span,
                              E0424,
-                             "`self` is not available in a static method. Maybe a `self` \
-                             argument is missing?")
+                             "`self` is not available in a static method");
+            err.span_label(span, &format!("not available in static method"));
+            err.note(&format!("maybe a `self` argument is missing?"));
+            err
         }
         ResolutionError::UnresolvedName { path, message: msg, context, is_static_method,
                                           is_field, def } => {
@@ -384,11 +397,13 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
             err
         }
         ResolutionError::UndeclaredLabel(name) => {
-            struct_span_err!(resolver.session,
-                             span,
-                             E0426,
-                             "use of undeclared label `{}`",
-                             name)
+            let mut err = struct_span_err!(resolver.session,
+                                           span,
+                                           E0426,
+                                           "use of undeclared label `{}`",
+                                           name);
+            err.span_label(span, &format!("undeclared label `{}`",&name));
+            err
         }
         ResolutionError::SelfImportsOnlyAllowedWithin => {
             struct_span_err!(resolver.session,
@@ -412,10 +427,14 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
         }
         ResolutionError::UnresolvedImport(name) => {
             let msg = match name {
-                Some((n, p)) => format!("unresolved import `{}`{}", n, p),
+                Some((n, _)) => format!("unresolved import `{}`", n),
                 None => "unresolved import".to_owned(),
             };
-            struct_span_err!(resolver.session, span, E0432, "{}", msg)
+            let mut err = struct_span_err!(resolver.session, span, E0432, "{}", msg);
+            if let Some((_, p)) = name {
+                err.span_label(span, &p);
+            }
+            err
         }
         ResolutionError::FailedToResolve(msg) => {
             let mut err = struct_span_err!(resolver.session, span, E0433,
@@ -432,13 +451,15 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
                               closure form instead")
         }
         ResolutionError::AttemptToUseNonConstantValueInConstant => {
-            struct_span_err!(resolver.session,
+            let mut err = struct_span_err!(resolver.session,
                              span,
                              E0435,
-                             "attempt to use a non-constant value in a constant")
+                             "attempt to use a non-constant value in a constant");
+            err.span_label(span, &format!("non-constant used with constant"));
+            err
         }
         ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
-            let shadows_what = PathResolution::new(binding.def().unwrap()).kind_name();
+            let shadows_what = PathResolution::new(binding.def()).kind_name();
             let mut err = struct_span_err!(resolver.session,
                                            span,
                                            E0530,
@@ -476,7 +497,7 @@ struct BindingInfo {
 }
 
 // Map from the name in a pattern to its binding mode.
-type BindingMap = HashMap<ast::Ident, BindingInfo>;
+type BindingMap = FnvHashMap<ast::Ident, BindingInfo>;
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 enum PatternSource {
@@ -681,14 +702,14 @@ enum ModulePrefixResult<'a> {
 /// One local scope.
 #[derive(Debug)]
 struct Rib<'a> {
-    bindings: HashMap<ast::Ident, Def>,
+    bindings: FnvHashMap<ast::Ident, Def>,
     kind: RibKind<'a>,
 }
 
 impl<'a> Rib<'a> {
     fn new(kind: RibKind<'a>) -> Rib<'a> {
         Rib {
-            bindings: HashMap::new(),
+            bindings: FnvHashMap(),
             kind: kind,
         }
     }
@@ -718,7 +739,7 @@ impl<'a> LexicalScopeBinding<'a> {
     fn local_def(self) -> LocalDef {
         match self {
             LexicalScopeBinding::LocalDef(local_def) => local_def,
-            LexicalScopeBinding::Item(binding) => LocalDef::from_def(binding.def().unwrap()),
+            LexicalScopeBinding::Item(binding) => LocalDef::from_def(binding.def()),
         }
     }
 
@@ -728,10 +749,6 @@ fn item(self) -> Option<&'a NameBinding<'a>> {
             _ => None,
         }
     }
-
-    fn module(self) -> Option<Module<'a>> {
-        self.item().and_then(NameBinding::module)
-    }
 }
 
 /// The link from a module up to its nearest parent node.
@@ -747,16 +764,18 @@ pub struct ModuleS<'a> {
     parent_link: ParentLink<'a>,
     def: Option<Def>,
 
+    // The node id of the closest normal module (`mod`) ancestor (including this module).
+    normal_ancestor_id: Option<NodeId>,
+
     // If the module is an extern crate, `def` is root of the external crate and `extern_crate_id`
     // is the NodeId of the local `extern crate` item (otherwise, `extern_crate_id` is None).
     extern_crate_id: Option<NodeId>,
 
-    resolutions: RefCell<HashMap<(Name, Namespace), &'a RefCell<NameResolution<'a>>>>,
-    unresolved_imports: RefCell<Vec<&'a ImportDirective<'a>>>,
+    resolutions: RefCell<FnvHashMap<(Name, Namespace), &'a RefCell<NameResolution<'a>>>>,
 
     no_implicit_prelude: Cell<bool>,
 
-    glob_importers: RefCell<Vec<(Module<'a>, &'a ImportDirective<'a>)>>,
+    glob_importers: RefCell<Vec<&'a ImportDirective<'a>>>,
     globs: RefCell<Vec<&'a ImportDirective<'a>>>,
 
     // Used to memoize the traits in this module for faster searches through all traits in scope.
@@ -766,29 +785,24 @@ pub struct ModuleS<'a> {
     // access the children must be preceded with a
     // `populate_module_if_necessary` call.
     populated: Cell<bool>,
-
-    arenas: &'a ResolverArenas<'a>,
 }
 
 pub type Module<'a> = &'a ModuleS<'a>;
 
 impl<'a> ModuleS<'a> {
-    fn new(parent_link: ParentLink<'a>,
-           def: Option<Def>,
-           external: bool,
-           arenas: &'a ResolverArenas<'a>) -> Self {
+    fn new(parent_link: ParentLink<'a>, def: Option<Def>, normal_ancestor_id: Option<NodeId>)
+           -> Self {
         ModuleS {
             parent_link: parent_link,
             def: def,
+            normal_ancestor_id: normal_ancestor_id,
             extern_crate_id: None,
-            resolutions: RefCell::new(HashMap::new()),
-            unresolved_imports: RefCell::new(Vec::new()),
+            resolutions: RefCell::new(FnvHashMap()),
             no_implicit_prelude: Cell::new(false),
             glob_importers: RefCell::new(Vec::new()),
             globs: RefCell::new((Vec::new())),
             traits: RefCell::new(None),
-            populated: Cell::new(!external),
-            arenas: arenas
+            populated: Cell::new(normal_ancestor_id.is_some()),
         }
     }
 
@@ -816,6 +830,13 @@ fn is_trait(&self) -> bool {
             _ => false,
         }
     }
+
+    fn parent(&self) -> Option<&'a Self> {
+        match self.parent_link {
+            ModuleParentLink(parent, _) | BlockParentLink(parent, _) => Some(parent),
+            NoParentLink => None,
+        }
+    }
 }
 
 impl<'a> fmt::Debug for ModuleS<'a> {
@@ -850,32 +871,35 @@ enum NameBindingKind<'a> {
         binding: &'a NameBinding<'a>,
         directive: &'a ImportDirective<'a>,
     },
+    Ambiguity {
+        b1: &'a NameBinding<'a>,
+        b2: &'a NameBinding<'a>,
+    }
 }
 
 #[derive(Clone, Debug)]
 struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>);
 
 impl<'a> NameBinding<'a> {
-    fn module(&self) -> Option<Module<'a>> {
+    fn module(&self) -> Result<Module<'a>, bool /* true if an error has already been reported */> {
         match self.kind {
-            NameBindingKind::Module(module) => Some(module),
-            NameBindingKind::Def(_) => None,
+            NameBindingKind::Module(module) => Ok(module),
             NameBindingKind::Import { binding, .. } => binding.module(),
+            NameBindingKind::Def(Def::Err) => Err(true),
+            NameBindingKind::Def(_) => Err(false),
+            NameBindingKind::Ambiguity { ..  } => Err(false),
         }
     }
 
-    fn def(&self) -> Option<Def> {
+    fn def(&self) -> Def {
         match self.kind {
-            NameBindingKind::Def(def) => Some(def),
-            NameBindingKind::Module(module) => module.def,
+            NameBindingKind::Def(def) => def,
+            NameBindingKind::Module(module) => module.def.unwrap(),
             NameBindingKind::Import { binding, .. } => binding.def(),
+            NameBindingKind::Ambiguity { .. } => Def::Err,
         }
     }
 
-    fn is_pseudo_public(&self) -> bool {
-        self.pseudo_vis() == ty::Visibility::Public
-    }
-
     // We sometimes need to treat variants as `pub` for backwards compatibility
     fn pseudo_vis(&self) -> ty::Visibility {
         if self.is_variant() { ty::Visibility::Public } else { self.vis }
@@ -889,7 +913,7 @@ fn is_variant(&self) -> bool {
     }
 
     fn is_extern_crate(&self) -> bool {
-        self.module().and_then(|module| module.extern_crate_id).is_some()
+        self.module().ok().and_then(|module| module.extern_crate_id).is_some()
     }
 
     fn is_import(&self) -> bool {
@@ -902,26 +926,35 @@ fn is_import(&self) -> bool {
     fn is_glob_import(&self) -> bool {
         match self.kind {
             NameBindingKind::Import { directive, .. } => directive.is_glob(),
+            NameBindingKind::Ambiguity { .. } => true,
             _ => false,
         }
     }
 
     fn is_importable(&self) -> bool {
-        match self.def().unwrap() {
+        match self.def() {
             Def::AssociatedConst(..) | Def::Method(..) | Def::AssociatedTy(..) => false,
             _ => true,
         }
     }
+
+    fn ambiguity(&self) -> Option<(&'a NameBinding<'a>, &'a NameBinding<'a>)> {
+        match self.kind {
+            NameBindingKind::Ambiguity { b1, b2 } => Some((b1, b2)),
+            NameBindingKind::Import { binding, .. } => binding.ambiguity(),
+            _ => None,
+        }
+    }
 }
 
 /// Interns the names of the primitive types.
 struct PrimitiveTypeTable {
-    primitive_types: HashMap<Name, PrimTy>,
+    primitive_types: FnvHashMap<Name, PrimTy>,
 }
 
 impl PrimitiveTypeTable {
     fn new() -> PrimitiveTypeTable {
-        let mut table = PrimitiveTypeTable { primitive_types: HashMap::new() };
+        let mut table = PrimitiveTypeTable { primitive_types: FnvHashMap() };
 
         table.intern("bool", TyBool);
         table.intern("char", TyChar);
@@ -955,7 +988,7 @@ pub struct Resolver<'a> {
 
     // Maps the node id of a statement to the expansions of the `macro_rules!`s
     // immediately above the statement (if appropriate).
-    macros_at_scope: HashMap<NodeId, Vec<Mark>>,
+    macros_at_scope: FnvHashMap<NodeId, Vec<Mark>>,
 
     graph_root: Module<'a>,
 
@@ -965,8 +998,11 @@ pub struct Resolver<'a> {
 
     structs: FnvHashMap<DefId, Vec<Name>>,
 
-    // The number of imports that are currently unresolved.
-    unresolved_imports: usize,
+    // All imports known to succeed or fail.
+    determined_imports: Vec<&'a ImportDirective<'a>>,
+
+    // All non-determined imports.
+    indeterminate_imports: Vec<&'a ImportDirective<'a>>,
 
     // The module that represents the current item scope.
     current_module: Module<'a>,
@@ -1022,13 +1058,16 @@ pub struct Resolver<'a> {
     // all imports, but only glob imports are actually interesting).
     pub glob_map: GlobMap,
 
-    used_imports: HashSet<(NodeId, Namespace)>,
-    used_crates: HashSet<CrateNum>,
+    used_imports: FnvHashSet<(NodeId, Namespace)>,
+    used_crates: FnvHashSet<CrateNum>,
     pub maybe_unused_trait_imports: NodeSet,
 
     privacy_errors: Vec<PrivacyError<'a>>,
+    ambiguity_errors: Vec<(Span, Name, &'a NameBinding<'a>)>,
 
     arenas: &'a ResolverArenas<'a>,
+    dummy_binding: &'a NameBinding<'a>,
+    new_import_semantics: bool, // true if `#![feature(item_like_imports)]`
 }
 
 pub struct ResolverArenas<'a> {
@@ -1063,15 +1102,12 @@ fn alloc_name_resolution(&'a self) -> &'a RefCell<NameResolution<'a>> {
 }
 
 impl<'a> ty::NodeIdTree for Resolver<'a> {
-    fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool {
-        let ancestor = self.definitions.local_def_id(ancestor);
-        let mut module = *self.module_map.get(&node).unwrap();
-        while module.def_id() != Some(ancestor) {
-            let module_parent = match self.get_nearest_normal_module_parent(module) {
-                Some(parent) => parent,
+    fn is_descendant_of(&self, mut node: NodeId, ancestor: NodeId) -> bool {
+        while node != ancestor {
+            node = match self.module_map[&node].parent() {
+                Some(parent) => parent.normal_ancestor_id.unwrap(),
                 None => return false,
-            };
-            module = module_parent;
+            }
         }
         true
     }
@@ -1081,7 +1117,7 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
     fn resolve_generated_global_path(&mut self, path: &hir::Path, is_value: bool) -> Def {
         let namespace = if is_value { ValueNS } else { TypeNS };
         match self.resolve_crate_relative_path(path.span, &path.segments, namespace) {
-            Ok(binding) => binding.def().unwrap(),
+            Ok(binding) => binding.def(),
             Err(true) => Def::Err,
             Err(false) => {
                 let path_name = &format!("{}", path);
@@ -1134,7 +1170,7 @@ pub fn new(session: &'a Session, make_glob_map: MakeGlobMap, arenas: &'a Resolve
                -> Resolver<'a> {
         let root_def_id = DefId::local(CRATE_DEF_INDEX);
         let graph_root =
-            ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false, arenas);
+            ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), Some(CRATE_NODE_ID));
         let graph_root = arenas.alloc_module(graph_root);
         let mut module_map = NodeMap();
         module_map.insert(CRATE_NODE_ID, graph_root);
@@ -1143,7 +1179,7 @@ pub fn new(session: &'a Session, make_glob_map: MakeGlobMap, arenas: &'a Resolve
             session: session,
 
             definitions: Definitions::new(),
-            macros_at_scope: HashMap::new(),
+            macros_at_scope: FnvHashMap(),
 
             // The outermost module has def ID 0; this is not reflected in the
             // AST.
@@ -1153,7 +1189,8 @@ pub fn new(session: &'a Session, make_glob_map: MakeGlobMap, arenas: &'a Resolve
             trait_item_map: FnvHashMap(),
             structs: FnvHashMap(),
 
-            unresolved_imports: 0,
+            determined_imports: Vec::new(),
+            indeterminate_imports: Vec::new(),
 
             current_module: graph_root,
             value_ribs: vec![Rib::new(ModuleRibKind(graph_root))],
@@ -1176,13 +1213,20 @@ pub fn new(session: &'a Session, make_glob_map: MakeGlobMap, arenas: &'a Resolve
             make_glob_map: make_glob_map == MakeGlobMap::Yes,
             glob_map: NodeMap(),
 
-            used_imports: HashSet::new(),
-            used_crates: HashSet::new(),
+            used_imports: FnvHashSet(),
+            used_crates: FnvHashSet(),
             maybe_unused_trait_imports: NodeSet(),
 
             privacy_errors: Vec::new(),
+            ambiguity_errors: Vec::new(),
 
             arenas: arenas,
+            dummy_binding: arenas.alloc_name_binding(NameBinding {
+                kind: NameBindingKind::Def(Def::Err),
+                span: DUMMY_SP,
+                vis: ty::Visibility::Public,
+            }),
+            new_import_semantics: session.features.borrow().item_like_imports,
         }
     }
 
@@ -1202,17 +1246,20 @@ pub fn resolve_crate(&mut self, krate: &Crate) {
         visit::walk_crate(self, krate);
 
         check_unused::check_crate(self, krate);
-        self.report_privacy_errors();
+        self.report_errors();
     }
 
-    fn new_module(&self, parent_link: ParentLink<'a>, def: Option<Def>, external: bool)
+    fn new_module(&self,
+                  parent_link: ParentLink<'a>,
+                  def: Option<Def>,
+                  normal_ancestor_id: Option<NodeId>)
                   -> Module<'a> {
-        self.arenas.alloc_module(ModuleS::new(parent_link, def, external, self.arenas))
+        self.arenas.alloc_module(ModuleS::new(parent_link, def, normal_ancestor_id))
     }
 
     fn new_extern_crate_module(&self, parent_link: ParentLink<'a>, def: Def, local_node_id: NodeId)
                                -> Module<'a> {
-        let mut module = ModuleS::new(parent_link, Some(def), false, self.arenas);
+        let mut module = ModuleS::new(parent_link, Some(def), Some(local_node_id));
         module.extern_crate_id = Some(local_node_id);
         self.arenas.modules.alloc(module)
     }
@@ -1221,9 +1268,10 @@ fn get_ribs<'b>(&'b mut self, ns: Namespace) -> &'b mut Vec<Rib<'a>> {
         match ns { ValueNS => &mut self.value_ribs, TypeNS => &mut self.type_ribs }
     }
 
-    fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) {
+    fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
+                  -> bool /* true if an error was reported */ {
         // track extern crates for unused_extern_crate lint
-        if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleS::def_id) {
+        if let Some(DefId { krate, .. }) = binding.module().ok().and_then(ModuleS::def_id) {
             self.used_crates.insert(krate);
         }
 
@@ -1231,6 +1279,13 @@ fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>
             self.used_imports.insert((directive.id, ns));
             self.add_to_glob_map(directive.id, name);
         }
+
+        if binding.ambiguity().is_some() {
+            self.ambiguity_errors.push((span, name, binding));
+            return true;
+        }
+
+        false
     }
 
     fn add_to_glob_map(&mut self, id: NodeId, name: Name) {
@@ -1239,19 +1294,32 @@ fn add_to_glob_map(&mut self, id: NodeId, name: Name) {
         }
     }
 
+    fn expect_module(&mut self, name: Name, binding: &'a NameBinding<'a>, span: Option<Span>)
+                     -> ResolveResult<Module<'a>> {
+        match binding.module() {
+            Ok(module) => Success(module),
+            Err(true) => Failed(None),
+            Err(false) => {
+                let msg = format!("Not a module `{}`", name);
+                Failed(span.map(|span| (span, msg)))
+            }
+        }
+    }
+
     /// Resolves the given module path from the given root `search_module`.
     fn resolve_module_path_from_root(&mut self,
                                      mut search_module: Module<'a>,
                                      module_path: &[Name],
                                      index: usize,
-                                     span: Span)
+                                     span: Option<Span>)
                                      -> ResolveResult<Module<'a>> {
-        fn search_parent_externals(needle: Name, module: Module) -> Option<Module> {
-            match module.resolve_name(needle, TypeNS, false) {
+        fn search_parent_externals<'a>(this: &mut Resolver<'a>, needle: Name, module: Module<'a>)
+                                       -> Option<Module<'a>> {
+            match this.resolve_name_in_module(module, needle, TypeNS, false, None) {
                 Success(binding) if binding.is_extern_crate() => Some(module),
                 _ => match module.parent_link {
                     ModuleParentLink(ref parent, _) => {
-                        search_parent_externals(needle, parent)
+                        search_parent_externals(this, needle, parent)
                     }
                     _ => None,
                 },
@@ -1266,16 +1334,17 @@ fn search_parent_externals(needle: Name, module: Module) -> Option<Module> {
         // modules as we go.
         while index < module_path_len {
             let name = module_path[index];
-            match self.resolve_name_in_module(search_module, name, TypeNS, false, true) {
-                Failed(None) => {
+            match self.resolve_name_in_module(search_module, name, TypeNS, false, span) {
+                Failed(_) => {
                     let segment_name = name.as_str();
                     let module_name = module_to_string(search_module);
                     let msg = if "???" == &module_name {
-                        match search_parent_externals(name, &self.current_module) {
+                        let current_module = self.current_module;
+                        match search_parent_externals(self, name, current_module) {
                             Some(module) => {
                                 let path_str = names_to_string(module_path);
                                 let target_mod_str = module_to_string(&module);
-                                let current_mod_str = module_to_string(&self.current_module);
+                                let current_mod_str = module_to_string(current_module);
 
                                 let prefix = if target_mod_str == current_mod_str {
                                     "self::".to_string()
@@ -1291,9 +1360,8 @@ fn search_parent_externals(needle: Name, module: Module) -> Option<Module> {
                         format!("Could not find `{}` in `{}`", segment_name, module_name)
                     };
 
-                    return Failed(Some((span, msg)));
+                    return Failed(span.map(|span| (span, msg)));
                 }
-                Failed(err) => return Failed(err),
                 Indeterminate => {
                     debug!("(resolving module path for import) module resolution is \
                             indeterminate: {}",
@@ -1303,12 +1371,9 @@ fn search_parent_externals(needle: Name, module: Module) -> Option<Module> {
                 Success(binding) => {
                     // Check to see whether there are type bindings, and, if
                     // so, whether there is a module within.
-                    if let Some(module_def) = binding.module() {
-                        self.check_privacy(name, binding, span);
-                        search_module = module_def;
-                    } else {
-                        let msg = format!("Not a module `{}`", name);
-                        return Failed(Some((span, msg)));
+                    match self.expect_module(name, binding, span) {
+                        Success(module) => search_module = module,
+                        result @ _ => return result,
                     }
                 }
             }
@@ -1324,7 +1389,7 @@ fn search_parent_externals(needle: Name, module: Module) -> Option<Module> {
     fn resolve_module_path(&mut self,
                            module_path: &[Name],
                            use_lexical_scope: UseLexicalScopeFlag,
-                           span: Span)
+                           span: Option<Span>)
                            -> ResolveResult<Module<'a>> {
         if module_path.len() == 0 {
             return Success(self.graph_root) // Use the crate root
@@ -1361,13 +1426,20 @@ fn resolve_module_path(&mut self,
                         // first component of the path in the current lexical
                         // scope and then proceed to resolve below that.
                         let ident = ast::Ident::with_empty_ctxt(module_path[0]);
-                        match self.resolve_ident_in_lexical_scope(ident, TypeNS, true)
-                                  .and_then(LexicalScopeBinding::module) {
-                            None => return Failed(None),
-                            Some(containing_module) => {
-                                search_module = containing_module;
-                                start_index = 1;
+                        let lexical_binding =
+                            self.resolve_ident_in_lexical_scope(ident, TypeNS, span);
+                        if let Some(binding) = lexical_binding.and_then(LexicalScopeBinding::item) {
+                            match self.expect_module(ident.name, binding, span) {
+                                Success(containing_module) => {
+                                    search_module = containing_module;
+                                    start_index = 1;
+                                }
+                                result @ _ => return result,
                             }
+                        } else {
+                            let msg =
+                                format!("Use of undeclared type or module `{}`", ident.name);
+                            return Failed(span.map(|span| (span, msg)));
                         }
                     }
                 }
@@ -1378,10 +1450,7 @@ fn resolve_module_path(&mut self,
             }
         }
 
-        self.resolve_module_path_from_root(search_module,
-                                           module_path,
-                                           start_index,
-                                           span)
+        self.resolve_module_path_from_root(search_module, module_path, start_index, span)
     }
 
     /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
@@ -1404,7 +1473,7 @@ fn resolve_module_path(&mut self,
     fn resolve_ident_in_lexical_scope(&mut self,
                                       mut ident: ast::Ident,
                                       ns: Namespace,
-                                      record_used: bool)
+                                      record_used: Option<Span>)
                                       -> Option<LexicalScopeBinding<'a>> {
         if ns == TypeNS {
             ident = ast::Ident::with_empty_ctxt(ident.name);
@@ -1432,8 +1501,8 @@ fn resolve_ident_in_lexical_scope(&mut self,
                 if module.def.is_some() {
                     return match self.prelude {
                         Some(prelude) if !module.no_implicit_prelude.get() => {
-                            prelude.resolve_name(name, ns, false).success()
-                                   .map(LexicalScopeBinding::Item)
+                            self.resolve_name_in_module(prelude, name, ns, false, None).success()
+                                .map(LexicalScopeBinding::Item)
                         }
                         _ => None,
                     };
@@ -1453,39 +1522,10 @@ fn resolve_ident_in_lexical_scope(&mut self,
         None
     }
 
-    /// Returns the nearest normal module parent of the given module.
-    fn get_nearest_normal_module_parent(&self, mut module: Module<'a>) -> Option<Module<'a>> {
-        loop {
-            match module.parent_link {
-                NoParentLink => return None,
-                ModuleParentLink(new_module, _) |
-                BlockParentLink(new_module, _) => {
-                    let new_module = new_module;
-                    if new_module.is_normal() {
-                        return Some(new_module);
-                    }
-                    module = new_module;
-                }
-            }
-        }
-    }
-
-    /// Returns the nearest normal module parent of the given module, or the
-    /// module itself if it is a normal module.
-    fn get_nearest_normal_module_parent_or_self(&self, module: Module<'a>) -> Module<'a> {
-        if module.is_normal() {
-            return module;
-        }
-        match self.get_nearest_normal_module_parent(module) {
-            None => module,
-            Some(new_module) => new_module,
-        }
-    }
-
     /// Resolves a "module prefix". A module prefix is one or both of (a) `self::`;
     /// (b) some chain of `super::`.
     /// grammar: (SELF MOD_SEP ) ? (SUPER MOD_SEP) *
-    fn resolve_module_prefix(&mut self, module_path: &[Name], span: Span)
+    fn resolve_module_prefix(&mut self, module_path: &[Name], span: Option<Span>)
                              -> ResolveResult<ModulePrefixResult<'a>> {
         // Start at the current module if we see `self` or `super`, or at the
         // top of the crate otherwise.
@@ -1494,22 +1534,20 @@ fn resolve_module_prefix(&mut self, module_path: &[Name], span: Span)
             "super" => 0,
             _ => return Success(NoPrefixFound),
         };
+
         let mut containing_module =
-            self.get_nearest_normal_module_parent_or_self(self.current_module);
+            self.module_map[&self.current_module.normal_ancestor_id.unwrap()];
 
         // Now loop through all the `super`s we find.
         while i < module_path.len() && "super" == module_path[i].as_str() {
             debug!("(resolving module prefix) resolving `super` at {}",
                    module_to_string(&containing_module));
-            match self.get_nearest_normal_module_parent(containing_module) {
-                None => {
-                    let msg = "There are too many initial `super`s.".into();
-                    return Failed(Some((span, msg)));
-                }
-                Some(new_module) => {
-                    containing_module = new_module;
-                    i += 1;
-                }
+            if let Some(parent) = containing_module.parent() {
+                containing_module = self.module_map[&parent.normal_ancestor_id.unwrap()];
+                i += 1;
+            } else {
+                let msg = "There are too many initial `super`s.".into();
+                return Failed(span.map(|span| (span, msg)));
             }
         }
 
@@ -1519,27 +1557,6 @@ fn resolve_module_prefix(&mut self, module_path: &[Name], span: Span)
         return Success(PrefixFound(containing_module, i));
     }
 
-    /// Attempts to resolve the supplied name in the given module for the
-    /// given namespace. If successful, returns the binding corresponding to
-    /// the name.
-    fn resolve_name_in_module(&mut self,
-                              module: Module<'a>,
-                              name: Name,
-                              namespace: Namespace,
-                              use_lexical_scope: bool,
-                              record_used: bool)
-                              -> ResolveResult<&'a NameBinding<'a>> {
-        debug!("(resolving name in module) resolving `{}` in `{}`", name, module_to_string(module));
-
-        self.populate_module_if_necessary(module);
-        module.resolve_name(name, namespace, use_lexical_scope).and_then(|binding| {
-            if record_used {
-                self.record_use(name, namespace, binding);
-            }
-            Success(binding)
-        })
-    }
-
     // AST resolution
     //
     // We maintain a list of value ribs and type ribs.
@@ -1564,7 +1581,7 @@ fn with_scope<F>(&mut self, id: NodeId, f: F)
         let module = self.module_map.get(&id).cloned(); // clones a reference
         if let Some(module) = module {
             // Move down in the graph.
-            let orig_module = ::std::mem::replace(&mut self.current_module, module);
+            let orig_module = replace(&mut self.current_module, module);
             self.value_ribs.push(Rib::new(ModuleRibKind(module)));
             self.type_ribs.push(Rib::new(ModuleRibKind(module)));
 
@@ -1616,6 +1633,7 @@ fn resolve_item(&mut self, item: &Item) {
             ItemKind::Enum(_, ref generics) |
             ItemKind::Ty(_, ref generics) |
             ItemKind::Struct(_, ref generics) |
+            ItemKind::Union(_, ref generics) |
             ItemKind::Fn(_, _, _, _, ref generics, _) => {
                 self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind),
                                              |this| visit::walk_item(this, item));
@@ -1694,7 +1712,7 @@ fn resolve_item(&mut self, item: &Item) {
                                                                    &prefix.segments,
                                                                    TypeNS) {
                                 Ok(binding) => {
-                                    let def = binding.def().unwrap();
+                                    let def = binding.def();
                                     self.record_def(item.id, PathResolution::new(def));
                                 }
                                 Err(true) => self.record_def(item.id, err_path_resolution()),
@@ -1726,17 +1744,19 @@ fn with_type_parameter_rib<'b, F>(&'b mut self, type_parameters: TypeParameters<
         match type_parameters {
             HasTypeParameters(generics, rib_kind) => {
                 let mut function_type_rib = Rib::new(rib_kind);
-                let mut seen_bindings = HashSet::new();
+                let mut seen_bindings = FnvHashMap();
                 for type_parameter in &generics.ty_params {
                     let name = type_parameter.ident.name;
                     debug!("with_type_parameter_rib: {}", type_parameter.id);
 
-                    if seen_bindings.contains(&name) {
+                    if seen_bindings.contains_key(&name) {
+                        let span = seen_bindings.get(&name).unwrap();
                         resolve_error(self,
                                       type_parameter.span,
-                                      ResolutionError::NameAlreadyUsedInTypeParameterList(name));
+                                      ResolutionError::NameAlreadyUsedInTypeParameterList(name,
+                                                                                          span));
                     }
-                    seen_bindings.insert(name);
+                    seen_bindings.entry(name).or_insert(type_parameter.span);
 
                     // plain insert (no renaming)
                     let def_id = self.definitions.local_def_id(type_parameter.id);
@@ -1788,7 +1808,7 @@ fn resolve_function(&mut self,
         self.label_ribs.push(Rib::new(rib_kind));
 
         // Add each argument to the rib.
-        let mut bindings_list = HashMap::new();
+        let mut bindings_list = FnvHashMap();
         for argument in &declaration.inputs {
             self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
 
@@ -1989,7 +2009,7 @@ fn resolve_local(&mut self, local: &Local) {
         walk_list!(self, visit_expr, &local.init);
 
         // Resolve the pattern.
-        self.resolve_pattern(&local.pat, PatternSource::Let, &mut HashMap::new());
+        self.resolve_pattern(&local.pat, PatternSource::Let, &mut FnvHashMap());
     }
 
     // build a map from pattern identifiers to binding-info's.
@@ -1997,7 +2017,7 @@ fn resolve_local(&mut self, local: &Local) {
     // that expands into an or-pattern where one 'x' was from the
     // user and one 'x' came from the macro.
     fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap {
-        let mut binding_map = HashMap::new();
+        let mut binding_map = FnvHashMap();
 
         pat.walk(&mut |pat| {
             if let PatKind::Ident(binding_mode, ident, ref sub_pat) = pat.node {
@@ -2057,7 +2077,7 @@ fn check_consistent_bindings(&mut self, arm: &Arm) {
     fn resolve_arm(&mut self, arm: &Arm) {
         self.value_ribs.push(Rib::new(NormalRibKind));
 
-        let mut bindings_list = HashMap::new();
+        let mut bindings_list = FnvHashMap();
         for pattern in &arm.pats {
             self.resolve_pattern(&pattern, PatternSource::Match, &mut bindings_list);
         }
@@ -2197,7 +2217,7 @@ fn fresh_binding(&mut self,
                      pat_id: NodeId,
                      outer_pat_id: NodeId,
                      pat_src: PatternSource,
-                     bindings: &mut HashMap<ast::Ident, NodeId>)
+                     bindings: &mut FnvHashMap<ast::Ident, NodeId>)
                      -> PathResolution {
         // Add the binding to the local ribs, if it
         // doesn't already exist in the bindings map. (We
@@ -2298,7 +2318,7 @@ fn resolve_pattern(&mut self,
                        pat_src: PatternSource,
                        // Maps idents to the node ID for the
                        // outermost pattern that binds them.
-                       bindings: &mut HashMap<ast::Ident, NodeId>) {
+                       bindings: &mut FnvHashMap<ast::Ident, NodeId>) {
         // Visit all direct subpatterns of this pattern.
         let outer_pat_id = pat.id;
         pat.walk(&mut |pat| {
@@ -2306,16 +2326,17 @@ fn resolve_pattern(&mut self,
                 PatKind::Ident(bmode, ref ident, ref opt_pat) => {
                     // First try to resolve the identifier as some existing
                     // entity, then fall back to a fresh binding.
-                    let binding = self.resolve_ident_in_lexical_scope(ident.node, ValueNS, false)
+                    let binding = self.resolve_ident_in_lexical_scope(ident.node, ValueNS, None)
                                       .and_then(LexicalScopeBinding::item);
-                    let resolution = binding.and_then(NameBinding::def).and_then(|def| {
+                    let resolution = binding.map(NameBinding::def).and_then(|def| {
                         let always_binding = !pat_src.is_refutable() || opt_pat.is_some() ||
                                              bmode != BindingMode::ByValue(Mutability::Immutable);
                         match def {
                             Def::Struct(..) | Def::Variant(..) |
                             Def::Const(..) | Def::AssociatedConst(..) if !always_binding => {
                                 // A constant, unit variant, etc pattern.
-                                self.record_use(ident.node.name, ValueNS, binding.unwrap());
+                                let name = ident.node.name;
+                                self.record_use(name, ValueNS, binding.unwrap(), ident.span);
                                 Some(PathResolution::new(def))
                             }
                             Def::Struct(..) | Def::Variant(..) |
@@ -2442,7 +2463,7 @@ fn resolve_path(&mut self, id: NodeId, path: &Path, path_depth: usize, namespace
 
         if path.global {
             let binding = self.resolve_crate_relative_path(span, segments, namespace);
-            return binding.map(|binding| mk_res(binding.def().unwrap()));
+            return binding.map(|binding| mk_res(binding.def()));
         }
 
         // Try to find a path to an item in a module.
@@ -2473,14 +2494,14 @@ fn resolve_path(&mut self, id: NodeId, path: &Path, path_depth: usize, namespace
             //
             // Such behavior is required for backward compatibility.
             // The same fallback is used when `a` resolves to nothing.
-            let def = resolve_identifier_with_fallback(self, true).ok_or(false);
+            let def = resolve_identifier_with_fallback(self, Some(span)).ok_or(false);
             return def.and_then(|def| self.adjust_local_def(def, span).ok_or(true)).map(mk_res);
         }
 
-        let unqualified_def = resolve_identifier_with_fallback(self, false);
+        let unqualified_def = resolve_identifier_with_fallback(self, None);
         let qualified_binding = self.resolve_module_relative_path(span, segments, namespace);
         match (qualified_binding, unqualified_def) {
-            (Ok(binding), Some(ref ud)) if binding.def().unwrap() == ud.def => {
+            (Ok(binding), Some(ref ud)) if binding.def() == ud.def => {
                 self.session
                     .add_lint(lint::builtin::UNUSED_QUALIFICATIONS,
                               id,
@@ -2490,14 +2511,14 @@ fn resolve_path(&mut self, id: NodeId, path: &Path, path_depth: usize, namespace
             _ => {}
         }
 
-        qualified_binding.map(|binding| mk_res(binding.def().unwrap()))
+        qualified_binding.map(|binding| mk_res(binding.def()))
     }
 
     // Resolve a single identifier
     fn resolve_identifier(&mut self,
                           identifier: ast::Ident,
                           namespace: Namespace,
-                          record_used: bool)
+                          record_used: Option<Span>)
                           -> Option<LocalDef> {
         if identifier.name == keywords::Invalid.name() {
             return None;
@@ -2611,18 +2632,11 @@ fn resolve_module_relative_path(&mut self,
                                   .collect::<Vec<_>>();
 
         let containing_module;
-        match self.resolve_module_path(&module_path, UseLexicalScope, span) {
+        match self.resolve_module_path(&module_path, UseLexicalScope, Some(span)) {
             Failed(err) => {
-                let (span, msg) = match err {
-                    Some((span, msg)) => (span, msg),
-                    None => {
-                        let msg = format!("Use of undeclared type or module `{}`",
-                                          names_to_string(&module_path));
-                        (span, msg)
-                    }
-                };
-
-                resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
+                if let Some((span, msg)) = err {
+                    resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
+                }
                 return Err(true);
             }
             Indeterminate => return Err(false),
@@ -2632,11 +2646,9 @@ fn resolve_module_relative_path(&mut self,
         }
 
         let name = segments.last().unwrap().identifier.name;
-        let result = self.resolve_name_in_module(containing_module, name, namespace, false, true);
-        result.success().map(|binding| {
-            self.check_privacy(name, binding, span);
-            binding
-        }).ok_or(false)
+        let result =
+            self.resolve_name_in_module(containing_module, name, namespace, false, Some(span));
+        result.success().ok_or(false)
     }
 
     /// Invariant: This must be called only during main resolution, not during
@@ -2650,21 +2662,11 @@ fn resolve_crate_relative_path<T>(&mut self, span: Span, segments: &[T], namespa
         let root_module = self.graph_root;
 
         let containing_module;
-        match self.resolve_module_path_from_root(root_module,
-                                                 &module_path,
-                                                 0,
-                                                 span) {
+        match self.resolve_module_path_from_root(root_module, &module_path, 0, Some(span)) {
             Failed(err) => {
-                let (span, msg) = match err {
-                    Some((span, msg)) => (span, msg),
-                    None => {
-                        let msg = format!("Use of undeclared module `::{}`",
-                                          names_to_string(&module_path));
-                        (span, msg)
-                    }
-                };
-
-                resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
+                if let Some((span, msg)) = err {
+                    resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
+                }
                 return Err(true);
             }
 
@@ -2676,11 +2678,9 @@ fn resolve_crate_relative_path<T>(&mut self, span: Span, segments: &[T], namespa
         }
 
         let name = segments.last().unwrap().name();
-        let result = self.resolve_name_in_module(containing_module, name, namespace, false, true);
-        result.success().map(|binding| {
-            self.check_privacy(name, binding, span);
-            binding
-        }).ok_or(false)
+        let result =
+            self.resolve_name_in_module(containing_module, name, namespace, false, Some(span));
+        result.success().ok_or(false)
     }
 
     fn with_no_errors<T, F>(&mut self, f: F) -> T
@@ -2708,7 +2708,6 @@ pub fn with_module_lexical_scope<T, F>(&mut self, module: Module<'a>, f: F) -> T
     fn with_empty_ribs<T, F>(&mut self, f: F) -> T
         where F: FnOnce(&mut Resolver<'a>) -> T,
     {
-        use ::std::mem::replace;
         let value_ribs = replace(&mut self.value_ribs, Vec::new());
         let type_ribs = replace(&mut self.type_ribs, Vec::new());
         let label_ribs = replace(&mut self.label_ribs, Vec::new());
@@ -2933,7 +2932,7 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
 
                                     match self.resolve_module_path(&name_path[..],
                                                                    UseLexicalScope,
-                                                                   expr.span) {
+                                                                   Some(expr.span)) {
                                         Success(e) => {
                                             if let Some(def_type) = e.def {
                                                 def = def_type;
@@ -3019,7 +3018,7 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
                 self.visit_expr(subexpression);
 
                 self.value_ribs.push(Rib::new(NormalRibKind));
-                self.resolve_pattern(pattern, PatternSource::IfLet, &mut HashMap::new());
+                self.resolve_pattern(pattern, PatternSource::IfLet, &mut FnvHashMap());
                 self.visit_block(if_block);
                 self.value_ribs.pop();
 
@@ -3029,7 +3028,7 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
             ExprKind::WhileLet(ref pattern, ref subexpression, ref block, label) => {
                 self.visit_expr(subexpression);
                 self.value_ribs.push(Rib::new(NormalRibKind));
-                self.resolve_pattern(pattern, PatternSource::WhileLet, &mut HashMap::new());
+                self.resolve_pattern(pattern, PatternSource::WhileLet, &mut FnvHashMap());
 
                 self.resolve_labeled_block(label.map(|l| l.node), expr.id, block);
 
@@ -3039,7 +3038,7 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
             ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => {
                 self.visit_expr(subexpression);
                 self.value_ribs.push(Rib::new(NormalRibKind));
-                self.resolve_pattern(pattern, PatternSource::For, &mut HashMap::new());
+                self.resolve_pattern(pattern, PatternSource::For, &mut FnvHashMap());
 
                 self.resolve_labeled_block(label.map(|l| l.node), expr.id, block);
 
@@ -3121,7 +3120,7 @@ fn add_trait_info(found_traits: &mut Vec<TraitCandidate>,
                     let mut collected_traits = Vec::new();
                     module.for_each_child(|name, ns, binding| {
                         if ns != TypeNS { return }
-                        if let Some(Def::Trait(_)) = binding.def() {
+                        if let Def::Trait(_) = binding.def() {
                             collected_traits.push((name, binding));
                         }
                     });
@@ -3129,7 +3128,7 @@ fn add_trait_info(found_traits: &mut Vec<TraitCandidate>,
                 }
 
                 for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
-                    let trait_def_id = binding.def().unwrap().def_id();
+                    let trait_def_id = binding.def().def_id();
                     if this.trait_item_map.contains_key(&(name, trait_def_id)) {
                         let mut import_id = None;
                         if let NameBindingKind::Import { directive, .. } = binding.kind {
@@ -3188,8 +3187,8 @@ fn lookup_candidates<FilterFn>(&mut self,
                 if name_binding.is_import() { return; }
 
                 // collect results based on the filter function
-                if let Some(def) = name_binding.def() {
-                    if name == lookup_name && ns == namespace && filter_fn(def) {
+                if name == lookup_name && ns == namespace {
+                    if filter_fn(name_binding.def()) {
                         // create the path
                         let ident = ast::Ident::with_empty_ctxt(name);
                         let params = PathParameters::none();
@@ -3219,7 +3218,7 @@ fn lookup_candidates<FilterFn>(&mut self,
                 }
 
                 // collect submodules to explore
-                if let Some(module) = name_binding.module() {
+                if let Ok(module) = name_binding.module() {
                     // form the path
                     let path_segments = match module.parent_link {
                         NoParentLink => path_segments.clone(),
@@ -3267,28 +3266,22 @@ fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
             ast::Visibility::Crate(_) => return ty::Visibility::Restricted(ast::CRATE_NODE_ID),
             ast::Visibility::Restricted { ref path, id } => (path, id),
             ast::Visibility::Inherited => {
-                let current_module =
-                    self.get_nearest_normal_module_parent_or_self(self.current_module);
-                let id =
-                    self.definitions.as_local_node_id(current_module.def_id().unwrap()).unwrap();
-                return ty::Visibility::Restricted(id);
+                return ty::Visibility::Restricted(self.current_module.normal_ancestor_id.unwrap());
             }
         };
 
         let segments: Vec<_> = path.segments.iter().map(|seg| seg.identifier.name).collect();
         let mut path_resolution = err_path_resolution();
-        let vis = match self.resolve_module_path(&segments, DontUseLexicalScope, path.span) {
+        let vis = match self.resolve_module_path(&segments, DontUseLexicalScope, Some(path.span)) {
             Success(module) => {
-                let def = module.def.unwrap();
-                path_resolution = PathResolution::new(def);
-                ty::Visibility::Restricted(self.definitions.as_local_node_id(def.def_id()).unwrap())
-            }
-            Failed(Some((span, msg))) => {
-                self.session.span_err(span, &format!("failed to resolve module path. {}", msg));
-                ty::Visibility::Public
+                path_resolution = PathResolution::new(module.def.unwrap());
+                ty::Visibility::Restricted(module.normal_ancestor_id.unwrap())
             }
-            _ => {
-                self.session.span_err(path.span, "unresolved module path");
+            Indeterminate => unreachable!(),
+            Failed(err) => {
+                if let Some((span, msg)) = err {
+                    self.session.span_err(span, &format!("failed to resolve module path. {}", msg));
+                }
                 ty::Visibility::Public
             }
         };
@@ -3301,20 +3294,28 @@ fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
     }
 
     fn is_accessible(&self, vis: ty::Visibility) -> bool {
-        let current_module = self.get_nearest_normal_module_parent_or_self(self.current_module);
-        let node_id = self.definitions.as_local_node_id(current_module.def_id().unwrap()).unwrap();
-        vis.is_accessible_from(node_id, self)
+        vis.is_accessible_from(self.current_module.normal_ancestor_id.unwrap(), self)
     }
 
-    fn check_privacy(&mut self, name: Name, binding: &'a NameBinding<'a>, span: Span) {
-        if !self.is_accessible(binding.vis) {
-            self.privacy_errors.push(PrivacyError(span, name, binding));
-        }
+    fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
+        vis.is_accessible_from(module.normal_ancestor_id.unwrap(), self)
     }
 
-    fn report_privacy_errors(&self) {
-        if self.privacy_errors.len() == 0 { return }
-        let mut reported_spans = HashSet::new();
+    fn report_errors(&self) {
+        let mut reported_spans = FnvHashSet();
+
+        for &(span, name, binding) in &self.ambiguity_errors {
+            if !reported_spans.insert(span) { continue }
+            let (b1, b2) = binding.ambiguity().unwrap();
+            let msg1 = format!("`{}` could resolve to the name imported here", name);
+            let msg2 = format!("`{}` could also resolve to the name imported here", name);
+            self.session.struct_span_err(span, &format!("`{}` is ambiguous", name))
+                .span_note(b1.span, &msg1)
+                .span_note(b2.span, &msg2)
+                .note(&format!("Consider adding an explicit import of `{}` to disambiguate", name))
+                .emit();
+        }
+
         for &PrivacyError(span, name, binding) in &self.privacy_errors {
             if !reported_spans.insert(span) { continue }
             if binding.is_extern_crate() {
@@ -3323,7 +3324,7 @@ fn report_privacy_errors(&self) {
                 let msg = format!("extern crate `{}` is private", name);
                 self.session.add_lint(lint::builtin::INACCESSIBLE_EXTERN_CRATE, node_id, span, msg);
             } else {
-                let def = binding.def().unwrap();
+                let def = binding.def();
                 self.session.span_err(span, &format!("{} `{}` is private", def.kind_name(), name));
             }
         }
@@ -3356,9 +3357,9 @@ fn report_conflict(&self,
         let msg = {
             let kind = match (ns, old_binding.module()) {
                 (ValueNS, _) => "a value",
-                (TypeNS, Some(module)) if module.extern_crate_id.is_some() => "an extern crate",
-                (TypeNS, Some(module)) if module.is_normal() => "a module",
-                (TypeNS, Some(module)) if module.is_trait() => "a trait",
+                (TypeNS, Ok(module)) if module.extern_crate_id.is_some() => "an extern crate",
+                (TypeNS, Ok(module)) if module.is_normal() => "a module",
+                (TypeNS, Ok(module)) if module.is_trait() => "a trait",
                 (TypeNS, _) => "a type",
             };
             format!("{} named `{}` has already been {} in this {}",
@@ -3366,15 +3367,27 @@ fn report_conflict(&self,
         };
 
         let mut err = match (old_binding.is_extern_crate(), binding.is_extern_crate()) {
-            (true, true) => struct_span_err!(self.session, span, E0259, "{}", msg),
+            (true, true) => {
+                let mut e = struct_span_err!(self.session, span, E0259, "{}", msg);
+                e.span_label(span, &format!("`{}` was already imported", name));
+                e
+            },
             (true, _) | (_, true) if binding.is_import() || old_binding.is_import() => {
                 let mut e = struct_span_err!(self.session, span, E0254, "{}", msg);
                 e.span_label(span, &"already imported");
                 e
             },
-            (true, _) | (_, true) => struct_span_err!(self.session, span, E0260, "{}", msg),
+            (true, _) | (_, true) => {
+                let mut e = struct_span_err!(self.session, span, E0260, "{}", msg);
+                e.span_label(span, &format!("`{}` already imported", name));
+                e
+            },
             _ => match (old_binding.is_import(), binding.is_import()) {
-                (false, false) => struct_span_err!(self.session, span, E0428, "{}", msg),
+                (false, false) => {
+                    let mut e = struct_span_err!(self.session, span, E0428, "{}", msg);
+                    e.span_label(span, &format!("already defined"));
+                    e
+                },
                 (true, true) => {
                     let mut e = struct_span_err!(self.session, span, E0252, "{}", msg);
                     e.span_label(span, &format!("already imported"));
index e08a30e40d354fb0db482f545fbc0dce56c95834..875d6745f6b2e26f7c5da2d45d0a0f5052a570db 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use self::Determinacy::*;
 use self::ImportDirectiveSubclass::*;
 
 use Module;
@@ -26,7 +27,7 @@
 
 use syntax::ast::{NodeId, Name};
 use syntax::util::lev_distance::find_best_match_for_name;
-use syntax_pos::{Span, DUMMY_SP};
+use syntax_pos::Span;
 
 use std::cell::{Cell, RefCell};
 
@@ -36,25 +37,35 @@ pub fn resolve_imports(&mut self) {
     }
 }
 
+#[derive(Copy, Clone, Debug)]
+pub enum Determinacy {
+    Determined,
+    Undetermined,
+}
+
 /// Contains data for specific types of import directives.
 #[derive(Clone, Debug)]
-pub enum ImportDirectiveSubclass {
+pub enum ImportDirectiveSubclass<'a> {
     SingleImport {
         target: Name,
         source: Name,
-        type_determined: Cell<bool>,
-        value_determined: Cell<bool>,
+        value_result: Cell<Result<&'a NameBinding<'a>, Determinacy>>,
+        type_result: Cell<Result<&'a NameBinding<'a>, Determinacy>>,
+    },
+    GlobImport {
+        is_prelude: bool,
+        max_vis: Cell<ty::Visibility>, // The visibility of the greatest reexport.
+        // n.b. `max_vis` is only used in `finalize_import` to check for reexport errors.
     },
-    GlobImport { is_prelude: bool },
 }
 
-impl ImportDirectiveSubclass {
+impl<'a> ImportDirectiveSubclass<'a> {
     pub fn single(target: Name, source: Name) -> Self {
         SingleImport {
             target: target,
             source: source,
-            type_determined: Cell::new(false),
-            value_determined: Cell::new(false),
+            type_result: Cell::new(Err(Undetermined)),
+            value_result: Cell::new(Err(Undetermined)),
         }
     }
 }
@@ -63,11 +74,12 @@ pub fn single(target: Name, source: Name) -> Self {
 #[derive(Debug,Clone)]
 pub struct ImportDirective<'a> {
     pub id: NodeId,
+    parent: Module<'a>,
     module_path: Vec<Name>,
-    target_module: Cell<Option<Module<'a>>>, // the resolution of `module_path`
-    subclass: ImportDirectiveSubclass,
+    imported_module: Cell<Option<Module<'a>>>, // the resolution of `module_path`
+    subclass: ImportDirectiveSubclass<'a>,
     span: Span,
-    vis: ty::Visibility, // see note in ImportResolutionPerNamespace about how to use this
+    vis: Cell<ty::Visibility>,
 }
 
 impl<'a> ImportDirective<'a> {
@@ -132,130 +144,173 @@ fn binding(&self) -> Option<&'a NameBinding<'a>> {
             _ => None, // The binding could be shadowed by a single import, so it is not known.
         })
     }
+}
+
+impl<'a> Resolver<'a> {
+    fn resolution(&self, module: Module<'a>, name: Name, ns: Namespace)
+                  -> &'a RefCell<NameResolution<'a>> {
+        *module.resolutions.borrow_mut().entry((name, ns))
+               .or_insert_with(|| self.arenas.alloc_name_resolution())
+    }
+
+    /// Attempts to resolve the supplied name in the given module for the given namespace.
+    /// If successful, returns the binding corresponding to the name.
+    /// Invariant: if `record_used` is `Some`, import resolution must be complete.
+    pub fn resolve_name_in_module(&mut self,
+                                  module: Module<'a>,
+                                  name: Name,
+                                  ns: Namespace,
+                                  allow_private_imports: bool,
+                                  record_used: Option<Span>)
+                                  -> ResolveResult<&'a NameBinding<'a>> {
+        self.populate_module_if_necessary(module);
+
+        let resolution = self.resolution(module, name, ns);
+        let resolution = match resolution.borrow_state() {
+            ::std::cell::BorrowState::Unused => resolution.borrow_mut(),
+            _ => return Failed(None), // This happens when there is a cycle of imports
+        };
+
+        let new_import_semantics = self.new_import_semantics;
+        let is_disallowed_private_import = |binding: &NameBinding| {
+            !new_import_semantics && !allow_private_imports && // disallowed
+            binding.vis != ty::Visibility::Public && binding.is_import() // non-`pub` import
+        };
+
+        if let Some(span) = record_used {
+            if let Some(binding) = resolution.binding {
+                if is_disallowed_private_import(binding) {
+                    return Failed(None);
+                }
+                if self.record_use(name, ns, binding, span) {
+                    return Success(self.dummy_binding);
+                }
+                if !self.is_accessible(binding.vis) {
+                    self.privacy_errors.push(PrivacyError(span, name, binding));
+                }
+            }
+
+            return resolution.binding.map(Success).unwrap_or(Failed(None));
+        }
+
+        // If the resolution doesn't depend on glob definability, check privacy and return.
+        if let Some(result) = self.try_result(&resolution, ns) {
+            return result.and_then(|binding| {
+                if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) {
+                    Success(binding)
+                } else {
+                    Failed(None)
+                }
+            });
+        }
+
+        // Check if the globs are determined
+        for directive in module.globs.borrow().iter() {
+            if self.is_accessible(directive.vis.get()) {
+                if let Some(module) = directive.imported_module.get() {
+                    let result = self.resolve_name_in_module(module, name, ns, true, None);
+                    if let Indeterminate = result {
+                        return Indeterminate;
+                    }
+                } else {
+                    return Indeterminate;
+                }
+            }
+        }
+
+        Failed(None)
+    }
 
     // Returns Some(the resolution of the name), or None if the resolution depends
     // on whether more globs can define the name.
-    fn try_result(&self, ns: Namespace, allow_private_imports: bool)
+    fn try_result(&mut self, resolution: &NameResolution<'a>, ns: Namespace)
                   -> Option<ResolveResult<&'a NameBinding<'a>>> {
-        match self.binding {
+        match resolution.binding {
             Some(binding) if !binding.is_glob_import() =>
-                return Some(Success(binding)),
-            _ => {} // Items and single imports are not shadowable
+                return Some(Success(binding)), // Items and single imports are not shadowable.
+            _ => {}
         };
 
         // Check if a single import can still define the name.
-        match self.single_imports {
-            SingleImports::None => {},
+        match resolution.single_imports {
             SingleImports::AtLeastOne => return Some(Indeterminate),
-            SingleImports::MaybeOne(directive) => {
-                // If (1) we don't allow private imports, (2) no public single import can define
-                // the name, and (3) no public glob has defined the name, the resolution depends
-                // on whether more globs can define the name.
-                if !allow_private_imports && directive.vis != ty::Visibility::Public &&
-                   !self.binding.map(NameBinding::is_pseudo_public).unwrap_or(false) {
-                    return None;
-                }
-
-                let target_module = match directive.target_module.get() {
-                    Some(target_module) => target_module,
+            SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis.get()) => {
+                let module = match directive.imported_module.get() {
+                    Some(module) => module,
                     None => return Some(Indeterminate),
                 };
                 let name = match directive.subclass {
                     SingleImport { source, .. } => source,
                     GlobImport { .. } => unreachable!(),
                 };
-                match target_module.resolve_name(name, ns, false) {
+                match self.resolve_name_in_module(module, name, ns, true, None) {
                     Failed(_) => {}
                     _ => return Some(Indeterminate),
                 }
             }
+            SingleImports::MaybeOne(_) | SingleImports::None => {},
         }
 
-        self.binding.map(Success)
-    }
-}
-
-impl<'a> ::ModuleS<'a> {
-    fn resolution(&self, name: Name, ns: Namespace) -> &'a RefCell<NameResolution<'a>> {
-        *self.resolutions.borrow_mut().entry((name, ns))
-             .or_insert_with(|| self.arenas.alloc_name_resolution())
+        resolution.binding.map(Success)
     }
 
-    pub fn resolve_name(&self, name: Name, ns: Namespace, allow_private_imports: bool)
-                        -> ResolveResult<&'a NameBinding<'a>> {
-        let resolution = self.resolution(name, ns);
-        let resolution = match resolution.borrow_state() {
-            ::std::cell::BorrowState::Unused => resolution.borrow_mut(),
-            _ => return Failed(None), // This happens when there is a cycle of imports
-        };
-
-        if let Some(result) = resolution.try_result(ns, allow_private_imports) {
-            // If the resolution doesn't depend on glob definability, check privacy and return.
-            return result.and_then(|binding| {
-                let allowed = allow_private_imports || !binding.is_import() ||
-                                                       binding.is_pseudo_public();
-                if allowed { Success(binding) } else { Failed(None) }
-            });
-        }
-
-        // Check if the globs are determined
-        for directive in self.globs.borrow().iter() {
-            if !allow_private_imports && directive.vis != ty::Visibility::Public { continue }
-            match directive.target_module.get() {
-                None => return Indeterminate,
-                Some(target_module) => match target_module.resolve_name(name, ns, false) {
-                    Indeterminate => return Indeterminate,
-                    _ => {}
-                }
-            }
-        }
-
-        Failed(None)
-    }
-
-    pub fn add_import_directive(&self,
+    // Add an import directive to the current module.
+    pub fn add_import_directive(&mut self,
                                 module_path: Vec<Name>,
-                                subclass: ImportDirectiveSubclass,
+                                subclass: ImportDirectiveSubclass<'a>,
                                 span: Span,
                                 id: NodeId,
                                 vis: ty::Visibility) {
+        let current_module = self.current_module;
         let directive = self.arenas.alloc_import_directive(ImportDirective {
+            parent: current_module,
             module_path: module_path,
-            target_module: Cell::new(None),
+            imported_module: Cell::new(None),
             subclass: subclass,
             span: span,
             id: id,
-            vis: vis,
+            vis: Cell::new(vis),
         });
 
-        self.unresolved_imports.borrow_mut().push(directive);
+        self.indeterminate_imports.push(directive);
         match directive.subclass {
             SingleImport { target, .. } => {
                 for &ns in &[ValueNS, TypeNS] {
-                    self.resolution(target, ns).borrow_mut().single_imports
-                                                            .add_directive(directive);
+                    let mut resolution = self.resolution(current_module, target, ns).borrow_mut();
+                    resolution.single_imports.add_directive(directive);
                 }
             }
             // We don't add prelude imports to the globs since they only affect lexical scopes,
             // which are not relevant to import resolution.
-            GlobImport { is_prelude: true } => {}
-            GlobImport { .. } => self.globs.borrow_mut().push(directive),
+            GlobImport { is_prelude: true, .. } => {}
+            GlobImport { .. } => self.current_module.globs.borrow_mut().push(directive),
         }
     }
-}
 
-impl<'a> Resolver<'a> {
     // Given a binding and an import directive that resolves to it,
     // return the corresponding binding defined by the import directive.
     fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
               -> NameBinding<'a> {
+        let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) ||
+                     !directive.is_glob() && binding.is_extern_crate() { // c.f. `PRIVATE_IN_PUBLIC`
+            directive.vis.get()
+        } else {
+            binding.pseudo_vis()
+        };
+
+        if let GlobImport { ref max_vis, .. } = directive.subclass {
+            if vis == directive.vis.get() || vis.is_at_least(max_vis.get(), self) {
+                max_vis.set(vis)
+            }
+        }
+
         NameBinding {
             kind: NameBindingKind::Import {
                 binding: binding,
                 directive: directive,
             },
             span: directive.span,
-            vis: directive.vis,
+            vis: vis,
         }
     }
 
@@ -265,10 +320,28 @@ pub fn try_define<T>(&mut self, module: Module<'a>, name: Name, ns: Namespace, b
         where T: ToNameBinding<'a>
     {
         let binding = self.arenas.alloc_name_binding(binding.to_name_binding());
-        self.update_resolution(module, name, ns, |_, resolution| {
+        self.update_resolution(module, name, ns, |this, resolution| {
             if let Some(old_binding) = resolution.binding {
                 if binding.is_glob_import() {
-                    resolution.duplicate_globs.push(binding);
+                    if !this.new_import_semantics || !old_binding.is_glob_import() {
+                        resolution.duplicate_globs.push(binding);
+                    } else if binding.def() != old_binding.def() {
+                        resolution.binding = Some(this.arenas.alloc_name_binding(NameBinding {
+                            kind: NameBindingKind::Ambiguity {
+                                b1: old_binding,
+                                b2: binding,
+                            },
+                            vis: if old_binding.vis.is_at_least(binding.vis, this) {
+                                old_binding.vis
+                            } else {
+                                binding.vis
+                            },
+                            span: old_binding.span,
+                        }));
+                    } else if !old_binding.vis.is_at_least(binding.vis, this) {
+                        // We are glob-importing the same item but with greater visibility.
+                        resolution.binding = Some(binding);
+                    }
                 } else if old_binding.is_glob_import() {
                     resolution.duplicate_globs.push(old_binding);
                     resolution.binding = Some(binding);
@@ -290,24 +363,30 @@ fn update_resolution<T, F>(&mut self, module: Module<'a>, name: Name, ns: Namesp
     {
         // Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
         // during which the resolution might end up getting re-defined via a glob cycle.
-        let (new_binding, t) = {
-            let mut resolution = &mut *module.resolution(name, ns).borrow_mut();
-            let was_known = resolution.binding().is_some();
+        let (binding, t) = {
+            let mut resolution = &mut *self.resolution(module, name, ns).borrow_mut();
+            let old_binding = resolution.binding();
 
             let t = f(self, resolution);
 
-            if was_known { return t; }
             match resolution.binding() {
-                Some(binding) => (binding, t),
+                _ if !self.new_import_semantics && old_binding.is_some() => return t,
                 None => return t,
+                Some(binding) => match old_binding {
+                    Some(old_binding) if old_binding as *const _ == binding as *const _ => return t,
+                    _ => (binding, t),
+                }
             }
         };
 
-        // Define `new_binding` in `module`s glob importers.
-        if new_binding.is_importable() && new_binding.is_pseudo_public() {
-            for &(importer, directive) in module.glob_importers.borrow_mut().iter() {
-                let imported_binding = self.import(new_binding, directive);
-                let _ = self.try_define(importer, name, ns, imported_binding);
+        // Define `binding` in `module`s glob importers.
+        for directive in module.glob_importers.borrow_mut().iter() {
+            if match self.new_import_semantics {
+                true => self.is_accessible_from(binding.vis, directive.parent),
+                false => binding.vis == ty::Visibility::Public,
+            } {
+                let imported_binding = self.import(binding, directive);
+                let _ = self.try_define(directive.parent, name, ns, imported_binding);
             }
         }
 
@@ -315,14 +394,6 @@ fn update_resolution<T, F>(&mut self, module: Module<'a>, name: Name, ns: Namesp
     }
 }
 
-struct ImportResolvingError<'a> {
-    /// Module where the error happened
-    source_module: Module<'a>,
-    import_directive: &'a ImportDirective<'a>,
-    span: Span,
-    help: String,
-}
-
 struct ImportResolver<'a, 'b: 'a> {
     resolver: &'a mut Resolver<'b>,
 }
@@ -359,104 +430,67 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
     /// point iteration.
     fn resolve_imports(&mut self) {
         let mut i = 0;
-        let mut prev_unresolved_imports = 0;
-        let mut errors = Vec::new();
+        let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1;
 
-        loop {
-            debug!("(resolving imports) iteration {}, {} imports left", i, self.unresolved_imports);
+        while self.indeterminate_imports.len() < prev_num_indeterminates {
+            prev_num_indeterminates = self.indeterminate_imports.len();
+            debug!("(resolving imports) iteration {}, {} imports left", i, prev_num_indeterminates);
 
-            // Attempt to resolve imports in all local modules.
-            for module in self.arenas.local_modules().iter() {
-                self.current_module = module;
-                self.resolve_imports_in_current_module(&mut errors);
-            }
+            let mut imports = Vec::new();
+            ::std::mem::swap(&mut imports, &mut self.indeterminate_imports);
 
-            if self.unresolved_imports == 0 {
-                debug!("(resolving imports) success");
-                for module in self.arenas.local_modules().iter() {
-                    self.finalize_resolutions_in(module, false);
+            for import in imports {
+                match self.resolve_import(&import) {
+                    Failed(_) => self.determined_imports.push(import),
+                    Indeterminate => self.indeterminate_imports.push(import),
+                    Success(()) => self.determined_imports.push(import),
                 }
-                break;
             }
 
-            if self.unresolved_imports == prev_unresolved_imports {
-                // resolving failed
-                // Report unresolved imports only if no hard error was already reported
-                // to avoid generating multiple errors on the same import.
-                // Imports that are still indeterminate at this point are actually blocked
-                // by errored imports, so there is no point reporting them.
-                for module in self.arenas.local_modules().iter() {
-                    self.finalize_resolutions_in(module, errors.len() == 0);
-                }
-                for e in errors {
-                    self.import_resolving_error(e)
-                }
-                break;
+            i += 1;
+        }
+
+        for module in self.arenas.local_modules().iter() {
+            self.finalize_resolutions_in(module);
+        }
+
+        let mut errors = false;
+        for i in 0 .. self.determined_imports.len() {
+            let import = self.determined_imports[i];
+            if let Failed(err) = self.finalize_import(import) {
+                errors = true;
+                let (span, help) = match err {
+                    Some((span, msg)) => (span, msg),
+                    None => continue,
+                };
+
+                // If the error is a single failed import then create a "fake" import
+                // resolution for it so that later resolve stages won't complain.
+                self.import_dummy_binding(import);
+                let path = import_path_to_string(&import.module_path, &import.subclass);
+                let error = ResolutionError::UnresolvedImport(Some((&path, &help)));
+                resolve_error(self.resolver, span, error);
             }
+        }
 
-            i += 1;
-            prev_unresolved_imports = self.unresolved_imports;
+        // Report unresolved imports only if no hard error was already reported
+        // to avoid generating multiple errors on the same import.
+        if !errors {
+            if let Some(import) = self.indeterminate_imports.iter().next() {
+                let error = ResolutionError::UnresolvedImport(None);
+                resolve_error(self.resolver, import.span, error);
+            }
         }
     }
 
     // Define a "dummy" resolution containing a Def::Err as a placeholder for a
     // failed resolution
-    fn import_dummy_binding(&mut self,
-                            source_module: Module<'b>,
-                            directive: &'b ImportDirective<'b>) {
+    fn import_dummy_binding(&mut self, directive: &'b ImportDirective<'b>) {
         if let SingleImport { target, .. } = directive.subclass {
-            let dummy_binding = self.arenas.alloc_name_binding(NameBinding {
-                kind: NameBindingKind::Def(Def::Err),
-                span: DUMMY_SP,
-                vis: ty::Visibility::Public,
-            });
+            let dummy_binding = self.dummy_binding;
             let dummy_binding = self.import(dummy_binding, directive);
-
-            let _ = self.try_define(source_module, target, ValueNS, dummy_binding.clone());
-            let _ = self.try_define(source_module, target, TypeNS, dummy_binding);
-        }
-    }
-
-    /// Resolves an `ImportResolvingError` into the correct enum discriminant
-    /// and passes that on to `resolve_error`.
-    fn import_resolving_error(&mut self, e: ImportResolvingError<'b>) {
-        // If the error is a single failed import then create a "fake" import
-        // resolution for it so that later resolve stages won't complain.
-        self.import_dummy_binding(e.source_module, e.import_directive);
-        let path = import_path_to_string(&e.import_directive.module_path,
-                                         &e.import_directive.subclass);
-        resolve_error(self.resolver,
-                      e.span,
-                      ResolutionError::UnresolvedImport(Some((&path, &e.help))));
-    }
-
-    /// Attempts to resolve imports for the given module only.
-    fn resolve_imports_in_current_module(&mut self, errors: &mut Vec<ImportResolvingError<'b>>) {
-        let mut imports = Vec::new();
-        let mut unresolved_imports = self.current_module.unresolved_imports.borrow_mut();
-        ::std::mem::swap(&mut imports, &mut unresolved_imports);
-
-        for import_directive in imports {
-            match self.resolve_import(&import_directive) {
-                Failed(err) => {
-                    let (span, help) = match err {
-                        Some((span, msg)) => (span, format!(". {}", msg)),
-                        None => (import_directive.span, String::new()),
-                    };
-                    errors.push(ImportResolvingError {
-                        source_module: self.current_module,
-                        import_directive: import_directive,
-                        span: span,
-                        help: help,
-                    });
-                }
-                Indeterminate => unresolved_imports.push(import_directive),
-                Success(()) => {
-                    // Decrement the count of unresolved imports.
-                    assert!(self.unresolved_imports >= 1);
-                    self.unresolved_imports -= 1;
-                }
-            }
+            let _ = self.try_define(directive.parent, target, ValueNS, dummy_binding.clone());
+            let _ = self.try_define(directive.parent, target, TypeNS, dummy_binding);
         }
     }
 
@@ -470,126 +504,197 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> ResolveResul
                names_to_string(&directive.module_path),
                module_to_string(self.current_module));
 
-        let target_module = match directive.target_module.get() {
-            Some(module) => module,
-            _ => match self.resolve_module_path(&directive.module_path,
-                                                DontUseLexicalScope,
-                                                directive.span) {
+        self.current_module = directive.parent;
+
+        let module = if let Some(module) = directive.imported_module.get() {
+            module
+        } else {
+            let vis = directive.vis.get();
+            // For better failure detection, pretend that the import will not define any names
+            // while resolving its module path.
+            directive.vis.set(ty::Visibility::PrivateExternal);
+            let result =
+                self.resolve_module_path(&directive.module_path, DontUseLexicalScope, None);
+            directive.vis.set(vis);
+
+            match result {
                 Success(module) => module,
                 Indeterminate => return Indeterminate,
                 Failed(err) => return Failed(err),
-            },
+            }
         };
 
-        directive.target_module.set(Some(target_module));
-        let (source, target, value_determined, type_determined) = match directive.subclass {
-            SingleImport { source, target, ref value_determined, ref type_determined } =>
-                (source, target, value_determined, type_determined),
-            GlobImport { .. } => return self.resolve_glob_import(target_module, directive),
+        directive.imported_module.set(Some(module));
+        let (source, target, value_result, type_result) = match directive.subclass {
+            SingleImport { source, target, ref value_result, ref type_result } =>
+                (source, target, value_result, type_result),
+            GlobImport { .. } => {
+                self.resolve_glob_import(directive);
+                return Success(());
+            }
         };
 
-        // We need to resolve both namespaces for this to succeed.
-        let value_result = self.resolve_name_in_module(target_module, source, ValueNS, false, true);
-        let type_result = self.resolve_name_in_module(target_module, source, TypeNS, false, true);
-
-        let module = self.current_module;
-        let mut privacy_error = true;
-        for &(ns, result, determined) in &[(ValueNS, &value_result, value_determined),
-                                           (TypeNS, &type_result, type_determined)] {
-            match *result {
-                Failed(..) if !determined.get() => {
-                    determined.set(true);
-                    self.update_resolution(module, target, ns, |_, resolution| {
+        let mut indeterminate = false;
+        for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] {
+            if let Err(Undetermined) = result.get() {
+                result.set({
+                    match self.resolve_name_in_module(module, source, ns, false, None) {
+                        Success(binding) => Ok(binding),
+                        Indeterminate => Err(Undetermined),
+                        Failed(_) => Err(Determined),
+                    }
+                });
+            } else {
+                continue
+            };
+
+            match result.get() {
+                Err(Undetermined) => indeterminate = true,
+                Err(Determined) => {
+                    self.update_resolution(directive.parent, target, ns, |_, resolution| {
                         resolution.single_imports.directive_failed()
                     });
                 }
-                Success(binding) if !binding.is_importable() => {
+                Ok(binding) if !binding.is_importable() => {
                     let msg = format!("`{}` is not directly importable", target);
                     struct_span_err!(self.session, directive.span, E0253, "{}", &msg)
                         .span_label(directive.span, &format!("cannot be imported directly"))
                         .emit();
                     // Do not import this illegal binding. Import a dummy binding and pretend
                     // everything is fine
-                    self.import_dummy_binding(module, directive);
+                    self.import_dummy_binding(directive);
                     return Success(());
                 }
-                Success(binding) if !self.is_accessible(binding.vis) => {}
-                Success(binding) if !determined.get() => {
-                    determined.set(true);
+                Ok(binding) => {
                     let imported_binding = self.import(binding, directive);
-                    let conflict = self.try_define(module, target, ns, imported_binding);
+                    let conflict = self.try_define(directive.parent, target, ns, imported_binding);
                     if let Err(old_binding) = conflict {
                         let binding = &self.import(binding, directive);
-                        self.report_conflict(module, target, ns, binding, old_binding);
+                        self.report_conflict(directive.parent, target, ns, binding, old_binding);
                     }
-                    privacy_error = false;
                 }
-                Success(_) => privacy_error = false,
-                _ => {}
             }
         }
 
-        match (&value_result, &type_result) {
-            (&Indeterminate, _) | (_, &Indeterminate) => return Indeterminate,
-            (&Failed(_), &Failed(_)) => {
-                let resolutions = target_module.resolutions.borrow();
-                let names = resolutions.iter().filter_map(|(&(ref name, _), resolution)| {
-                    if *name == source { return None; } // Never suggest the same name
+        if indeterminate { Indeterminate } else { Success(()) }
+    }
+
+    fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> ResolveResult<()> {
+        self.current_module = directive.parent;
+
+        let ImportDirective { ref module_path, span, .. } = *directive;
+        let module_result = self.resolve_module_path(&module_path, DontUseLexicalScope, Some(span));
+        let module = match module_result {
+            Success(module) => module,
+            Indeterminate => return Indeterminate,
+            Failed(err) => return Failed(err),
+        };
+
+        let (name, value_result, type_result) = match directive.subclass {
+            SingleImport { source, ref value_result, ref type_result, .. } =>
+                (source, value_result.get(), type_result.get()),
+            GlobImport { .. } if module.def_id() == directive.parent.def_id() => {
+                // Importing a module into itself is not allowed.
+                let msg = "Cannot glob-import a module into itself.".into();
+                return Failed(Some((directive.span, msg)));
+            }
+            GlobImport { is_prelude, ref max_vis } => {
+                if !is_prelude &&
+                   max_vis.get() != ty::Visibility::PrivateExternal && // Allow empty globs.
+                   !max_vis.get().is_at_least(directive.vis.get(), self) {
+                    let msg = "A non-empty glob must import something with the glob's visibility";
+                    self.session.span_err(directive.span, msg);
+                }
+                return Success(());
+            }
+        };
+
+        for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] {
+            if let Ok(binding) = result {
+                if self.record_use(name, ns, binding, directive.span) {
+                    self.resolution(module, name, ns).borrow_mut().binding =
+                        Some(self.dummy_binding);
+                }
+            }
+        }
+
+        if value_result.is_err() && type_result.is_err() {
+            let (value_result, type_result);
+            value_result = self.resolve_name_in_module(module, name, ValueNS, false, Some(span));
+            type_result = self.resolve_name_in_module(module, name, TypeNS, false, Some(span));
+
+            return if let (Failed(_), Failed(_)) = (value_result, type_result) {
+                let resolutions = module.resolutions.borrow();
+                let names = resolutions.iter().filter_map(|(&(ref n, _), resolution)| {
+                    if *n == name { return None; } // Never suggest the same name
                     match *resolution.borrow() {
-                        NameResolution { binding: Some(_), .. } => Some(name),
+                        NameResolution { binding: Some(_), .. } => Some(n),
                         NameResolution { single_imports: SingleImports::None, .. } => None,
-                        _ => Some(name),
+                        _ => Some(n),
                     }
                 });
-                let lev_suggestion = match find_best_match_for_name(names, &source.as_str(), None) {
+                let lev_suggestion = match find_best_match_for_name(names, &name.as_str(), None) {
                     Some(name) => format!(". Did you mean to use `{}`?", name),
                     None => "".to_owned(),
                 };
-                let module_str = module_to_string(target_module);
+                let module_str = module_to_string(module);
                 let msg = if &module_str == "???" {
-                    format!("There is no `{}` in the crate root{}", source, lev_suggestion)
+                    format!("no `{}` in the root{}", name, lev_suggestion)
                 } else {
-                    format!("There is no `{}` in `{}`{}", source, module_str, lev_suggestion)
+                    format!("no `{}` in `{}`{}", name, module_str, lev_suggestion)
                 };
-                return Failed(Some((directive.span, msg)));
+                Failed(Some((directive.span, msg)))
+            } else {
+                // `resolve_name_in_module` reported a privacy error.
+                self.import_dummy_binding(directive);
+                Success(())
             }
-            _ => (),
         }
 
-        if privacy_error {
-            for &(ns, result) in &[(ValueNS, &value_result), (TypeNS, &type_result)] {
-                let binding = match *result { Success(binding) => binding, _ => continue };
-                self.privacy_errors.push(PrivacyError(directive.span, source, binding));
-                let imported_binding = self.import(binding, directive);
-                let _ = self.try_define(module, target, ns, imported_binding);
+        let session = self.session;
+        let reexport_error = || {
+            let msg = format!("`{}` is private, and cannot be reexported", name);
+            let note_msg =
+                format!("consider marking `{}` as `pub` in the imported module", name);
+            struct_span_err!(session, directive.span, E0364, "{}", &msg)
+                .span_note(directive.span, &note_msg)
+                .emit();
+        };
+
+        let extern_crate_lint = || {
+            let msg = format!("extern crate `{}` is private, and cannot be reexported \
+                               (error E0364), consider declaring with `pub`",
+                               name);
+            session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg);
+        };
+
+        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 => {
+                let vis = directive.vis.get();
+                if !value_binding.pseudo_vis().is_at_least(vis, self) &&
+                   !type_binding.pseudo_vis().is_at_least(vis, self) {
+                    reexport_error();
+                } else if type_binding.is_extern_crate() &&
+                          !type_binding.vis.is_at_least(vis, self) {
+                    extern_crate_lint();
+                }
             }
-        }
 
-        match (&value_result, &type_result) {
-            (&Success(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis, self) &&
-                                      self.is_accessible(binding.vis) => {
-                let msg = format!("`{}` is private, and cannot be reexported", source);
-                let note_msg = format!("consider marking `{}` as `pub` in the imported module",
-                                        source);
-                struct_span_err!(self.session, directive.span, E0364, "{}", &msg)
-                    .span_note(directive.span, &note_msg)
-                    .emit();
+            (Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => {
+                reexport_error();
             }
 
-            (_, &Success(binding)) if !binding.pseudo_vis().is_at_least(directive.vis, self) &&
-                                      self.is_accessible(binding.vis) => {
+            (_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => {
                 if binding.is_extern_crate() {
-                    let msg = format!("extern crate `{}` is private, and cannot be reexported \
-                                       (error E0364), consider declaring with `pub`",
-                                       source);
-                    self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg);
+                    extern_crate_lint();
                 } else {
-                    let mut err = struct_span_err!(self.session, directive.span, E0365,
-                                                     "`{}` is private, and cannot be reexported",
-                                                     source);
-                    err.span_label(directive.span, &format!("reexport of private `{}`", source));
-                    err.note(&format!("consider declaring type or module `{}` with `pub`", source));
-                    err.emit();
+                    struct_span_err!(self.session, directive.span, E0365,
+                                     "`{}` is private, and cannot be reexported", name)
+                        .span_label(directive.span, &format!("reexport of private `{}`", name))
+                        .note(&format!("consider declaring type or module `{}` with `pub`", name))
+                        .emit();
                 }
             }
 
@@ -599,9 +704,9 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> ResolveResul
         // Record what this import resolves to for later uses in documentation,
         // this may resolve to either a value or a type, but for documentation
         // purposes it's good enough to just favor one over the other.
-        let def = match type_result.success().and_then(NameBinding::def) {
+        let def = match type_result.ok().map(NameBinding::def) {
             Some(def) => def,
-            None => value_result.success().and_then(NameBinding::def).unwrap(),
+            None => value_result.ok().map(NameBinding::def).unwrap(),
         };
         let path_resolution = PathResolution::new(def);
         self.def_map.insert(directive.id, path_resolution);
@@ -610,57 +715,46 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> ResolveResul
         return Success(());
     }
 
-    // Resolves a glob import. Note that this function cannot fail; it either
-    // succeeds or bails out (as importing * from an empty module or a module
-    // that exports nothing is valid). target_module is the module we are
-    // actually importing, i.e., `foo` in `use foo::*`.
-    fn resolve_glob_import(&mut self, target_module: Module<'b>, directive: &'b ImportDirective<'b>)
-                           -> ResolveResult<()> {
-        if let Some(Def::Trait(_)) = target_module.def {
-            self.session.span_err(directive.span, "items in traits are not importable.");
-        }
-
-        let module = self.current_module;
-        if module.def_id() == target_module.def_id() {
-            // This means we are trying to glob import a module into itself, and it is a no-go
-            let msg = "Cannot glob-import a module into itself.".into();
-            return Failed(Some((directive.span, msg)));
-        }
-        self.populate_module_if_necessary(target_module);
+    fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) {
+        let module = directive.imported_module.get().unwrap();
+        self.populate_module_if_necessary(module);
 
-        if let GlobImport { is_prelude: true } = directive.subclass {
-            self.prelude = Some(target_module);
-            return Success(());
+        if let Some(Def::Trait(_)) = module.def {
+            self.session.span_err(directive.span, "items in traits are not importable.");
+            return;
+        } else if module.def_id() == directive.parent.def_id()  {
+            return;
+        } else if let GlobImport { is_prelude: true, .. } = directive.subclass {
+            self.prelude = Some(module);
+            return;
         }
 
-        // Add to target_module's glob_importers
-        target_module.glob_importers.borrow_mut().push((module, directive));
+        // Add to module's glob_importers
+        module.glob_importers.borrow_mut().push(directive);
 
         // Ensure that `resolutions` isn't borrowed during `try_define`,
         // since it might get updated via a glob cycle.
-        let bindings = target_module.resolutions.borrow().iter().filter_map(|(name, resolution)| {
+        let bindings = module.resolutions.borrow().iter().filter_map(|(name, resolution)| {
             resolution.borrow().binding().map(|binding| (*name, binding))
         }).collect::<Vec<_>>();
         for ((name, ns), binding) in bindings {
-            if binding.is_importable() && binding.is_pseudo_public() {
+            if binding.pseudo_vis() == ty::Visibility::Public ||
+               self.new_import_semantics && self.is_accessible(binding.vis) {
                 let imported_binding = self.import(binding, directive);
-                let _ = self.try_define(module, name, ns, imported_binding);
+                let _ = self.try_define(directive.parent, name, ns, imported_binding);
             }
         }
 
         // Record the destination of this import
-        if let Some(did) = target_module.def_id() {
+        if let Some(did) = module.def_id() {
             let resolution = PathResolution::new(Def::Mod(did));
             self.def_map.insert(directive.id, resolution);
         }
-
-        debug!("(resolving glob import) successfully resolved import");
-        return Success(());
     }
 
     // Miscellaneous post-processing, including recording reexports, reporting conflicts,
     // reporting the PRIVATE_IN_PUBLIC lint, and reporting unresolved imports.
-    fn finalize_resolutions_in(&mut self, module: Module<'b>, report_unresolved_imports: bool) {
+    fn finalize_resolutions_in(&mut self, module: Module<'b>) {
         // Since import resolution is finished, globs will not define any more names.
         *module.globs.borrow_mut() = Vec::new();
 
@@ -673,20 +767,23 @@ fn finalize_resolutions_in(&mut self, module: Module<'b>, report_unresolved_impo
             };
 
             // Report conflicts
-            for duplicate_glob in resolution.duplicate_globs.iter() {
-                // FIXME #31337: We currently allow items to shadow glob-imported re-exports.
-                if !binding.is_import() {
-                    if let NameBindingKind::Import { binding, .. } = duplicate_glob.kind {
-                        if binding.is_import() { continue }
+            if !self.new_import_semantics {
+                for duplicate_glob in resolution.duplicate_globs.iter() {
+                    // FIXME #31337: We currently allow items to shadow glob-imported re-exports.
+                    if !binding.is_import() {
+                        if let NameBindingKind::Import { binding, .. } = duplicate_glob.kind {
+                            if binding.is_import() { continue }
+                        }
                     }
-                }
 
-                self.report_conflict(module, name, ns, duplicate_glob, binding);
+                    self.report_conflict(module, name, ns, duplicate_glob, binding);
+                }
             }
 
             if binding.vis == ty::Visibility::Public &&
                (binding.is_import() || binding.is_extern_crate()) {
-                if let Some(def) = binding.def() {
+                let def = binding.def();
+                if def != Def::Err {
                     reexports.push(Export { name: name, def_id: def.def_id() });
                 }
             }
@@ -708,13 +805,6 @@ fn finalize_resolutions_in(&mut self, module: Module<'b>, report_unresolved_impo
                 self.export_map.insert(node_id, reexports);
             }
         }
-
-        if report_unresolved_imports {
-            for import in module.unresolved_imports.borrow().iter() {
-                resolve_error(self.resolver, import.span, ResolutionError::UnresolvedImport(None));
-                break;
-            }
-        }
     }
 }
 
index 5e967f3250f710523440b186f468246a7d65b4e8..dbe956f021e4c3a90edc04d41231bd4fe28829ce 100644 (file)
@@ -1102,18 +1102,11 @@ fn visit_item(&mut self, item: &ast::Item) {
                     }
                     ast::ViewPathList(ref path, ref list) => {
                         for plid in list {
-                            match plid.node {
-                                ast::PathListItemKind::Ident { id, .. } => {
-                                    let scope = self.cur_scope;
-                                    if let Some(def_id) = self.lookup_type_ref(id) {
-                                        self.process_def_kind(id,
-                                                              plid.span,
-                                                              Some(plid.span),
-                                                              def_id,
-                                                              scope);
-                                    }
-                                }
-                                ast::PathListItemKind::Mod { .. } => (),
+                            let scope = self.cur_scope;
+                            let id = plid.node.id;
+                            if let Some(def_id) = self.lookup_type_ref(id) {
+                                let span = plid.span;
+                                self.process_def_kind(id, span, Some(span), def_id, scope);
                             }
                         }
 
diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs
deleted file mode 100644 (file)
index d6866b2..0000000
+++ /dev/null
@@ -1,2012 +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.
-
-//! # Compilation of match statements
-//!
-//! I will endeavor to explain the code as best I can.  I have only a loose
-//! understanding of some parts of it.
-//!
-//! ## Matching
-//!
-//! The basic state of the code is maintained in an array `m` of `Match`
-//! objects.  Each `Match` describes some list of patterns, all of which must
-//! match against the current list of values.  If those patterns match, then
-//! the arm listed in the match is the correct arm.  A given arm may have
-//! multiple corresponding match entries, one for each alternative that
-//! remains.  As we proceed these sets of matches are adjusted by the various
-//! `enter_XXX()` functions, each of which adjusts the set of options given
-//! some information about the value which has been matched.
-//!
-//! So, initially, there is one value and N matches, each of which have one
-//! constituent pattern.  N here is usually the number of arms but may be
-//! greater, if some arms have multiple alternatives.  For example, here:
-//!
-//!     enum Foo { A, B(int), C(usize, usize) }
-//!     match foo {
-//!         A => ...,
-//!         B(x) => ...,
-//!         C(1, 2) => ...,
-//!         C(_) => ...
-//!     }
-//!
-//! The value would be `foo`.  There would be four matches, each of which
-//! contains one pattern (and, in one case, a guard).  We could collect the
-//! various options and then compile the code for the case where `foo` is an
-//! `A`, a `B`, and a `C`.  When we generate the code for `C`, we would (1)
-//! drop the two matches that do not match a `C` and (2) expand the other two
-//! into two patterns each.  In the first case, the two patterns would be `1`
-//! and `2`, and the in the second case the _ pattern would be expanded into
-//! `_` and `_`.  The two values are of course the arguments to `C`.
-//!
-//! Here is a quick guide to the various functions:
-//!
-//! - `compile_submatch()`: The main workhouse.  It takes a list of values and
-//!   a list of matches and finds the various possibilities that could occur.
-//!
-//! - `enter_XXX()`: modifies the list of matches based on some information
-//!   about the value that has been matched.  For example,
-//!   `enter_rec_or_struct()` adjusts the values given that a record or struct
-//!   has been matched.  This is an infallible pattern, so *all* of the matches
-//!   must be either wildcards or record/struct patterns.  `enter_opt()`
-//!   handles the fallible cases, and it is correspondingly more complex.
-//!
-//! ## Bindings
-//!
-//! We store information about the bound variables for each arm as part of the
-//! per-arm `ArmData` struct.  There is a mapping from identifiers to
-//! `BindingInfo` structs.  These structs contain the mode/id/type of the
-//! binding, but they also contain an LLVM value which points at an alloca
-//! called `llmatch`. For by value bindings that are Copy, we also create
-//! an extra alloca that we copy the matched value to so that any changes
-//! we do to our copy is not reflected in the original and vice-versa.
-//! We don't do this if it's a move since the original value can't be used
-//! and thus allowing us to cheat in not creating an extra alloca.
-//!
-//! The `llmatch` binding always stores a pointer into the value being matched
-//! which points at the data for the binding.  If the value being matched has
-//! type `T`, then, `llmatch` will point at an alloca of type `T*` (and hence
-//! `llmatch` has type `T**`).  So, if you have a pattern like:
-//!
-//!    let a: A = ...;
-//!    let b: B = ...;
-//!    match (a, b) { (ref c, d) => { ... } }
-//!
-//! For `c` and `d`, we would generate allocas of type `C*` and `D*`
-//! respectively.  These are called the `llmatch`.  As we match, when we come
-//! up against an identifier, we store the current pointer into the
-//! corresponding alloca.
-//!
-//! Once a pattern is completely matched, and assuming that there is no guard
-//! pattern, we will branch to a block that leads to the body itself.  For any
-//! by-value bindings, this block will first load the ptr from `llmatch` (the
-//! one of type `D*`) and then load a second time to get the actual value (the
-//! one of type `D`). For by ref bindings, the value of the local variable is
-//! simply the first alloca.
-//!
-//! So, for the example above, we would generate a setup kind of like this:
-//!
-//!        +-------+
-//!        | Entry |
-//!        +-------+
-//!            |
-//!        +--------------------------------------------+
-//!        | llmatch_c = (addr of first half of tuple)  |
-//!        | llmatch_d = (addr of second half of tuple) |
-//!        +--------------------------------------------+
-//!            |
-//!        +--------------------------------------+
-//!        | *llbinding_d = **llmatch_d           |
-//!        +--------------------------------------+
-//!
-//! If there is a guard, the situation is slightly different, because we must
-//! execute the guard code.  Moreover, we need to do so once for each of the
-//! alternatives that lead to the arm, because if the guard fails, they may
-//! have different points from which to continue the search. Therefore, in that
-//! case, we generate code that looks more like:
-//!
-//!        +-------+
-//!        | Entry |
-//!        +-------+
-//!            |
-//!        +-------------------------------------------+
-//!        | llmatch_c = (addr of first half of tuple) |
-//!        | llmatch_d = (addr of first half of tuple) |
-//!        +-------------------------------------------+
-//!            |
-//!        +-------------------------------------------------+
-//!        | *llbinding_d = **llmatch_d                      |
-//!        | check condition                                 |
-//!        | if false { goto next case }                     |
-//!        | if true { goto body }                           |
-//!        +-------------------------------------------------+
-//!
-//! The handling for the cleanups is a bit... sensitive.  Basically, the body
-//! is the one that invokes `add_clean()` for each binding.  During the guard
-//! evaluation, we add temporary cleanups and revoke them after the guard is
-//! evaluated (it could fail, after all). Note that guards and moves are
-//! just plain incompatible.
-//!
-//! Some relevant helper functions that manage bindings:
-//! - `create_bindings_map()`
-//! - `insert_lllocals()`
-//!
-//!
-//! ## Notes on vector pattern matching.
-//!
-//! Vector pattern matching is surprisingly tricky. The problem is that
-//! the structure of the vector isn't fully known, and slice matches
-//! can be done on subparts of it.
-//!
-//! The way that vector pattern matches are dealt with, then, is as
-//! follows. First, we make the actual condition associated with a
-//! vector pattern simply a vector length comparison. So the pattern
-//! [1, .. x] gets the condition "vec len >= 1", and the pattern
-//! [.. x] gets the condition "vec len >= 0". The problem here is that
-//! having the condition "vec len >= 1" hold clearly does not mean that
-//! only a pattern that has exactly that condition will match. This
-//! means that it may well be the case that a condition holds, but none
-//! of the patterns matching that condition match; to deal with this,
-//! when doing vector length matches, we have match failures proceed to
-//! the next condition to check.
-//!
-//! There are a couple more subtleties to deal with. While the "actual"
-//! condition associated with vector length tests is simply a test on
-//! the vector length, the actual vec_len Opt entry contains more
-//! information used to restrict which matches are associated with it.
-//! So that all matches in a submatch are matching against the same
-//! values from inside the vector, they are split up by how many
-//! elements they match at the front and at the back of the vector. In
-//! order to make sure that arms are properly checked in order, even
-//! with the overmatching conditions, each vec_len Opt entry is
-//! associated with a range of matches.
-//! Consider the following:
-//!
-//!   match &[1, 2, 3] {
-//!       [1, 1, .. _] => 0,
-//!       [1, 2, 2, .. _] => 1,
-//!       [1, 2, 3, .. _] => 2,
-//!       [1, 2, .. _] => 3,
-//!       _ => 4
-//!   }
-//! The proper arm to match is arm 2, but arms 0 and 3 both have the
-//! condition "len >= 2". If arm 3 was lumped in with arm 0, then the
-//! wrong branch would be taken. Instead, vec_len Opts are associated
-//! with a contiguous range of matches that have the same "shape".
-//! This is sort of ugly and requires a bunch of special handling of
-//! vec_len options.
-
-pub use self::BranchKind::*;
-pub use self::OptResult::*;
-pub use self::TransBindingMode::*;
-use self::Opt::*;
-use self::FailureHandler::*;
-
-use llvm::{ValueRef, BasicBlockRef};
-use rustc_const_eval::check_match::{self, Constructor, StaticInliner};
-use rustc_const_eval::{compare_lit_exprs, eval_const_expr, fatal_const_eval_err};
-use rustc::hir::def::{Def, DefMap};
-use rustc::hir::def_id::DefId;
-use middle::expr_use_visitor as euv;
-use middle::lang_items::StrEqFnLangItem;
-use middle::mem_categorization as mc;
-use middle::mem_categorization::Categorization;
-use rustc::hir::pat_util::*;
-use rustc::ty::subst::Substs;
-use adt;
-use base::*;
-use build::{AddCase, And, Br, CondBr, GEPi, InBoundsGEP, Load, PointerCast};
-use build::{Not, Store, Sub, add_comment};
-use build;
-use callee::{Callee, ArgVals};
-use cleanup::{self, CleanupMethods, DropHintMethods};
-use common::*;
-use consts;
-use datum::*;
-use debuginfo::{self, DebugLoc, ToDebugLoc};
-use expr::{self, Dest};
-use monomorphize;
-use tvec;
-use type_of;
-use Disr;
-use value::Value;
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc::traits::Reveal;
-use session::config::NoDebugInfo;
-use util::common::indenter;
-use util::nodemap::FnvHashMap;
-use util::ppaux;
-
-use std;
-use std::cell::RefCell;
-use std::cmp::Ordering;
-use std::fmt;
-use std::rc::Rc;
-use rustc::hir::{self, PatKind};
-use syntax::ast::{self, DUMMY_NODE_ID, NodeId};
-use syntax_pos::Span;
-use rustc::hir::fold::Folder;
-use syntax::ptr::P;
-
-#[derive(Copy, Clone, Debug)]
-struct ConstantExpr<'a>(&'a hir::Expr);
-
-impl<'a> ConstantExpr<'a> {
-    fn eq<'b, 'tcx>(self, other: ConstantExpr<'a>, tcx: TyCtxt<'b, 'tcx, 'tcx>) -> bool {
-        match compare_lit_exprs(tcx, self.0.span, self.0, other.0) {
-            Ok(result) => result == Ordering::Equal,
-            Err(_) => bug!("compare_list_exprs: type mismatch"),
-        }
-    }
-}
-
-// An option identifying a branch (either a literal, an enum variant or a range)
-#[derive(Debug)]
-enum Opt<'a, 'tcx> {
-    ConstantValue(ConstantExpr<'a>, DebugLoc),
-    ConstantRange(ConstantExpr<'a>, ConstantExpr<'a>, DebugLoc),
-    Variant(Disr, Rc<adt::Repr<'tcx>>, DefId, DebugLoc),
-    SliceLengthEqual(usize, DebugLoc),
-    SliceLengthGreaterOrEqual(/* prefix length */ usize,
-                              /* suffix length */ usize,
-                              DebugLoc),
-}
-
-impl<'a, 'b, 'tcx> Opt<'a, 'tcx> {
-    fn eq(&self, other: &Opt<'a, 'tcx>, tcx: TyCtxt<'b, 'tcx, 'tcx>) -> bool {
-        match (self, other) {
-            (&ConstantValue(a, _), &ConstantValue(b, _)) => a.eq(b, tcx),
-            (&ConstantRange(a1, a2, _), &ConstantRange(b1, b2, _)) => {
-                a1.eq(b1, tcx) && a2.eq(b2, tcx)
-            }
-            (&Variant(a_disr, ref a_repr, a_def, _),
-             &Variant(b_disr, ref b_repr, b_def, _)) => {
-                a_disr == b_disr && *a_repr == *b_repr && a_def == b_def
-            }
-            (&SliceLengthEqual(a, _), &SliceLengthEqual(b, _)) => a == b,
-            (&SliceLengthGreaterOrEqual(a1, a2, _),
-             &SliceLengthGreaterOrEqual(b1, b2, _)) => {
-                a1 == b1 && a2 == b2
-            }
-            _ => false
-        }
-    }
-
-    fn trans<'blk>(&self, mut bcx: Block<'blk, 'tcx>) -> OptResult<'blk, 'tcx> {
-        use consts::TrueConst::Yes;
-        let _icx = push_ctxt("match::trans_opt");
-        let ccx = bcx.ccx();
-        match *self {
-            ConstantValue(ConstantExpr(lit_expr), _) => {
-                let lit_ty = bcx.tcx().node_id_to_type(lit_expr.id);
-                let expr = consts::const_expr(ccx, &lit_expr, bcx.fcx.param_substs, None, Yes);
-                let llval = match expr {
-                    Ok((llval, _)) => llval,
-                    Err(err) => {
-                        fatal_const_eval_err(bcx.tcx(), err.as_inner(), lit_expr.span, "pattern");
-                    }
-                };
-                let lit_datum = immediate_rvalue(llval, lit_ty);
-                let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
-                SingleResult(Result::new(bcx, lit_datum.val))
-            }
-            ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => {
-                let l1 = match consts::const_expr(ccx, &l1, bcx.fcx.param_substs, None, Yes) {
-                    Ok((l1, _)) => l1,
-                    Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l1.span, "pattern"),
-                };
-                let l2 = match consts::const_expr(ccx, &l2, bcx.fcx.param_substs, None, Yes) {
-                    Ok((l2, _)) => l2,
-                    Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l2.span, "pattern"),
-                };
-                RangeResult(Result::new(bcx, l1), Result::new(bcx, l2))
-            }
-            Variant(disr_val, ref repr, _, _) => {
-                SingleResult(Result::new(bcx, adt::trans_case(bcx, &repr, disr_val)))
-            }
-            SliceLengthEqual(length, _) => {
-                SingleResult(Result::new(bcx, C_uint(ccx, length)))
-            }
-            SliceLengthGreaterOrEqual(prefix, suffix, _) => {
-                LowerBound(Result::new(bcx, C_uint(ccx, prefix + suffix)))
-            }
-        }
-    }
-
-    fn debug_loc(&self) -> DebugLoc {
-        match *self {
-            ConstantValue(_,debug_loc)                 |
-            ConstantRange(_, _, debug_loc)             |
-            Variant(_, _, _, debug_loc)                |
-            SliceLengthEqual(_, debug_loc)             |
-            SliceLengthGreaterOrEqual(_, _, debug_loc) => debug_loc
-        }
-    }
-}
-
-#[derive(Copy, Clone, PartialEq)]
-pub enum BranchKind {
-    NoBranch,
-    Single,
-    Switch,
-    Compare,
-    CompareSliceLength
-}
-
-pub enum OptResult<'blk, 'tcx: 'blk> {
-    SingleResult(Result<'blk, 'tcx>),
-    RangeResult(Result<'blk, 'tcx>, Result<'blk, 'tcx>),
-    LowerBound(Result<'blk, 'tcx>)
-}
-
-#[derive(Clone, Copy, PartialEq)]
-pub enum TransBindingMode {
-    /// By-value binding for a copy type: copies from matched data
-    /// into a fresh LLVM alloca.
-    TrByCopy(/* llbinding */ ValueRef),
-
-    /// By-value binding for a non-copy type where we copy into a
-    /// fresh LLVM alloca; this most accurately reflects the language
-    /// semantics (e.g. it properly handles overwrites of the matched
-    /// input), but potentially injects an unwanted copy.
-    TrByMoveIntoCopy(/* llbinding */ ValueRef),
-
-    /// Binding a non-copy type by reference under the hood; this is
-    /// a codegen optimization to avoid unnecessary memory traffic.
-    TrByMoveRef,
-
-    /// By-ref binding exposed in the original source input.
-    TrByRef,
-}
-
-impl TransBindingMode {
-    /// if binding by making a fresh copy; returns the alloca that it
-    /// will copy into; otherwise None.
-    fn alloca_if_copy(&self) -> Option<ValueRef> {
-        match *self {
-            TrByCopy(llbinding) | TrByMoveIntoCopy(llbinding) => Some(llbinding),
-            TrByMoveRef | TrByRef => None,
-        }
-    }
-}
-
-/// Information about a pattern binding:
-/// - `llmatch` is a pointer to a stack slot.  The stack slot contains a
-///   pointer into the value being matched.  Hence, llmatch has type `T**`
-///   where `T` is the value being matched.
-/// - `trmode` is the trans binding mode
-/// - `id` is the node id of the binding
-/// - `ty` is the Rust type of the binding
-#[derive(Clone, Copy)]
-pub struct BindingInfo<'tcx> {
-    pub llmatch: ValueRef,
-    pub trmode: TransBindingMode,
-    pub id: ast::NodeId,
-    pub span: Span,
-    pub ty: Ty<'tcx>,
-}
-
-type BindingsMap<'tcx> = FnvHashMap<ast::Name, BindingInfo<'tcx>>;
-
-struct ArmData<'p, 'blk, 'tcx: 'blk> {
-    bodycx: Block<'blk, 'tcx>,
-    arm: &'p hir::Arm,
-    bindings_map: BindingsMap<'tcx>
-}
-
-/// Info about Match.
-/// If all `pats` are matched then arm `data` will be executed.
-/// As we proceed `bound_ptrs` are filled with pointers to values to be bound,
-/// these pointers are stored in llmatch variables just before executing `data` arm.
-struct Match<'a, 'p: 'a, 'blk: 'a, 'tcx: 'blk> {
-    pats: Vec<&'p hir::Pat>,
-    data: &'a ArmData<'p, 'blk, 'tcx>,
-    bound_ptrs: Vec<(ast::Name, ValueRef)>,
-    // Thread along renamings done by the check_match::StaticInliner, so we can
-    // map back to original NodeIds
-    pat_renaming_map: Option<&'a FnvHashMap<(NodeId, Span), NodeId>>
-}
-
-impl<'a, 'p, 'blk, 'tcx> fmt::Debug for Match<'a, 'p, 'blk, 'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        if ppaux::verbose() {
-            // for many programs, this just take too long to serialize
-            write!(f, "{:?}", self.pats)
-        } else {
-            write!(f, "{} pats", self.pats.len())
-        }
-    }
-}
-
-fn has_nested_bindings(m: &[Match], col: usize) -> bool {
-    for br in m {
-        if let PatKind::Binding(_, _, Some(..)) = br.pats[col].node {
-            return true
-        }
-    }
-    false
-}
-
-// As noted in `fn match_datum`, we should eventually pass around a
-// `Datum<Lvalue>` for the `val`; but until we get to that point, this
-// `MatchInput` struct will serve -- it has everything `Datum<Lvalue>`
-// does except for the type field.
-#[derive(Copy, Clone)]
-pub struct MatchInput { val: ValueRef, lval: Lvalue }
-
-impl<'tcx> Datum<'tcx, Lvalue> {
-    pub fn match_input(&self) -> MatchInput {
-        MatchInput {
-            val: self.val,
-            lval: self.kind,
-        }
-    }
-}
-
-impl fmt::Debug for MatchInput {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Debug::fmt(&Value(self.val), f)
-    }
-}
-
-impl MatchInput {
-    fn from_val(val: ValueRef) -> MatchInput {
-        MatchInput {
-            val: val,
-            lval: Lvalue::new("MatchInput::from_val"),
-        }
-    }
-
-    fn to_datum<'tcx>(self, ty: Ty<'tcx>) -> Datum<'tcx, Lvalue> {
-        Datum::new(self.val, ty, self.lval)
-    }
-}
-
-fn expand_nested_bindings<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                              m: &[Match<'a, 'p, 'blk, 'tcx>],
-                                              col: usize,
-                                              val: MatchInput)
-                                              -> Vec<Match<'a, 'p, 'blk, 'tcx>> {
-    debug!("expand_nested_bindings(bcx={}, m={:?}, col={}, val={:?})",
-           bcx.to_str(), m, col, val);
-    let _indenter = indenter();
-
-    m.iter().map(|br| {
-        let mut bound_ptrs = br.bound_ptrs.clone();
-        let mut pat = br.pats[col];
-        loop {
-            pat = match pat.node {
-                PatKind::Binding(_, ref path, Some(ref inner)) => {
-                    bound_ptrs.push((path.node, val.val));
-                    &inner
-                },
-                _ => break
-            }
-        }
-
-        let mut pats = br.pats.clone();
-        pats[col] = pat;
-        Match {
-            pats: pats,
-            data: &br.data,
-            bound_ptrs: bound_ptrs,
-            pat_renaming_map: br.pat_renaming_map,
-        }
-    }).collect()
-}
-
-fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
-                                          m: &[Match<'a, 'p, 'blk, 'tcx>],
-                                          col: usize,
-                                          val: MatchInput,
-                                          mut e: F)
-                                          -> Vec<Match<'a, 'p, 'blk, 'tcx>> where
-    F: FnMut(&[(&'p hir::Pat, Option<Ty<'tcx>>)])
-             -> Option<Vec<(&'p hir::Pat, Option<Ty<'tcx>>)>>,
-{
-    debug!("enter_match(bcx={}, m={:?}, col={}, val={:?})",
-           bcx.to_str(), m, col, val);
-    let _indenter = indenter();
-
-    m.iter().filter_map(|br| {
-        let pats : Vec<_> = br.pats.iter().map(|p| (*p, None)).collect();
-        e(&pats).map(|pats| {
-            let this = br.pats[col];
-            let mut bound_ptrs = br.bound_ptrs.clone();
-            match this.node {
-                PatKind::Binding(_, ref path, None) => {
-                    bound_ptrs.push((path.node, val.val));
-                }
-                PatKind::Vec(ref before, Some(ref slice), ref after) => {
-                    if let PatKind::Binding(_, ref path, None) = slice.node {
-                        let subslice_val = bind_subslice_pat(
-                            bcx, this.id, val,
-                            before.len(), after.len());
-                        bound_ptrs.push((path.node, subslice_val));
-                    }
-                }
-                _ => {}
-            }
-            Match {
-                pats: pats.into_iter().map(|p| p.0).collect(),
-                data: br.data,
-                bound_ptrs: bound_ptrs,
-                pat_renaming_map: br.pat_renaming_map,
-            }
-        })
-    }).collect()
-}
-
-fn enter_default<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                     m: &[Match<'a, 'p, 'blk, 'tcx>],
-                                     col: usize,
-                                     val: MatchInput)
-                                     -> Vec<Match<'a, 'p, 'blk, 'tcx>> {
-    debug!("enter_default(bcx={}, m={:?}, col={}, val={:?})",
-           bcx.to_str(), m, col, val);
-    let _indenter = indenter();
-
-    // Collect all of the matches that can match against anything.
-    enter_match(bcx, m, col, val, |pats| {
-        match pats[col].0.node {
-            PatKind::Binding(..) | PatKind::Wild => {
-                let mut r = pats[..col].to_vec();
-                r.extend_from_slice(&pats[col + 1..]);
-                Some(r)
-            }
-            _ => None
-        }
-    })
-}
-
-// <pcwalton> nmatsakis: what does enter_opt do?
-// <pcwalton> in trans/match
-// <pcwalton> trans/match.rs is like stumbling around in a dark cave
-// <nmatsakis> pcwalton: the enter family of functions adjust the set of
-//             patterns as needed
-// <nmatsakis> yeah, at some point I kind of achieved some level of
-//             understanding
-// <nmatsakis> anyhow, they adjust the patterns given that something of that
-//             kind has been found
-// <nmatsakis> pcwalton: ok, right, so enter_XXX() adjusts the patterns, as I
-//             said
-// <nmatsakis> enter_match() kind of embodies the generic code
-// <nmatsakis> it is provided with a function that tests each pattern to see
-//             if it might possibly apply and so forth
-// <nmatsakis> so, if you have a pattern like {a: _, b: _, _} and one like _
-// <nmatsakis> then _ would be expanded to (_, _)
-// <nmatsakis> one spot for each of the sub-patterns
-// <nmatsakis> enter_opt() is one of the more complex; it covers the fallible
-//             cases
-// <nmatsakis> enter_rec_or_struct() or enter_tuple() are simpler, since they
-//             are infallible patterns
-// <nmatsakis> so all patterns must either be records (resp. tuples) or
-//             wildcards
-
-/// The above is now outdated in that enter_match() now takes a function that
-/// takes the complete row of patterns rather than just the first one.
-/// Also, most of the enter_() family functions have been unified with
-/// the check_match specialization step.
-fn enter_opt<'a, 'p, 'blk, 'tcx>(
-             bcx: Block<'blk, 'tcx>,
-             _: ast::NodeId,
-             m: &[Match<'a, 'p, 'blk, 'tcx>],
-             opt: &Opt,
-             col: usize,
-             variant_size: usize,
-             val: MatchInput)
-             -> Vec<Match<'a, 'p, 'blk, 'tcx>> {
-    debug!("enter_opt(bcx={}, m={:?}, opt={:?}, col={}, val={:?})",
-           bcx.to_str(), m, *opt, col, val);
-    let _indenter = indenter();
-
-    let ctor = match opt {
-        &ConstantValue(ConstantExpr(expr), _) => Constructor::ConstantValue(
-            eval_const_expr(bcx.tcx(), &expr)
-        ),
-        &ConstantRange(ConstantExpr(lo), ConstantExpr(hi), _) => Constructor::ConstantRange(
-            eval_const_expr(bcx.tcx(), &lo),
-            eval_const_expr(bcx.tcx(), &hi)
-        ),
-        &SliceLengthEqual(n, _) =>
-            Constructor::Slice(n),
-        &SliceLengthGreaterOrEqual(before, after, _) =>
-            Constructor::SliceWithSubslice(before, after),
-        &Variant(_, _, def_id, _) =>
-            Constructor::Variant(def_id)
-    };
-
-    let param_env = bcx.tcx().empty_parameter_environment();
-    let mcx = check_match::MatchCheckCtxt {
-        tcx: bcx.tcx(),
-        param_env: param_env,
-    };
-    enter_match(bcx, m, col, val, |pats|
-        check_match::specialize(&mcx, &pats[..], &ctor, col, variant_size)
-    )
-}
-
-// Returns the options in one column of matches. An option is something that
-// needs to be conditionally matched at runtime; for example, the discriminant
-// on a set of enum variants or a literal.
-fn get_branches<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                    m: &[Match<'a, 'p, 'blk, 'tcx>],
-                                    col: usize)
-                                    -> Vec<Opt<'p, 'tcx>> {
-    let tcx = bcx.tcx();
-
-    let mut found: Vec<Opt> = vec![];
-    for br in m {
-        let cur = br.pats[col];
-        let debug_loc = match br.pat_renaming_map {
-            Some(pat_renaming_map) => {
-                match pat_renaming_map.get(&(cur.id, cur.span)) {
-                    Some(&id) => DebugLoc::At(id, cur.span),
-                    None => DebugLoc::At(cur.id, cur.span),
-                }
-            }
-            None => DebugLoc::None
-        };
-
-        let opt = match cur.node {
-            PatKind::Lit(ref l) => {
-                ConstantValue(ConstantExpr(&l), debug_loc)
-            }
-            PatKind::Path(..) | PatKind::TupleStruct(..) | PatKind::Struct(..) => {
-                match tcx.expect_def(cur.id) {
-                    Def::Variant(enum_id, var_id) => {
-                        let variant = tcx.lookup_adt_def(enum_id).variant_with_id(var_id);
-                        Variant(Disr::from(variant.disr_val),
-                                adt::represent_node(bcx, cur.id),
-                                var_id,
-                                debug_loc)
-                    }
-                    _ => continue
-                }
-            }
-            PatKind::Range(ref l1, ref l2) => {
-                ConstantRange(ConstantExpr(&l1), ConstantExpr(&l2), debug_loc)
-            }
-            PatKind::Vec(ref before, None, ref after) => {
-                SliceLengthEqual(before.len() + after.len(), debug_loc)
-            }
-            PatKind::Vec(ref before, Some(_), ref after) => {
-                SliceLengthGreaterOrEqual(before.len(), after.len(), debug_loc)
-            }
-            _ => continue
-        };
-
-        if !found.iter().any(|x| x.eq(&opt, tcx)) {
-            found.push(opt);
-        }
-    }
-    found
-}
-
-struct ExtractedBlock<'blk, 'tcx: 'blk> {
-    vals: Vec<ValueRef>,
-    bcx: Block<'blk, 'tcx>,
-}
-
-fn extract_variant_args<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                    repr: &adt::Repr<'tcx>,
-                                    disr_val: Disr,
-                                    val: MatchInput)
-                                    -> ExtractedBlock<'blk, 'tcx> {
-    let _icx = push_ctxt("match::extract_variant_args");
-    // Assume enums are always sized for now.
-    let val = adt::MaybeSizedValue::sized(val.val);
-    let args = (0..adt::num_args(repr, disr_val)).map(|i| {
-        adt::trans_field_ptr(bcx, repr, val, disr_val, i)
-    }).collect();
-
-    ExtractedBlock { vals: args, bcx: bcx }
-}
-
-/// Helper for converting from the ValueRef that we pass around in the match code, which is always
-/// an lvalue, into a Datum. Eventually we should just pass around a Datum and be done with it.
-fn match_datum<'tcx>(val: MatchInput, left_ty: Ty<'tcx>) -> Datum<'tcx, Lvalue> {
-    val.to_datum(left_ty)
-}
-
-fn bind_subslice_pat(bcx: Block,
-                     pat_id: ast::NodeId,
-                     val: MatchInput,
-                     offset_left: usize,
-                     offset_right: usize) -> ValueRef {
-    let _icx = push_ctxt("match::bind_subslice_pat");
-    let vec_ty = node_id_type(bcx, pat_id);
-    let vec_ty_contents = match vec_ty.sty {
-        ty::TyBox(ty) => ty,
-        ty::TyRef(_, mt) | ty::TyRawPtr(mt) => mt.ty,
-        _ => vec_ty
-    };
-    let unit_ty = vec_ty_contents.sequence_element_type(bcx.tcx());
-    let vec_datum = match_datum(val, vec_ty);
-    let (base, len) = vec_datum.get_vec_base_and_len(bcx);
-
-    let slice_begin = InBoundsGEP(bcx, base, &[C_uint(bcx.ccx(), offset_left)]);
-    let diff = offset_left + offset_right;
-    if let ty::TyArray(ty, n) = vec_ty_contents.sty {
-        let array_ty = bcx.tcx().mk_array(ty, n-diff);
-        let llty_array = type_of::type_of(bcx.ccx(), array_ty);
-        return PointerCast(bcx, slice_begin, llty_array.ptr_to());
-    }
-
-    let slice_len_offset = C_uint(bcx.ccx(), diff);
-    let slice_len = Sub(bcx, len, slice_len_offset, DebugLoc::None);
-    let slice_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReErased),
-                                         bcx.tcx().mk_slice(unit_ty));
-    let scratch = rvalue_scratch_datum(bcx, slice_ty, "");
-    Store(bcx, slice_begin, expr::get_dataptr(bcx, scratch.val));
-    Store(bcx, slice_len, expr::get_meta(bcx, scratch.val));
-    scratch.val
-}
-
-fn extract_vec_elems<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                 left_ty: Ty<'tcx>,
-                                 before: usize,
-                                 after: usize,
-                                 val: MatchInput)
-                                 -> ExtractedBlock<'blk, 'tcx> {
-    let _icx = push_ctxt("match::extract_vec_elems");
-    let vec_datum = match_datum(val, left_ty);
-    let (base, len) = vec_datum.get_vec_base_and_len(bcx);
-    let mut elems = vec![];
-    elems.extend((0..before).map(|i| GEPi(bcx, base, &[i])));
-    elems.extend((0..after).rev().map(|i| {
-        InBoundsGEP(bcx, base, &[
-            Sub(bcx, len, C_uint(bcx.ccx(), i + 1), DebugLoc::None)
-        ])
-    }));
-    ExtractedBlock { vals: elems, bcx: bcx }
-}
-
-// Macro for deciding whether any of the remaining matches fit a given kind of
-// pattern.  Note that, because the macro is well-typed, either ALL of the
-// matches should fit that sort of pattern or NONE (however, some of the
-// matches may be wildcards like _ or identifiers).
-macro_rules! any_pat {
-    ($m:expr, $col:expr, $pattern:pat) => (
-        ($m).iter().any(|br| {
-            match br.pats[$col].node {
-                $pattern => true,
-                _ => false
-            }
-        })
-    )
-}
-
-fn any_uniq_pat(m: &[Match], col: usize) -> bool {
-    any_pat!(m, col, PatKind::Box(_))
-}
-
-fn any_region_pat(m: &[Match], col: usize) -> bool {
-    any_pat!(m, col, PatKind::Ref(..))
-}
-
-fn any_irrefutable_adt_pat(tcx: TyCtxt, m: &[Match], col: usize) -> bool {
-    m.iter().any(|br| {
-        let pat = br.pats[col];
-        match pat.node {
-            PatKind::Tuple(..) => true,
-            PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => {
-                match tcx.expect_def(pat.id) {
-                    Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => true,
-                    _ => false,
-                }
-            }
-            _ => false
-        }
-    })
-}
-
-/// What to do when the pattern match fails.
-enum FailureHandler {
-    Infallible,
-    JumpToBasicBlock(BasicBlockRef),
-    Unreachable
-}
-
-impl FailureHandler {
-    fn is_fallible(&self) -> bool {
-        match *self {
-            Infallible => false,
-            _ => true
-        }
-    }
-
-    fn is_infallible(&self) -> bool {
-        !self.is_fallible()
-    }
-
-    fn handle_fail(&self, bcx: Block) {
-        match *self {
-            Infallible =>
-                bug!("attempted to panic in a non-panicking panic handler!"),
-            JumpToBasicBlock(basic_block) =>
-                Br(bcx, basic_block, DebugLoc::None),
-            Unreachable =>
-                build::Unreachable(bcx)
-        }
-    }
-}
-
-fn pick_column_to_specialize(def_map: &RefCell<DefMap>, m: &[Match]) -> Option<usize> {
-    fn pat_score(def_map: &RefCell<DefMap>, pat: &hir::Pat) -> usize {
-        match pat.node {
-            PatKind::Binding(_, _, Some(ref inner)) => pat_score(def_map, &inner),
-            _ if pat_is_refutable(&def_map.borrow(), pat) => 1,
-            _ => 0
-        }
-    }
-
-    let column_score = |m: &[Match], col: usize| -> usize {
-        let total_score = m.iter()
-            .map(|row| row.pats[col])
-            .map(|pat| pat_score(def_map, pat))
-            .sum();
-
-        // Irrefutable columns always go first, they'd only be duplicated in the branches.
-        if total_score == 0 {
-            std::usize::MAX
-        } else {
-            total_score
-        }
-    };
-
-    let column_contains_any_nonwild_patterns = |&col: &usize| -> bool {
-        m.iter().any(|row| match row.pats[col].node {
-            PatKind::Wild => false,
-            _ => true
-        })
-    };
-
-    (0..m[0].pats.len())
-        .filter(column_contains_any_nonwild_patterns)
-        .map(|col| (col, column_score(m, col)))
-        .max_by_key(|&(_, score)| score)
-        .map(|(col, _)| col)
-}
-
-// Compiles a comparison between two things.
-fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
-                              lhs: ValueRef,
-                              rhs: ValueRef,
-                              rhs_t: Ty<'tcx>,
-                              debug_loc: DebugLoc)
-                              -> Result<'blk, 'tcx> {
-    fn compare_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                               lhs_data: ValueRef,
-                               lhs_len: ValueRef,
-                               rhs_data: ValueRef,
-                               rhs_len: ValueRef,
-                               rhs_t: Ty<'tcx>,
-                               debug_loc: DebugLoc)
-                               -> Result<'blk, 'tcx> {
-        let did = langcall(bcx.tcx(),
-                           None,
-                           &format!("comparison of `{}`", rhs_t),
-                           StrEqFnLangItem);
-        let args = [lhs_data, lhs_len, rhs_data, rhs_len];
-        Callee::def(bcx.ccx(), did, Substs::empty(bcx.tcx()))
-            .call(bcx, debug_loc, ArgVals(&args), None)
-    }
-
-    let _icx = push_ctxt("compare_values");
-    if rhs_t.is_scalar() {
-        let cmp = compare_scalar_types(cx, lhs, rhs, rhs_t, hir::BiEq, debug_loc);
-        return Result::new(cx, cmp);
-    }
-
-    match rhs_t.sty {
-        ty::TyRef(_, mt) => match mt.ty.sty {
-            ty::TyStr => {
-                let lhs_data = Load(cx, expr::get_dataptr(cx, lhs));
-                let lhs_len = Load(cx, expr::get_meta(cx, lhs));
-                let rhs_data = Load(cx, expr::get_dataptr(cx, rhs));
-                let rhs_len = Load(cx, expr::get_meta(cx, rhs));
-                compare_str(cx, lhs_data, lhs_len, rhs_data, rhs_len, rhs_t, debug_loc)
-            }
-            ty::TyArray(ty, _) | ty::TySlice(ty) => match ty.sty {
-                ty::TyUint(ast::UintTy::U8) => {
-                    // NOTE: cast &[u8] and &[u8; N] to &str and abuse the str_eq lang item,
-                    // which calls memcmp().
-                    let pat_len = val_ty(rhs).element_type().array_length();
-                    let ty_str_slice = cx.tcx().mk_static_str();
-
-                    let rhs_data = GEPi(cx, rhs, &[0, 0]);
-                    let rhs_len = C_uint(cx.ccx(), pat_len);
-
-                    let lhs_data;
-                    let lhs_len;
-                    if val_ty(lhs) == val_ty(rhs) {
-                        // Both the discriminant and the pattern are thin pointers
-                        lhs_data = GEPi(cx, lhs, &[0, 0]);
-                        lhs_len = C_uint(cx.ccx(), pat_len);
-                    } else {
-                        // The discriminant is a fat pointer
-                        let llty_str_slice = type_of::type_of(cx.ccx(), ty_str_slice).ptr_to();
-                        let lhs_str = PointerCast(cx, lhs, llty_str_slice);
-                        lhs_data = Load(cx, expr::get_dataptr(cx, lhs_str));
-                        lhs_len = Load(cx, expr::get_meta(cx, lhs_str));
-                    }
-
-                    compare_str(cx, lhs_data, lhs_len, rhs_data, rhs_len, rhs_t, debug_loc)
-                },
-                _ => bug!("only byte strings supported in compare_values"),
-            },
-            _ => bug!("only string and byte strings supported in compare_values"),
-        },
-        _ => bug!("only scalars, byte strings, and strings supported in compare_values"),
-    }
-}
-
-/// For each binding in `data.bindings_map`, adds an appropriate entry into the `fcx.lllocals` map
-fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
-                               bindings_map: &BindingsMap<'tcx>,
-                               cs: Option<cleanup::ScopeId>)
-                               -> Block<'blk, 'tcx> {
-    for (&name, &binding_info) in bindings_map {
-        let (llval, aliases_other_state) = match binding_info.trmode {
-            // By value mut binding for a copy type: load from the ptr
-            // into the matched value and copy to our alloca
-            TrByCopy(llbinding) |
-            TrByMoveIntoCopy(llbinding) => {
-                let llval = Load(bcx, binding_info.llmatch);
-                let lvalue = match binding_info.trmode {
-                    TrByCopy(..) =>
-                        Lvalue::new("_match::insert_lllocals"),
-                    TrByMoveIntoCopy(..) => {
-                        // match_input moves from the input into a
-                        // separate stack slot.
-                        //
-                        // E.g. consider moving the value `D(A)` out
-                        // of the tuple `(D(A), D(B))` and into the
-                        // local variable `x` via the pattern `(x,_)`,
-                        // leaving the remainder of the tuple `(_,
-                        // D(B))` still to be dropped in the future.
-                        //
-                        // Thus, here we must zero the place that we
-                        // are moving *from*, because we do not yet
-                        // track drop flags for a fragmented parent
-                        // match input expression.
-                        //
-                        // Longer term we will be able to map the move
-                        // into `(x, _)` up to the parent path that
-                        // owns the whole tuple, and mark the
-                        // corresponding stack-local drop-flag
-                        // tracking the first component of the tuple.
-                        let hint_kind = HintKind::ZeroAndMaintain;
-                        Lvalue::new_with_hint("_match::insert_lllocals (match_input)",
-                                              bcx, binding_info.id, hint_kind)
-                    }
-                    _ => bug!(),
-                };
-                let datum = Datum::new(llval, binding_info.ty, lvalue);
-                call_lifetime_start(bcx, llbinding);
-                bcx = datum.store_to(bcx, llbinding);
-                if let Some(cs) = cs {
-                    bcx.fcx.schedule_lifetime_end(cs, llbinding);
-                }
-
-                (llbinding, false)
-            },
-
-            // By value move bindings: load from the ptr into the matched value
-            TrByMoveRef => (Load(bcx, binding_info.llmatch), true),
-
-            // By ref binding: use the ptr into the matched value
-            TrByRef => (binding_info.llmatch, true),
-        };
-
-
-        // A local that aliases some other state must be zeroed, since
-        // the other state (e.g. some parent data that we matched
-        // into) will still have its subcomponents (such as this
-        // local) destructed at the end of the parent's scope. Longer
-        // term, we will properly map such parents to the set of
-        // unique drop flags for its fragments.
-        let hint_kind = if aliases_other_state {
-            HintKind::ZeroAndMaintain
-        } else {
-            HintKind::DontZeroJustUse
-        };
-        let lvalue = Lvalue::new_with_hint("_match::insert_lllocals (local)",
-                                           bcx,
-                                           binding_info.id,
-                                           hint_kind);
-        let datum = Datum::new(llval, binding_info.ty, lvalue);
-        if let Some(cs) = cs {
-            let opt_datum = lvalue.dropflag_hint(bcx);
-            bcx.fcx.schedule_lifetime_end(cs, binding_info.llmatch);
-            bcx.fcx.schedule_drop_and_fill_mem(cs, llval, binding_info.ty, opt_datum);
-        }
-
-        debug!("binding {} to {:?}", binding_info.id, Value(llval));
-        bcx.fcx.lllocals.borrow_mut().insert(binding_info.id, datum);
-        debuginfo::create_match_binding_metadata(bcx, name, binding_info);
-    }
-    bcx
-}
-
-fn compile_guard<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                     guard_expr: &hir::Expr,
-                                     data: &ArmData<'p, 'blk, 'tcx>,
-                                     m: &[Match<'a, 'p, 'blk, 'tcx>],
-                                     vals: &[MatchInput],
-                                     chk: &FailureHandler,
-                                     has_genuine_default: bool)
-                                     -> Block<'blk, 'tcx> {
-    debug!("compile_guard(bcx={}, guard_expr={:?}, m={:?}, vals={:?})",
-           bcx.to_str(), guard_expr, m, vals);
-    let _indenter = indenter();
-
-    let mut bcx = insert_lllocals(bcx, &data.bindings_map, None);
-
-    let val = unpack_datum!(bcx, expr::trans(bcx, guard_expr));
-    let val = val.to_llbool(bcx);
-
-    for (_, &binding_info) in &data.bindings_map {
-        if let Some(llbinding) = binding_info.trmode.alloca_if_copy() {
-            call_lifetime_end(bcx, llbinding)
-        }
-    }
-
-    for (_, &binding_info) in &data.bindings_map {
-        bcx.fcx.lllocals.borrow_mut().remove(&binding_info.id);
-    }
-
-    with_cond(bcx, Not(bcx, val, guard_expr.debug_loc()), |bcx| {
-        for (_, &binding_info) in &data.bindings_map {
-            call_lifetime_end(bcx, binding_info.llmatch);
-        }
-        match chk {
-            // If the default arm is the only one left, move on to the next
-            // condition explicitly rather than (possibly) falling back to
-            // the default arm.
-            &JumpToBasicBlock(_) if m.len() == 1 && has_genuine_default => {
-                chk.handle_fail(bcx);
-            }
-            _ => {
-                compile_submatch(bcx, m, vals, chk, has_genuine_default);
-            }
-        };
-        bcx
-    })
-}
-
-fn compile_submatch<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                        m: &[Match<'a, 'p, 'blk, 'tcx>],
-                                        vals: &[MatchInput],
-                                        chk: &FailureHandler,
-                                        has_genuine_default: bool) {
-    debug!("compile_submatch(bcx={}, m={:?}, vals=[{:?}])",
-           bcx.to_str(), m, vals);
-    let _indenter = indenter();
-    let _icx = push_ctxt("match::compile_submatch");
-    let mut bcx = bcx;
-    if m.is_empty() {
-        if chk.is_fallible() {
-            chk.handle_fail(bcx);
-        }
-        return;
-    }
-
-    let tcx = bcx.tcx();
-    let def_map = &tcx.def_map;
-    match pick_column_to_specialize(def_map, m) {
-        Some(col) => {
-            let val = vals[col];
-            if has_nested_bindings(m, col) {
-                let expanded = expand_nested_bindings(bcx, m, col, val);
-                compile_submatch_continue(bcx,
-                                          &expanded[..],
-                                          vals,
-                                          chk,
-                                          col,
-                                          val,
-                                          has_genuine_default)
-            } else {
-                compile_submatch_continue(bcx, m, vals, chk, col, val, has_genuine_default)
-            }
-        }
-        None => {
-            let data = &m[0].data;
-            for &(ref name, ref value_ptr) in &m[0].bound_ptrs {
-                let binfo = *data.bindings_map.get(name).unwrap();
-                call_lifetime_start(bcx, binfo.llmatch);
-                if binfo.trmode == TrByRef && type_is_fat_ptr(bcx.tcx(), binfo.ty) {
-                    expr::copy_fat_ptr(bcx, *value_ptr, binfo.llmatch);
-                }
-                else {
-                    Store(bcx, *value_ptr, binfo.llmatch);
-                }
-            }
-            match data.arm.guard {
-                Some(ref guard_expr) => {
-                    bcx = compile_guard(bcx,
-                                        &guard_expr,
-                                        m[0].data,
-                                        &m[1..m.len()],
-                                        vals,
-                                        chk,
-                                        has_genuine_default);
-                }
-                _ => ()
-            }
-            Br(bcx, data.bodycx.llbb, DebugLoc::None);
-        }
-    }
-}
-
-fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
-                                                 m: &[Match<'a, 'p, 'blk, 'tcx>],
-                                                 vals: &[MatchInput],
-                                                 chk: &FailureHandler,
-                                                 col: usize,
-                                                 val: MatchInput,
-                                                 has_genuine_default: bool) {
-    let fcx = bcx.fcx;
-    let tcx = bcx.tcx();
-
-    let mut vals_left = vals[0..col].to_vec();
-    vals_left.extend_from_slice(&vals[col + 1..]);
-    let ccx = bcx.fcx.ccx;
-
-    // Find a real id (we're adding placeholder wildcard patterns, but
-    // each column is guaranteed to have at least one real pattern)
-    let pat_id = m.iter().map(|br| br.pats[col].id)
-                         .find(|&id| id != DUMMY_NODE_ID)
-                         .unwrap_or(DUMMY_NODE_ID);
-
-    let left_ty = if pat_id == DUMMY_NODE_ID {
-        tcx.mk_nil()
-    } else {
-        node_id_type(bcx, pat_id)
-    };
-
-    let mcx = check_match::MatchCheckCtxt {
-        tcx: bcx.tcx(),
-        param_env: bcx.tcx().empty_parameter_environment(),
-    };
-    let adt_vals = if any_irrefutable_adt_pat(bcx.tcx(), m, col) {
-        let repr = adt::represent_type(bcx.ccx(), left_ty);
-        let arg_count = adt::num_args(&repr, Disr(0));
-        let (arg_count, struct_val) = if type_is_sized(bcx.tcx(), left_ty) {
-            (arg_count, val.val)
-        } else {
-            // For an unsized ADT (i.e. DST struct), we need to treat
-            // the last field specially: instead of simply passing a
-            // ValueRef pointing to that field, as with all the others,
-            // we skip it and instead construct a 'fat ptr' below.
-            (arg_count - 1, Load(bcx, expr::get_dataptr(bcx, val.val)))
-        };
-        let mut field_vals: Vec<ValueRef> = (0..arg_count).map(|ix|
-            // By definition, these are all sized
-            adt::trans_field_ptr(bcx, &repr, adt::MaybeSizedValue::sized(struct_val), Disr(0), ix)
-        ).collect();
-
-        match left_ty.sty {
-            ty::TyStruct(def, substs) if !type_is_sized(bcx.tcx(), left_ty) => {
-                // The last field is technically unsized but
-                // since we can only ever match that field behind
-                // a reference we construct a fat ptr here.
-                let unsized_ty = def.struct_variant().fields.last().map(|field| {
-                    monomorphize::field_ty(bcx.tcx(), substs, field)
-                }).unwrap();
-                let scratch = alloc_ty(bcx, unsized_ty, "__struct_field_fat_ptr");
-
-                let meta = Load(bcx, expr::get_meta(bcx, val.val));
-                let struct_val = adt::MaybeSizedValue::unsized_(struct_val, meta);
-
-                let data = adt::trans_field_ptr(bcx, &repr, struct_val, Disr(0), arg_count);
-                Store(bcx, data, expr::get_dataptr(bcx, scratch));
-                Store(bcx, meta, expr::get_meta(bcx, scratch));
-                field_vals.push(scratch);
-            }
-            _ => {}
-        }
-        Some(field_vals)
-    } else if any_uniq_pat(m, col) || any_region_pat(m, col) {
-        let ptr = if type_is_fat_ptr(bcx.tcx(), left_ty) {
-            val.val
-        } else {
-            Load(bcx, val.val)
-        };
-        Some(vec!(ptr))
-    } else {
-        match left_ty.sty {
-            ty::TyArray(_, n) => {
-                let args = extract_vec_elems(bcx, left_ty, n, 0, val);
-                Some(args.vals)
-            }
-            _ => None
-        }
-    };
-    match adt_vals {
-        Some(field_vals) => {
-            let pats = enter_match(bcx, m, col, val, |pats|
-                check_match::specialize(&mcx, pats,
-                                        &Constructor::Single, col,
-                                        field_vals.len())
-            );
-            let mut vals: Vec<_> = field_vals.into_iter()
-                .map(|v|MatchInput::from_val(v))
-                .collect();
-            vals.extend_from_slice(&vals_left);
-            compile_submatch(bcx, &pats, &vals, chk, has_genuine_default);
-            return;
-        }
-        _ => ()
-    }
-
-    // Decide what kind of branch we need
-    let opts = get_branches(bcx, m, col);
-    debug!("options={:?}", opts);
-    let mut kind = NoBranch;
-    let mut test_val = val.val;
-    debug!("test_val={:?}", Value(test_val));
-    if !opts.is_empty() {
-        match opts[0] {
-            ConstantValue(..) | ConstantRange(..) => {
-                test_val = load_if_immediate(bcx, val.val, left_ty);
-                kind = if left_ty.is_integral() {
-                    Switch
-                } else {
-                    Compare
-                };
-            }
-            Variant(_, ref repr, _, _) => {
-                let (the_kind, val_opt) = adt::trans_switch(bcx, &repr,
-                                                            val.val, true);
-                kind = the_kind;
-                if let Some(tval) = val_opt { test_val = tval; }
-            }
-            SliceLengthEqual(..) | SliceLengthGreaterOrEqual(..) => {
-                let (_, len) = tvec::get_base_and_len(bcx, val.val, left_ty);
-                test_val = len;
-                kind = Switch;
-            }
-        }
-    }
-    for o in &opts {
-        match *o {
-            ConstantRange(..) => { kind = Compare; break },
-            SliceLengthGreaterOrEqual(..) => { kind = CompareSliceLength; break },
-            _ => ()
-        }
-    }
-    let else_cx = match kind {
-        NoBranch | Single => bcx,
-        _ => bcx.fcx.new_temp_block("match_else")
-    };
-    let sw = if kind == Switch {
-        build::Switch(bcx, test_val, else_cx.llbb, opts.len())
-    } else {
-        C_int(ccx, 0) // Placeholder for when not using a switch
-    };
-
-    let defaults = enter_default(else_cx, m, col, val);
-    let exhaustive = chk.is_infallible() && defaults.is_empty();
-    let len = opts.len();
-
-    if exhaustive && kind == Switch {
-        build::Unreachable(else_cx);
-    }
-
-    // Compile subtrees for each option
-    for (i, opt) in opts.iter().enumerate() {
-        // In some cases of range and vector pattern matching, we need to
-        // override the failure case so that instead of failing, it proceeds
-        // to try more matching. branch_chk, then, is the proper failure case
-        // for the current conditional branch.
-        let mut branch_chk = None;
-        let mut opt_cx = else_cx;
-        let debug_loc = opt.debug_loc();
-
-        if kind == Switch || !exhaustive || i + 1 < len {
-            opt_cx = bcx.fcx.new_temp_block("match_case");
-            match kind {
-                Single => Br(bcx, opt_cx.llbb, debug_loc),
-                Switch => {
-                    match opt.trans(bcx) {
-                        SingleResult(r) => {
-                            AddCase(sw, r.val, opt_cx.llbb);
-                            bcx = r.bcx;
-                        }
-                        _ => {
-                            bug!(
-                                "in compile_submatch, expected \
-                                 opt.trans() to return a SingleResult")
-                        }
-                    }
-                }
-                Compare | CompareSliceLength => {
-                    let t = if kind == Compare {
-                        left_ty
-                    } else {
-                        tcx.types.usize // vector length
-                    };
-                    let Result { bcx: after_cx, val: matches } = {
-                        match opt.trans(bcx) {
-                            SingleResult(Result { bcx, val }) => {
-                                compare_values(bcx, test_val, val, t, debug_loc)
-                            }
-                            RangeResult(Result { val: vbegin, .. },
-                                        Result { bcx, val: vend }) => {
-                                let llge = compare_scalar_types(bcx, test_val, vbegin,
-                                                                t, hir::BiGe, debug_loc);
-                                let llle = compare_scalar_types(bcx, test_val, vend,
-                                                                t, hir::BiLe, debug_loc);
-                                Result::new(bcx, And(bcx, llge, llle, DebugLoc::None))
-                            }
-                            LowerBound(Result { bcx, val }) => {
-                                Result::new(bcx, compare_scalar_types(bcx, test_val,
-                                                                      val, t, hir::BiGe,
-                                                                      debug_loc))
-                            }
-                        }
-                    };
-                    bcx = fcx.new_temp_block("compare_next");
-
-                    // If none of the sub-cases match, and the current condition
-                    // is guarded or has multiple patterns, move on to the next
-                    // condition, if there is any, rather than falling back to
-                    // the default.
-                    let guarded = m[i].data.arm.guard.is_some();
-                    let multi_pats = m[i].pats.len() > 1;
-                    if i + 1 < len && (guarded || multi_pats || kind == CompareSliceLength) {
-                        branch_chk = Some(JumpToBasicBlock(bcx.llbb));
-                    }
-                    CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb, debug_loc);
-                }
-                _ => ()
-            }
-        } else if kind == Compare || kind == CompareSliceLength {
-            Br(bcx, else_cx.llbb, debug_loc);
-        }
-
-        let mut size = 0;
-        let mut unpacked = Vec::new();
-        match *opt {
-            Variant(disr_val, ref repr, _, _) => {
-                let ExtractedBlock {vals: argvals, bcx: new_bcx} =
-                    extract_variant_args(opt_cx, &repr, disr_val, val);
-                size = argvals.len();
-                unpacked = argvals;
-                opt_cx = new_bcx;
-            }
-            SliceLengthEqual(len, _) => {
-                let args = extract_vec_elems(opt_cx, left_ty, len, 0, val);
-                size = args.vals.len();
-                unpacked = args.vals.clone();
-                opt_cx = args.bcx;
-            }
-            SliceLengthGreaterOrEqual(before, after, _) => {
-                let args = extract_vec_elems(opt_cx, left_ty, before, after, val);
-                size = args.vals.len();
-                unpacked = args.vals.clone();
-                opt_cx = args.bcx;
-            }
-            ConstantValue(..) | ConstantRange(..) => ()
-        }
-        let opt_ms = enter_opt(opt_cx, pat_id, m, opt, col, size, val);
-        let mut opt_vals: Vec<_> = unpacked.into_iter()
-            .map(|v|MatchInput::from_val(v))
-            .collect();
-        opt_vals.extend_from_slice(&vals_left[..]);
-        compile_submatch(opt_cx,
-                         &opt_ms[..],
-                         &opt_vals[..],
-                         branch_chk.as_ref().unwrap_or(chk),
-                         has_genuine_default);
-    }
-
-    // Compile the fall-through case, if any
-    if !exhaustive && kind != Single {
-        if kind == Compare || kind == CompareSliceLength {
-            Br(bcx, else_cx.llbb, DebugLoc::None);
-        }
-        match chk {
-            // If there is only one default arm left, move on to the next
-            // condition explicitly rather than (eventually) falling back to
-            // the last default arm.
-            &JumpToBasicBlock(_) if defaults.len() == 1 && has_genuine_default => {
-                chk.handle_fail(else_cx);
-            }
-            _ => {
-                compile_submatch(else_cx,
-                                 &defaults[..],
-                                 &vals_left[..],
-                                 chk,
-                                 has_genuine_default);
-            }
-        }
-    }
-}
-
-pub fn trans_match<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                               match_expr: &hir::Expr,
-                               discr_expr: &hir::Expr,
-                               arms: &[hir::Arm],
-                               dest: Dest)
-                               -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("match::trans_match");
-    trans_match_inner(bcx, match_expr.id, discr_expr, arms, dest)
-}
-
-/// Checks whether the binding in `discr` is assigned to anywhere in the expression `body`
-fn is_discr_reassigned(bcx: Block, discr: &hir::Expr, body: &hir::Expr) -> bool {
-    let (vid, field) = match discr.node {
-        hir::ExprPath(..) => match bcx.tcx().expect_def(discr.id) {
-            Def::Local(_, vid) | Def::Upvar(_, vid, _, _) => (vid, None),
-            _ => return false
-        },
-        hir::ExprField(ref base, field) => {
-            let vid = match bcx.tcx().expect_def_or_none(base.id) {
-                Some(Def::Local(_, vid)) | Some(Def::Upvar(_, vid, _, _)) => vid,
-                _ => return false
-            };
-            (vid, Some(mc::NamedField(field.node)))
-        },
-        hir::ExprTupField(ref base, field) => {
-            let vid = match bcx.tcx().expect_def_or_none(base.id) {
-                Some(Def::Local(_, vid)) | Some(Def::Upvar(_, vid, _, _)) => vid,
-                _ => return false
-            };
-            (vid, Some(mc::PositionalField(field.node)))
-        },
-        _ => return false
-    };
-
-    let mut rc = ReassignmentChecker {
-        node: vid,
-        field: field,
-        reassigned: false
-    };
-    bcx.tcx().normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
-        let mut visitor = euv::ExprUseVisitor::new(&mut rc, &infcx);
-        visitor.walk_expr(body);
-    });
-    rc.reassigned
-}
-
-struct ReassignmentChecker {
-    node: ast::NodeId,
-    field: Option<mc::FieldName>,
-    reassigned: bool
-}
-
-// Determine if the expression we're matching on is reassigned to within
-// the body of the match's arm.
-// We only care for the `mutate` callback since this check only matters
-// for cases where the matched value is moved.
-impl<'tcx> euv::Delegate<'tcx> for ReassignmentChecker {
-    fn consume(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: euv::ConsumeMode) {}
-    fn matched_pat(&mut self, _: &hir::Pat, _: mc::cmt, _: euv::MatchMode) {}
-    fn consume_pat(&mut self, _: &hir::Pat, _: mc::cmt, _: euv::ConsumeMode) {}
-    fn borrow(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: ty::Region,
-              _: ty::BorrowKind, _: euv::LoanCause) {}
-    fn decl_without_init(&mut self, _: ast::NodeId, _: Span) {}
-
-    fn mutate(&mut self, _: ast::NodeId, _: Span, cmt: mc::cmt, _: euv::MutateMode) {
-        let cmt_id = |cmt: &mc::cmt| match cmt.cat {
-            Categorization::Upvar(mc::Upvar { id: ty::UpvarId { var_id: vid, ..}, ..}) |
-            Categorization::Local(vid) => Some(vid),
-            Categorization::Interior(ref base_cmt, mc::InteriorField(_)) => Some(base_cmt.id),
-            _ => None
-        };
-        match cmt.cat {
-            Categorization::Upvar(mc::Upvar { id: ty::UpvarId { var_id: vid, .. }, .. }) |
-            Categorization::Local(vid) => self.reassigned |= self.node == vid,
-            ref cat => {
-                let mut cat = cat;
-                while let &Categorization::Interior(ref base_cmt, mc::InteriorField(field)) = cat {
-                    if let Some(vid) = cmt_id(base_cmt) {
-                        if self.node == vid && (self.field.is_none() || self.field == Some(field)) {
-                            self.reassigned = true;
-                            return;
-                        }
-                    }
-                    cat = &base_cmt.cat;
-                }
-            }
-        }
-    }
-}
-
-fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &hir::Pat,
-                                   discr: &hir::Expr, body: &hir::Expr)
-                                   -> BindingsMap<'tcx> {
-    // Create the bindings map, which is a mapping from each binding name
-    // to an alloca() that will be the value for that local variable.
-    // Note that we use the names because each binding will have many ids
-    // from the various alternatives.
-    let ccx = bcx.ccx();
-    let reassigned = is_discr_reassigned(bcx, discr, body);
-    let mut bindings_map = FnvHashMap();
-    pat_bindings(&pat, |bm, p_id, span, path1| {
-        let name = path1.node;
-        let variable_ty = node_id_type(bcx, p_id);
-        let llvariable_ty = type_of::type_of(ccx, variable_ty);
-        let tcx = bcx.tcx();
-        let param_env = tcx.empty_parameter_environment();
-
-        let llmatch;
-        let trmode;
-        let moves_by_default = variable_ty.moves_by_default(tcx, &param_env, span);
-        match bm {
-            hir::BindByValue(_) if !moves_by_default || reassigned =>
-            {
-                llmatch = alloca(bcx, llvariable_ty.ptr_to(), "__llmatch");
-                let llcopy = alloca(bcx, llvariable_ty, &bcx.name(name));
-                trmode = if moves_by_default {
-                    TrByMoveIntoCopy(llcopy)
-                } else {
-                    TrByCopy(llcopy)
-                };
-            }
-            hir::BindByValue(_) => {
-                // in this case, the final type of the variable will be T,
-                // but during matching we need to store a *T as explained
-                // above
-                llmatch = alloca(bcx, llvariable_ty.ptr_to(), &bcx.name(name));
-                trmode = TrByMoveRef;
-            }
-            hir::BindByRef(_) => {
-                llmatch = alloca(bcx, llvariable_ty, &bcx.name(name));
-                trmode = TrByRef;
-            }
-        };
-        bindings_map.insert(name, BindingInfo {
-            llmatch: llmatch,
-            trmode: trmode,
-            id: p_id,
-            span: span,
-            ty: variable_ty
-        });
-    });
-    return bindings_map;
-}
-
-fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>,
-                                 match_id: ast::NodeId,
-                                 discr_expr: &hir::Expr,
-                                 arms: &[hir::Arm],
-                                 dest: Dest) -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("match::trans_match_inner");
-    let fcx = scope_cx.fcx;
-    let mut bcx = scope_cx;
-    let tcx = bcx.tcx();
-
-    let discr_datum = unpack_datum!(bcx, expr::trans_to_lvalue(bcx, discr_expr,
-                                                               "match"));
-    if bcx.unreachable.get() {
-        return bcx;
-    }
-
-    let t = node_id_type(bcx, discr_expr.id);
-    let chk = if t.is_uninhabited(tcx) {
-        Unreachable
-    } else {
-        Infallible
-    };
-
-    let arm_datas: Vec<ArmData> = arms.iter().map(|arm| ArmData {
-        bodycx: fcx.new_id_block("case_body", arm.body.id),
-        arm: arm,
-        bindings_map: create_bindings_map(bcx, &arm.pats[0], discr_expr, &arm.body)
-    }).collect();
-
-    let mut pat_renaming_map = if scope_cx.sess().opts.debuginfo != NoDebugInfo {
-        Some(FnvHashMap())
-    } else {
-        None
-    };
-
-    let arm_pats: Vec<Vec<P<hir::Pat>>> = {
-        let mut static_inliner = StaticInliner::new(scope_cx.tcx(),
-                                                    pat_renaming_map.as_mut());
-        arm_datas.iter().map(|arm_data| {
-            arm_data.arm.pats.iter().map(|p| static_inliner.fold_pat((*p).clone())).collect()
-        }).collect()
-    };
-
-    let mut matches = Vec::new();
-    for (arm_data, pats) in arm_datas.iter().zip(&arm_pats) {
-        matches.extend(pats.iter().map(|p| Match {
-            pats: vec![&p],
-            data: arm_data,
-            bound_ptrs: Vec::new(),
-            pat_renaming_map: pat_renaming_map.as_ref()
-        }));
-    }
-
-    // `compile_submatch` works one column of arm patterns a time and
-    // then peels that column off. So as we progress, it may become
-    // impossible to tell whether we have a genuine default arm, i.e.
-    // `_ => foo` or not. Sometimes it is important to know that in order
-    // to decide whether moving on to the next condition or falling back
-    // to the default arm.
-    let has_default = arms.last().map_or(false, |arm| {
-        arm.pats.len() == 1
-        && arm.pats.last().unwrap().node == PatKind::Wild
-    });
-
-    compile_submatch(bcx, &matches[..], &[discr_datum.match_input()], &chk, has_default);
-
-    let mut arm_cxs = Vec::new();
-    for arm_data in &arm_datas {
-        let mut bcx = arm_data.bodycx;
-
-        // insert bindings into the lllocals map and add cleanups
-        let cs = fcx.push_custom_cleanup_scope();
-        bcx = insert_lllocals(bcx, &arm_data.bindings_map, Some(cleanup::CustomScope(cs)));
-        bcx = expr::trans_into(bcx, &arm_data.arm.body, dest);
-        bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, cs);
-        arm_cxs.push(bcx);
-    }
-
-    bcx = scope_cx.fcx.join_blocks(match_id, &arm_cxs[..]);
-    return bcx;
-}
-
-/// Generates code for a local variable declaration like `let <pat>;` or `let <pat> =
-/// <opt_init_expr>`.
-pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                               local: &hir::Local)
-                               -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("match::store_local");
-    let mut bcx = bcx;
-    let tcx = bcx.tcx();
-    let pat = &local.pat;
-
-    fn create_dummy_locals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
-                                       pat: &hir::Pat)
-                                       -> Block<'blk, 'tcx> {
-        let _icx = push_ctxt("create_dummy_locals");
-        // create dummy memory for the variables if we have no
-        // value to store into them immediately
-        let tcx = bcx.tcx();
-        pat_bindings(pat, |_, p_id, _, path1| {
-            let scope = cleanup::var_scope(tcx, p_id);
-            bcx = mk_binding_alloca(
-                bcx, p_id, path1.node, scope, (),
-                "_match::store_local::create_dummy_locals",
-                |(), bcx, Datum { val: llval, ty, kind }| {
-                    // Dummy-locals start out uninitialized, so set their
-                    // drop-flag hints (if any) to "moved."
-                    if let Some(hint) = kind.dropflag_hint(bcx) {
-                        let moved_hint = adt::DTOR_MOVED_HINT;
-                        debug!("store moved_hint={} for hint={:?}, uninitialized dummy",
-                               moved_hint, hint);
-                        Store(bcx, C_u8(bcx.fcx.ccx, moved_hint), hint.to_value().value());
-                    }
-
-                    if kind.drop_flag_info.must_zero() {
-                        // if no drop-flag hint, or the hint requires
-                        // we maintain the embedded drop-flag, then
-                        // mark embedded drop-flag(s) as moved
-                        // (i.e. "already dropped").
-                        drop_done_fill_mem(bcx, llval, ty);
-                    }
-                    bcx
-                });
-        });
-        bcx
-    }
-
-    match local.init {
-        Some(ref init_expr) => {
-            // Optimize the "let x = expr" case. This just writes
-            // the result of evaluating `expr` directly into the alloca
-            // for `x`. Often the general path results in similar or the
-            // same code post-optimization, but not always. In particular,
-            // in unsafe code, you can have expressions like
-            //
-            //    let x = intrinsics::uninit();
-            //
-            // In such cases, the more general path is unsafe, because
-            // it assumes it is matching against a valid value.
-            if let Some(name) = simple_name(pat) {
-                let var_scope = cleanup::var_scope(tcx, local.id);
-                return mk_binding_alloca(
-                    bcx, pat.id, name, var_scope, (),
-                    "_match::store_local",
-                    |(), bcx, Datum { val: v, .. }| expr::trans_into(bcx, &init_expr,
-                                                                     expr::SaveIn(v)));
-            }
-
-            // General path.
-            let init_datum =
-                unpack_datum!(bcx, expr::trans_to_lvalue(bcx, &init_expr, "let"));
-            if bcx.sess().asm_comments() {
-                add_comment(bcx, "creating zeroable ref llval");
-            }
-            let var_scope = cleanup::var_scope(tcx, local.id);
-            bind_irrefutable_pat(bcx, pat, init_datum.match_input(), var_scope)
-        }
-        None => {
-            create_dummy_locals(bcx, pat)
-        }
-    }
-}
-
-fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
-                                       p_id: ast::NodeId,
-                                       name: ast::Name,
-                                       cleanup_scope: cleanup::ScopeId,
-                                       arg: A,
-                                       caller_name: &'static str,
-                                       populate: F)
-                                       -> Block<'blk, 'tcx> where
-    F: FnOnce(A, Block<'blk, 'tcx>, Datum<'tcx, Lvalue>) -> Block<'blk, 'tcx>,
-{
-    let var_ty = node_id_type(bcx, p_id);
-
-    // Allocate memory on stack for the binding.
-    let llval = alloc_ty(bcx, var_ty, &bcx.name(name));
-    let lvalue = Lvalue::new_with_hint(caller_name, bcx, p_id, HintKind::DontZeroJustUse);
-    let datum = Datum::new(llval, var_ty, lvalue);
-
-    debug!("mk_binding_alloca cleanup_scope={:?} llval={:?} var_ty={:?}",
-           cleanup_scope, Value(llval), var_ty);
-
-    // Subtle: be sure that we *populate* the memory *before*
-    // we schedule the cleanup.
-    call_lifetime_start(bcx, llval);
-    let bcx = populate(arg, bcx, datum);
-    bcx.fcx.schedule_lifetime_end(cleanup_scope, llval);
-    bcx.fcx.schedule_drop_mem(cleanup_scope, llval, var_ty, lvalue.dropflag_hint(bcx));
-
-    // Now that memory is initialized and has cleanup scheduled,
-    // insert datum into the local variable map.
-    bcx.fcx.lllocals.borrow_mut().insert(p_id, datum);
-    bcx
-}
-
-/// A simple version of the pattern matching code that only handles
-/// irrefutable patterns. This is used in let/argument patterns,
-/// not in match statements. Unifying this code with the code above
-/// sounds nice, but in practice it produces very inefficient code,
-/// since the match code is so much more general. In most cases,
-/// LLVM is able to optimize the code, but it causes longer compile
-/// times and makes the generated code nigh impossible to read.
-///
-/// # Arguments
-/// - bcx: starting basic block context
-/// - pat: the irrefutable pattern being matched.
-/// - val: the value being matched -- must be an lvalue (by ref, with cleanup)
-pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                    pat: &hir::Pat,
-                                    val: MatchInput,
-                                    cleanup_scope: cleanup::ScopeId)
-                                    -> Block<'blk, 'tcx> {
-    debug!("bind_irrefutable_pat(bcx={}, pat={:?}, val={:?})",
-           bcx.to_str(), pat, val);
-
-    if bcx.sess().asm_comments() {
-        add_comment(bcx, &format!("bind_irrefutable_pat(pat={:?})",
-                                 pat));
-    }
-
-    let _indenter = indenter();
-
-    let _icx = push_ctxt("match::bind_irrefutable_pat");
-    let mut bcx = bcx;
-    let tcx = bcx.tcx();
-    let ccx = bcx.ccx();
-    match pat.node {
-        PatKind::Binding(pat_binding_mode, ref path1, ref inner) => {
-            // Allocate the stack slot where the value of this
-            // binding will live and place it into the appropriate
-            // map.
-            bcx = mk_binding_alloca(bcx, pat.id, path1.node, cleanup_scope, (),
-                                    "_match::bind_irrefutable_pat",
-                                    |(), bcx, Datum { val: llval, ty, kind: _ }| {
-                match pat_binding_mode {
-                    hir::BindByValue(_) => {
-                        // By value binding: move the value that `val`
-                        // points at into the binding's stack slot.
-                        let d = val.to_datum(ty);
-                        d.store_to(bcx, llval)
-                    }
-
-                    hir::BindByRef(_) => {
-                        // By ref binding: the value of the variable
-                        // is the pointer `val` itself or fat pointer referenced by `val`
-                        if type_is_fat_ptr(bcx.tcx(), ty) {
-                            expr::copy_fat_ptr(bcx, val.val, llval);
-                        }
-                        else {
-                            Store(bcx, val.val, llval);
-                        }
-
-                        bcx
-                    }
-                }
-            });
-
-            if let Some(ref inner_pat) = *inner {
-                bcx = bind_irrefutable_pat(bcx, &inner_pat, val, cleanup_scope);
-            }
-        }
-        PatKind::TupleStruct(_, ref sub_pats, ddpos) => {
-            match bcx.tcx().expect_def(pat.id) {
-                Def::Variant(enum_id, var_id) => {
-                    let repr = adt::represent_node(bcx, pat.id);
-                    let vinfo = ccx.tcx().lookup_adt_def(enum_id).variant_with_id(var_id);
-                    let args = extract_variant_args(bcx,
-                                                    &repr,
-                                                    Disr::from(vinfo.disr_val),
-                                                    val);
-                    for (i, subpat) in sub_pats.iter()
-                                               .enumerate_and_adjust(vinfo.fields.len(), ddpos) {
-                        bcx = bind_irrefutable_pat(
-                            bcx,
-                            subpat,
-                            MatchInput::from_val(args.vals[i]),
-                            cleanup_scope);
-                    }
-                }
-                Def::Struct(..) => {
-                    let expected_len = match *ccx.tcx().pat_ty(&pat) {
-                        ty::TyS{sty: ty::TyStruct(adt_def, _), ..} => {
-                            adt_def.struct_variant().fields.len()
-                        }
-                        ref ty => {
-                            span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty);
-                        }
-                    };
-
-                    let repr = adt::represent_node(bcx, pat.id);
-                    let val = adt::MaybeSizedValue::sized(val.val);
-                    for (i, elem) in sub_pats.iter().enumerate_and_adjust(expected_len, ddpos) {
-                        let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), i);
-                        bcx = bind_irrefutable_pat(
-                            bcx,
-                            &elem,
-                            MatchInput::from_val(fldptr),
-                            cleanup_scope);
-                    }
-                }
-                _ => {
-                    // Nothing to do here.
-                }
-            }
-        }
-        PatKind::Struct(_, ref fields, _) => {
-            let tcx = bcx.tcx();
-            let pat_ty = node_id_type(bcx, pat.id);
-            let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
-            let pat_v = VariantInfo::of_node(tcx, pat_ty, pat.id);
-
-            let val = if type_is_sized(tcx, pat_ty) {
-                adt::MaybeSizedValue::sized(val.val)
-            } else {
-                let data = Load(bcx, expr::get_dataptr(bcx, val.val));
-                let meta = Load(bcx, expr::get_meta(bcx, val.val));
-                adt::MaybeSizedValue::unsized_(data, meta)
-            };
-
-            for f in fields {
-                let name = f.node.name;
-                let field_idx = pat_v.field_index(name);
-                let mut fldptr = adt::trans_field_ptr(
-                    bcx,
-                    &pat_repr,
-                    val,
-                    pat_v.discr,
-                    field_idx);
-
-                let fty = pat_v.fields[field_idx].1;
-                // If it's not sized, then construct a fat pointer instead of
-                // a regular one
-                if !type_is_sized(tcx, fty) {
-                    let scratch = alloc_ty(bcx, fty, "__struct_field_fat_ptr");
-                    debug!("Creating fat pointer {:?}", Value(scratch));
-                    Store(bcx, fldptr, expr::get_dataptr(bcx, scratch));
-                    Store(bcx, val.meta, expr::get_meta(bcx, scratch));
-                    fldptr = scratch;
-                }
-                bcx = bind_irrefutable_pat(bcx,
-                                           &f.node.pat,
-                                           MatchInput::from_val(fldptr),
-                                           cleanup_scope);
-            }
-        }
-        PatKind::Tuple(ref elems, ddpos) => {
-            match tcx.node_id_to_type(pat.id).sty {
-                ty::TyTuple(ref tys) => {
-                    let repr = adt::represent_node(bcx, pat.id);
-                    let val = adt::MaybeSizedValue::sized(val.val);
-                    for (i, elem) in elems.iter().enumerate_and_adjust(tys.len(), ddpos) {
-                        let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), i);
-                        bcx = bind_irrefutable_pat(
-                            bcx,
-                            &elem,
-                            MatchInput::from_val(fldptr),
-                            cleanup_scope);
-                    }
-                }
-                ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty),
-            }
-        }
-        PatKind::Box(ref inner) => {
-            let pat_ty = node_id_type(bcx, inner.id);
-            // Pass along DSTs as fat pointers.
-            let val = if type_is_fat_ptr(tcx, pat_ty) {
-                // We need to check for this, as the pattern could be binding
-                // a fat pointer by-value.
-                if let PatKind::Binding(hir::BindByRef(..),_,_) = inner.node {
-                    val.val
-                } else {
-                    Load(bcx, val.val)
-                }
-            } else if type_is_sized(tcx, pat_ty) {
-                Load(bcx, val.val)
-            } else {
-                val.val
-            };
-            bcx = bind_irrefutable_pat(
-                bcx, &inner, MatchInput::from_val(val), cleanup_scope);
-        }
-        PatKind::Ref(ref inner, _) => {
-            let pat_ty = node_id_type(bcx, inner.id);
-            // Pass along DSTs as fat pointers.
-            let val = if type_is_fat_ptr(tcx, pat_ty) {
-                // We need to check for this, as the pattern could be binding
-                // a fat pointer by-value.
-                if let PatKind::Binding(hir::BindByRef(..),_,_) = inner.node {
-                    val.val
-                } else {
-                    Load(bcx, val.val)
-                }
-            } else if type_is_sized(tcx, pat_ty) {
-                Load(bcx, val.val)
-            } else {
-                val.val
-            };
-            bcx = bind_irrefutable_pat(
-                bcx,
-                &inner,
-                MatchInput::from_val(val),
-                cleanup_scope);
-        }
-        PatKind::Vec(ref before, ref slice, ref after) => {
-            let pat_ty = node_id_type(bcx, pat.id);
-            let mut extracted = extract_vec_elems(bcx, pat_ty, before.len(), after.len(), val);
-            match slice {
-                &Some(_) => {
-                    extracted.vals.insert(
-                        before.len(),
-                        bind_subslice_pat(bcx, pat.id, val, before.len(), after.len())
-                    );
-                }
-                &None => ()
-            }
-            bcx = before
-                .iter()
-                .chain(slice.iter())
-                .chain(after.iter())
-                .zip(extracted.vals)
-                .fold(bcx, |bcx, (inner, elem)| {
-                    bind_irrefutable_pat(
-                        bcx,
-                        &inner,
-                        MatchInput::from_val(elem),
-                        cleanup_scope)
-                });
-        }
-        PatKind::Path(..) | PatKind::Wild |
-        PatKind::Lit(..) | PatKind::Range(..) => ()
-    }
-    return bcx;
-}
index 3a7fde6a36bad02e6629ef9c27ea297b148b2d0e..c2b040c32f6a364e20e4d154e791375142b0ae9c 100644 (file)
@@ -21,6 +21,7 @@
 use cabi_powerpc;
 use cabi_powerpc64;
 use cabi_mips;
+use cabi_mips64;
 use cabi_asmjs;
 use machine::{llalign_of_min, llsize_of, llsize_of_real, llsize_of_store};
 use type_::Type;
@@ -269,6 +270,7 @@ pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             Vectorcall => llvm::X86_VectorCall,
             C => llvm::CCallConv,
             Win64 => llvm::X86_64_Win64,
+            SysV64 => llvm::X86_64_SysV,
 
             // These API constants ought to be more specific...
             Cdecl => llvm::CCallConv,
@@ -483,7 +485,9 @@ pub fn adjust_for_abi<'a, 'tcx>(&mut self,
 
         match &ccx.sess().target.target.arch[..] {
             "x86" => cabi_x86::compute_abi_info(ccx, self),
-            "x86_64" => if ccx.sess().target.target.options.is_like_windows {
+            "x86_64" => if abi == Abi::SysV64 {
+                cabi_x86_64::compute_abi_info(ccx, self);
+            } else if abi == Abi::Win64 || ccx.sess().target.target.options.is_like_windows {
                 cabi_x86_win64::compute_abi_info(ccx, self);
             } else {
                 cabi_x86_64::compute_abi_info(ccx, self);
@@ -498,6 +502,7 @@ pub fn adjust_for_abi<'a, 'tcx>(&mut self,
                 cabi_arm::compute_abi_info(ccx, self, flavor);
             },
             "mips" => cabi_mips::compute_abi_info(ccx, self),
+            "mips64" => cabi_mips64::compute_abi_info(ccx, self),
             "powerpc" => cabi_powerpc::compute_abi_info(ccx, self),
             "powerpc64" => cabi_powerpc64::compute_abi_info(ccx, self),
             "asmjs" => cabi_asmjs::compute_abi_info(ccx, self),
index d48ec98a20dfb3d308a0cfa73507d9569d879269..2fb7a69d36186a45e45646112300e6cd690e1a88 100644 (file)
 use syntax::ast;
 use syntax::attr;
 use syntax::attr::IntType;
-use _match;
 use abi::FAT_PTR_ADDR;
-use base::InitAlloca;
 use build::*;
-use cleanup;
-use cleanup::CleanupMethods;
 use common::*;
-use datum;
 use debuginfo::DebugLoc;
 use glue;
 use machine;
 use type_of;
 use value::Value;
 
-type Hint = attr::ReprAttr;
-
-// Representation of the context surrounding an unsized type. I want
-// to be able to track the drop flags that are injected by trans.
-#[derive(Clone, Copy, PartialEq, Debug)]
-pub struct TypeContext {
-    prefix: Type,
-    needs_drop_flag: bool,
+#[derive(Copy, Clone, PartialEq)]
+pub enum BranchKind {
+    Switch,
+    Single
 }
 
-impl TypeContext {
-    pub fn prefix(&self) -> Type { self.prefix }
-    pub fn needs_drop_flag(&self) -> bool { self.needs_drop_flag }
-
-    fn direct(t: Type) -> TypeContext {
-        TypeContext { prefix: t, needs_drop_flag: false }
-    }
-    fn may_need_drop_flag(t: Type, needs_drop_flag: bool) -> TypeContext {
-        TypeContext { prefix: t, needs_drop_flag: needs_drop_flag }
-    }
-}
+type Hint = attr::ReprAttr;
 
 /// Representations.
 #[derive(Eq, PartialEq, Debug)]
@@ -97,22 +78,10 @@ pub enum Repr<'tcx> {
     /// C-like enums; basically an int.
     CEnum(IntType, Disr, Disr), // discriminant range (signedness based on the IntType)
     /// Single-case variants, and structs/tuples/records.
-    ///
-    /// Structs with destructors need a dynamic destroyedness flag to
-    /// avoid running the destructor too many times; this is included
-    /// in the `Struct` if present.
-    /// (The flag if nonzero, represents the initialization value to use;
-    ///  if zero, then use no flag at all.)
-    Univariant(Struct<'tcx>, u8),
+    Univariant(Struct<'tcx>),
     /// General-case enums: for each case there is a struct, and they
     /// all start with a field for the discriminant.
-    ///
-    /// Types with destructors need a dynamic destroyedness flag to
-    /// avoid running the destructor too many times; the last argument
-    /// indicates whether such a flag is present.
-    /// (The flag, if nonzero, represents the initialization value to use;
-    ///  if zero, then use no flag at all.)
-    General(IntType, Vec<Struct<'tcx>>, u8),
+    General(IntType, Vec<Struct<'tcx>>),
     /// Two cases distinguished by a nullable pointer: the case with discriminant
     /// `nndiscr` must have single field which is known to be nonnull due to its type.
     /// The other case is known to be zero sized. Hence we represent the enum
@@ -178,14 +147,6 @@ pub fn has_meta(&self) -> bool {
     }
 }
 
-/// Convenience for `represent_type`.  There should probably be more or
-/// these, for places in trans where the `Ty` isn't directly
-/// available.
-pub fn represent_node<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                  node: ast::NodeId) -> Rc<Repr<'tcx>> {
-    represent_type(bcx.ccx(), node_id_type(bcx, node))
-}
-
 /// Decides how to represent a given type.
 pub fn represent_type<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                 t: Ty<'tcx>)
@@ -201,91 +162,36 @@ pub fn represent_type<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     repr
 }
 
-const fn repeat_u8_as_u32(val: u8) -> u32 {
-    (val as u32) << 24 | (val as u32) << 16 | (val as u32) << 8 | val as u32
-}
-
-const fn repeat_u8_as_u64(val: u8) -> u64 {
-    (repeat_u8_as_u32(val) as u64) << 32 | repeat_u8_as_u32(val) as u64
-}
-
-/// `DTOR_NEEDED_HINT` is a stack-local hint that just means
-/// "we do not know whether the destructor has run or not; check the
-/// drop-flag embedded in the value itself."
-pub const DTOR_NEEDED_HINT: u8 = 0x3d;
-
-/// `DTOR_MOVED_HINT` is a stack-local hint that means "this value has
-/// definitely been moved; you do not need to run its destructor."
-///
-/// (However, for now, such values may still end up being explicitly
-/// zeroed by the generated code; this is the distinction between
-/// `datum::DropFlagInfo::ZeroAndMaintain` versus
-/// `datum::DropFlagInfo::DontZeroJustUse`.)
-pub const DTOR_MOVED_HINT: u8 = 0x2d;
-
-pub const DTOR_NEEDED: u8 = 0xd4;
-#[allow(dead_code)]
-pub const DTOR_NEEDED_U64: u64 = repeat_u8_as_u64(DTOR_NEEDED);
-
-pub const DTOR_DONE: u8 = 0x1d;
-#[allow(dead_code)]
-pub const DTOR_DONE_U64: u64 = repeat_u8_as_u64(DTOR_DONE);
-
-fn dtor_to_init_u8(dtor: bool) -> u8 {
-    if dtor { DTOR_NEEDED } else { 0 }
-}
-
-pub trait GetDtorType<'tcx> { fn dtor_type(self) -> Ty<'tcx>; }
-impl<'a, 'tcx> GetDtorType<'tcx> for TyCtxt<'a, 'tcx, 'tcx> {
-    fn dtor_type(self) -> Ty<'tcx> { self.types.u8 }
-}
-
-fn dtor_active(flag: u8) -> bool {
-    flag != 0
-}
-
 fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                      t: Ty<'tcx>) -> Repr<'tcx> {
     match t.sty {
         ty::TyTuple(ref elems) => {
-            Univariant(mk_struct(cx, &elems[..], false, t), 0)
+            Univariant(mk_struct(cx, &elems[..], false, t))
         }
         ty::TyStruct(def, substs) => {
-            let mut ftys = def.struct_variant().fields.iter().map(|field| {
+            let ftys = def.struct_variant().fields.iter().map(|field| {
                 monomorphize::field_ty(cx.tcx(), substs, field)
             }).collect::<Vec<_>>();
             let packed = cx.tcx().lookup_packed(def.did);
-            // FIXME(16758) don't add a drop flag to unsized structs, as it
-            // won't actually be in the location we say it is because it'll be after
-            // the unsized field. Several other pieces of code assume that the unsized
-            // field is definitely the last one.
-            let dtor = def.dtor_kind().has_drop_flag() && type_is_sized(cx.tcx(), t);
-            if dtor {
-                ftys.push(cx.tcx().dtor_type());
-            }
 
-            Univariant(mk_struct(cx, &ftys[..], packed, t), dtor_to_init_u8(dtor))
+            Univariant(mk_struct(cx, &ftys[..], packed, t))
         }
         ty::TyClosure(_, ref substs) => {
-            Univariant(mk_struct(cx, &substs.upvar_tys, false, t), 0)
+            Univariant(mk_struct(cx, &substs.upvar_tys, false, t))
         }
         ty::TyEnum(def, substs) => {
             let cases = get_cases(cx.tcx(), def, substs);
             let hint = *cx.tcx().lookup_repr_hints(def.did).get(0)
                 .unwrap_or(&attr::ReprAny);
 
-            let dtor = def.dtor_kind().has_drop_flag();
-
             if cases.is_empty() {
                 // Uninhabitable; represent as unit
                 // (Typechecking will reject discriminant-sizing attrs.)
                 assert_eq!(hint, attr::ReprAny);
-                let ftys = if dtor { vec!(cx.tcx().dtor_type()) } else { vec!() };
-                return Univariant(mk_struct(cx, &ftys[..], false, t),
-                                  dtor_to_init_u8(dtor));
+                return Univariant(mk_struct(cx, &[], false, t));
             }
 
-            if !dtor && cases.iter().all(|c| c.tys.is_empty()) {
+            if cases.iter().all(|c| c.tys.is_empty()) {
                 // All bodies empty -> intlike
                 let discrs: Vec<_> = cases.iter().map(|c| Disr::from(c.discr)).collect();
                 let bounds = IntBounds {
@@ -307,13 +213,10 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
             if cases.len() == 1 && hint == attr::ReprAny {
                 // Equivalent to a struct/tuple/newtype.
-                let mut ftys = cases[0].tys.clone();
-                if dtor { ftys.push(cx.tcx().dtor_type()); }
-                return Univariant(mk_struct(cx, &ftys[..], false, t),
-                                  dtor_to_init_u8(dtor));
+                return Univariant(mk_struct(cx, &cases[0].tys, false, t));
             }
 
-            if !dtor && cases.len() == 2 && hint == attr::ReprAny {
+            if cases.len() == 2 && hint == attr::ReprAny {
                 // Nullable pointer optimization
                 let mut discr = 0;
                 while discr < 2 {
@@ -356,7 +259,6 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let fields : Vec<_> = cases.iter().map(|c| {
                 let mut ftys = vec!(ty_of_inttype(cx.tcx(), min_ity));
                 ftys.extend_from_slice(&c.tys);
-                if dtor { ftys.push(cx.tcx().dtor_type()); }
                 mk_struct(cx, &ftys, false, t)
             }).collect();
 
@@ -418,13 +320,12 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let fields : Vec<_> = cases.iter().map(|c| {
                 let mut ftys = vec!(ty_of_inttype(cx.tcx(), ity));
                 ftys.extend_from_slice(&c.tys);
-                if dtor { ftys.push(cx.tcx().dtor_type()); }
                 mk_struct(cx, &ftys[..], false, t)
             }).collect();
 
             ensure_enum_fits_in_address_space(cx, &fields[..], t);
 
-            General(ity, fields, dtor_to_init_u8(dtor))
+            General(ity, fields)
         }
         _ => bug!("adt::represent_type called on non-ADT type: {}", t)
     }
@@ -722,9 +623,7 @@ fn ensure_enum_fits_in_address_space<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 /// and fill in the actual contents in a second pass to prevent
 /// unbounded recursion; see also the comments in `trans::type_of`.
 pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>) -> Type {
-    let c = generic_type_of(cx, r, None, false, false, false);
-    assert!(!c.needs_drop_flag);
-    c.prefix
+    generic_type_of(cx, r, None, false, false)
 }
 
 
@@ -733,25 +632,19 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>) -> Type {
 // are going to get the wrong type (it will not include the unsized parts of it).
 pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                 r: &Repr<'tcx>, dst: bool) -> Type {
-    let c = generic_type_of(cx, r, None, true, dst, false);
-    assert!(!c.needs_drop_flag);
-    c.prefix
-}
-pub fn sizing_type_context_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                                        r: &Repr<'tcx>, dst: bool) -> TypeContext {
-    generic_type_of(cx, r, None, true, dst, true)
+    generic_type_of(cx, r, None, true, dst)
 }
+
 pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                     r: &Repr<'tcx>, name: &str) -> Type {
-    let c = generic_type_of(cx, r, Some(name), false, false, false);
-    assert!(!c.needs_drop_flag);
-    c.prefix
+    generic_type_of(cx, r, Some(name), false, false)
 }
+
 pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                 r: &Repr<'tcx>, llty: &mut Type) {
     match *r {
         CEnum(..) | General(..) | RawNullablePointer { .. } => { }
-        Univariant(ref st, _) | StructWrappedNullablePointer { nonnull: ref st, .. } =>
+        Univariant(ref st) | StructWrappedNullablePointer { nonnull: ref st, .. } =>
             llty.set_struct_body(&struct_llfields(cx, st, false, false),
                                  st.packed)
     }
@@ -761,50 +654,40 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                              r: &Repr<'tcx>,
                              name: Option<&str>,
                              sizing: bool,
-                             dst: bool,
-                             delay_drop_flag: bool) -> TypeContext {
-    debug!("adt::generic_type_of r: {:?} name: {:?} sizing: {} dst: {} delay_drop_flag: {}",
-           r, name, sizing, dst, delay_drop_flag);
+                             dst: bool) -> Type {
+    debug!("adt::generic_type_of r: {:?} name: {:?} sizing: {} dst: {}",
+           r, name, sizing, dst);
     match *r {
-        CEnum(ity, _, _) => TypeContext::direct(ll_inttype(cx, ity)),
+        CEnum(ity, _, _) => ll_inttype(cx, ity),
         RawNullablePointer { nnty, .. } =>
-            TypeContext::direct(type_of::sizing_type_of(cx, nnty)),
+            type_of::sizing_type_of(cx, nnty),
         StructWrappedNullablePointer { nonnull: ref st, .. } => {
             match name {
                 None => {
-                    TypeContext::direct(
-                        Type::struct_(cx, &struct_llfields(cx, st, sizing, dst),
-                                      st.packed))
+                    Type::struct_(cx, &struct_llfields(cx, st, sizing, dst),
+                                  st.packed)
                 }
                 Some(name) => {
                     assert_eq!(sizing, false);
-                    TypeContext::direct(Type::named_struct(cx, name))
+                    Type::named_struct(cx, name)
                 }
             }
         }
-        Univariant(ref st, dtor_needed) => {
-            let dtor_needed = dtor_needed != 0;
+        Univariant(ref st) => {
             match name {
                 None => {
-                    let mut fields = struct_llfields(cx, st, sizing, dst);
-                    if delay_drop_flag && dtor_needed {
-                        fields.pop();
-                    }
-                    TypeContext::may_need_drop_flag(
-                        Type::struct_(cx, &fields,
-                                      st.packed),
-                        delay_drop_flag && dtor_needed)
+                    let fields = struct_llfields(cx, st, sizing, dst);
+                    Type::struct_(cx, &fields, st.packed)
                 }
                 Some(name) => {
                     // Hypothesis: named_struct's can never need a
                     // drop flag. (... needs validation.)
                     assert_eq!(sizing, false);
-                    TypeContext::direct(Type::named_struct(cx, name))
+                    Type::named_struct(cx, name)
                 }
             }
         }
-        General(ity, ref sts, dtor_needed) => {
-            let dtor_needed = dtor_needed != 0;
+        General(ity, ref sts) => {
             // We need a representation that has:
             // * The alignment of the most-aligned field
             // * The size of the largest variant (rounded up to that alignment)
@@ -836,25 +719,18 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             };
             assert_eq!(machine::llalign_of_min(cx, fill_ty), align);
             assert_eq!(padded_discr_size % discr_size, 0); // Ensure discr_ty can fill pad evenly
-            let mut fields: Vec<Type> =
+            let fields: Vec<Type> =
                 [discr_ty,
                  Type::array(&discr_ty, (padded_discr_size - discr_size)/discr_size),
                  fill_ty].iter().cloned().collect();
-            if delay_drop_flag && dtor_needed {
-                fields.pop();
-            }
             match name {
                 None => {
-                    TypeContext::may_need_drop_flag(
-                        Type::struct_(cx, &fields[..], false),
-                        delay_drop_flag && dtor_needed)
+                    Type::struct_(cx, &fields[..], false)
                 }
                 Some(name) => {
                     let mut llty = Type::named_struct(cx, name);
                     llty.set_struct_body(&fields[..], false);
-                    TypeContext::may_need_drop_flag(
-                        llty,
-                        delay_drop_flag && dtor_needed)
+                    llty
                 }
             }
         }
@@ -873,22 +749,19 @@ fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, st: &Struct<'tcx>,
 
 /// Obtain a representation of the discriminant sufficient to translate
 /// destructuring; this may or may not involve the actual discriminant.
-///
-/// This should ideally be less tightly tied to `_match`.
 pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                 r: &Repr<'tcx>,
                                 scrutinee: ValueRef,
                                 range_assert: bool)
-                                -> (_match::BranchKind, Option<ValueRef>) {
+                                -> (BranchKind, Option<ValueRef>) {
     match *r {
         CEnum(..) | General(..) |
         RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
-            (_match::Switch, Some(trans_get_discr(bcx, r, scrutinee, None,
-                                                  range_assert)))
+            (BranchKind::Switch, Some(trans_get_discr(bcx, r, scrutinee, None, range_assert)))
         }
         Univariant(..) => {
             // N.B.: Univariant means <= 1 enum variants (*not* == 1 variants).
-            (_match::Single, None)
+            (BranchKind::Single, None)
         }
     }
 }
@@ -896,7 +769,7 @@ pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool {
     match *r {
         CEnum(ity, _, _) => ity.is_signed(),
-        General(ity, _, _) => ity.is_signed(),
+        General(ity, _) => ity.is_signed(),
         Univariant(..) => false,
         RawNullablePointer { .. } => false,
         StructWrappedNullablePointer { .. } => false,
@@ -913,7 +786,7 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
         CEnum(ity, min, max) => {
             load_discr(bcx, ity, scrutinee, min, max, range_assert)
         }
-        General(ity, ref cases, _) => {
+        General(ity, ref cases) => {
             let ptr = StructGEP(bcx, scrutinee, 0);
             load_discr(bcx, ity, ptr, Disr(0), Disr(cases.len() as u64 - 1),
                        range_assert)
@@ -977,7 +850,7 @@ pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr)
         CEnum(ity, _, _) => {
             C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true)
         }
-        General(ity, _, _) => {
+        General(ity, _) => {
             C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true)
         }
         Univariant(..) => {
@@ -1001,21 +874,12 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
             Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true),
                   val);
         }
-        General(ity, ref cases, dtor) => {
-            if dtor_active(dtor) {
-                let ptr = trans_field_ptr(bcx, r, MaybeSizedValue::sized(val), discr,
-                                          cases[discr.0 as usize].fields.len() - 2);
-                Store(bcx, C_u8(bcx.ccx(), DTOR_NEEDED), ptr);
-            }
+        General(ity, _) => {
             Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true),
                   StructGEP(bcx, val, 0));
         }
-        Univariant(ref st, dtor) => {
+        Univariant(_) => {
             assert_eq!(discr, Disr(0));
-            if dtor_active(dtor) {
-                Store(bcx, C_u8(bcx.ccx(), DTOR_NEEDED),
-                      StructGEP(bcx, val, st.fields.len() - 1));
-            }
         }
         RawNullablePointer { nndiscr, nnty, ..} => {
             if discr != nndiscr {
@@ -1046,28 +910,6 @@ fn assert_discr_in_range(ity: IntType, min: Disr, max: Disr, discr: Disr) {
     }
 }
 
-/// The number of fields in a given case; for use when obtaining this
-/// information from the type or definition is less convenient.
-pub fn num_args(r: &Repr, discr: Disr) -> usize {
-    match *r {
-        CEnum(..) => 0,
-        Univariant(ref st, dtor) => {
-            assert_eq!(discr, Disr(0));
-            st.fields.len() - (if dtor_active(dtor) { 1 } else { 0 })
-        }
-        General(_, ref cases, dtor) => {
-            cases[discr.0 as usize].fields.len() - 1 - (if dtor_active(dtor) { 1 } else { 0 })
-        }
-        RawNullablePointer { nndiscr, ref nullfields, .. } => {
-            if discr == nndiscr { 1 } else { nullfields.len() }
-        }
-        StructWrappedNullablePointer { ref nonnull, nndiscr,
-                                       ref nullfields, .. } => {
-            if discr == nndiscr { nonnull.fields.len() } else { nullfields.len() }
-        }
-    }
-}
-
 /// Access a field, at a point when the value's case is known.
 pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
                                    val: MaybeSizedValue, discr: Disr, ix: usize) -> ValueRef {
@@ -1087,11 +929,11 @@ pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
         CEnum(..) => {
             bug!("element access in C-like enum")
         }
-        Univariant(ref st, _dtor) => {
+        Univariant(ref st) => {
             assert_eq!(discr, Disr(0));
             struct_field_ptr(bcx, st, val, ix, false)
         }
-        General(_, ref cases, _) => {
+        General(_, ref cases) => {
             struct_field_ptr(bcx, &cases[discr.0 as usize], val, ix + 1, true)
         }
         RawNullablePointer { nndiscr, ref nullfields, .. } |
@@ -1218,108 +1060,6 @@ fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
     bcx.pointercast(byte_ptr, ll_fty.ptr_to())
 }
 
-pub fn fold_variants<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
-                                    r: &Repr<'tcx>,
-                                    value: ValueRef,
-                                    mut f: F)
-                                    -> Block<'blk, 'tcx> where
-    F: FnMut(Block<'blk, 'tcx>, &Struct<'tcx>, ValueRef) -> Block<'blk, 'tcx>,
-{
-    let fcx = bcx.fcx;
-    match *r {
-        Univariant(ref st, _) => {
-            f(bcx, st, value)
-        }
-        General(ity, ref cases, _) => {
-            let ccx = bcx.ccx();
-
-            // See the comments in trans/base.rs for more information (inside
-            // iter_structural_ty), but the gist here is that if the enum's
-            // discriminant is *not* in the range that we're expecting (in which
-            // case we'll take the fall-through branch on the switch
-            // instruction) then we can't just optimize this to an Unreachable
-            // block.
-            //
-            // Currently we still have filling drop, so this means that the drop
-            // glue for enums may be called when the enum has been paved over
-            // with the "I've been dropped" value. In this case the default
-            // branch of the switch instruction will actually be taken at
-            // runtime, so the basic block isn't actually unreachable, so we
-            // need to make it do something with defined behavior. In this case
-            // we just return early from the function.
-            //
-            // Note that this is also why the `trans_get_discr` below has
-            // `false` to indicate that loading the discriminant should
-            // not have a range assert.
-            let ret_void_cx = fcx.new_temp_block("enum-variant-iter-ret-void");
-            RetVoid(ret_void_cx, DebugLoc::None);
-
-            let discr_val = trans_get_discr(bcx, r, value, None, false);
-            let llswitch = Switch(bcx, discr_val, ret_void_cx.llbb, cases.len());
-            let bcx_next = fcx.new_temp_block("enum-variant-iter-next");
-
-            for (discr, case) in cases.iter().enumerate() {
-                let mut variant_cx = fcx.new_temp_block(
-                    &format!("enum-variant-iter-{}", &discr.to_string())
-                );
-                let rhs_val = C_integral(ll_inttype(ccx, ity), discr as u64, true);
-                AddCase(llswitch, rhs_val, variant_cx.llbb);
-
-                let fields = case.fields.iter().map(|&ty|
-                    type_of::type_of(bcx.ccx(), ty)).collect::<Vec<_>>();
-                let real_ty = Type::struct_(ccx, &fields[..], case.packed);
-                let variant_value = PointerCast(variant_cx, value, real_ty.ptr_to());
-
-                variant_cx = f(variant_cx, case, variant_value);
-                Br(variant_cx, bcx_next.llbb, DebugLoc::None);
-            }
-
-            bcx_next
-        }
-        _ => bug!()
-    }
-}
-
-/// Access the struct drop flag, if present.
-pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
-                                       r: &Repr<'tcx>,
-                                       val: ValueRef)
-                                       -> datum::DatumBlock<'blk, 'tcx, datum::Expr>
-{
-    let tcx = bcx.tcx();
-    let ptr_ty = bcx.tcx().mk_imm_ptr(tcx.dtor_type());
-    match *r {
-        Univariant(ref st, dtor) if dtor_active(dtor) => {
-            let flag_ptr = StructGEP(bcx, val, st.fields.len() - 1);
-            datum::immediate_rvalue_bcx(bcx, flag_ptr, ptr_ty).to_expr_datumblock()
-        }
-        General(_, _, dtor) if dtor_active(dtor) => {
-            let fcx = bcx.fcx;
-            let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
-            let scratch = unpack_datum!(bcx, datum::lvalue_scratch_datum(
-                bcx, tcx.dtor_type(), "drop_flag",
-                InitAlloca::Uninit("drop flag itself has no dtor"),
-                cleanup::CustomScope(custom_cleanup_scope), |bcx, _| {
-                    debug!("no-op populate call for trans_drop_flag_ptr on dtor_type={:?}",
-                           tcx.dtor_type());
-                    bcx
-                }
-            ));
-            bcx = fold_variants(bcx, r, val, |variant_cx, st, value| {
-                let ptr = struct_field_ptr(&variant_cx.build(), st,
-                                           MaybeSizedValue::sized(value),
-                                           (st.fields.len() - 1), false);
-                datum::Datum::new(ptr, ptr_ty, datum::Lvalue::new("adt::trans_drop_flag_ptr"))
-                    .store_to(variant_cx, scratch.val)
-            });
-            let expr_datum = scratch.to_expr_datum();
-            fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
-            datum::DatumBlock::new(bcx, expr_datum)
-        }
-        _ => bug!("tried to get drop flag of non-droppable type")
-    }
-}
-
 /// Construct a constant value, suitable for initializing a
 /// GlobalVariable, given a case and constant values for its fields.
 /// Note that this may have a different LLVM type (and different
@@ -1347,7 +1087,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr
             assert_discr_in_range(ity, min, max, discr);
             C_integral(ll_inttype(ccx, ity), discr.0, true)
         }
-        General(ity, ref cases, _) => {
+        General(ity, ref cases) => {
             let case = &cases[discr.0 as usize];
             let (max_sz, _) = union_size_and_align(&cases[..]);
             let lldiscr = C_integral(ll_inttype(ccx, ity), discr.0 as u64, true);
@@ -1357,7 +1097,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr
             contents.extend_from_slice(&[padding(ccx, max_sz - case.size)]);
             C_struct(ccx, &contents[..], false)
         }
-        Univariant(ref st, _dro) => {
+        Univariant(ref st) => {
             assert_eq!(discr, Disr(0));
             let contents = build_const_struct(ccx, st, vals);
             C_struct(ccx, &contents[..], st.packed)
@@ -1458,28 +1198,6 @@ fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
 #[inline]
 fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a }
 
-/// Get the discriminant of a constant value.
-pub fn const_get_discrim(r: &Repr, val: ValueRef) -> Disr {
-    match *r {
-        CEnum(ity, _, _) => {
-            match ity {
-                attr::SignedInt(..) => Disr(const_to_int(val) as u64),
-                attr::UnsignedInt(..) => Disr(const_to_uint(val)),
-            }
-        }
-        General(ity, _, _) => {
-            match ity {
-                attr::SignedInt(..) => Disr(const_to_int(const_get_elt(val, &[0])) as u64),
-                attr::UnsignedInt(..) => Disr(const_to_uint(const_get_elt(val, &[0])))
-            }
-        }
-        Univariant(..) => Disr(0),
-        RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
-            bug!("const discrim access of non c-like enum")
-        }
-    }
-}
-
 /// Extract a field of a constant value, as appropriate for its
 /// representation.
 ///
index 5514fb0f4efc37b067b21439af683cf9d6a8f754..308118b1fbc6cda9e718c08eedee0099e269c0f3 100644 (file)
 use base;
 use build::*;
 use common::*;
-use datum::{Datum, Lvalue};
 use type_of;
 use type_::Type;
 
-use rustc::hir as ast;
+use rustc::hir;
+use rustc::ty::Ty;
+
 use std::ffi::CString;
 use syntax::ast::AsmDialect;
 use libc::{c_uint, c_char};
 
 // Take an inline assembly expression and splat it out via LLVM
 pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                    ia: &ast::InlineAsm,
-                                    outputs: Vec<Datum<'tcx, Lvalue>>,
+                                    ia: &hir::InlineAsm,
+                                    outputs: Vec<(ValueRef, Ty<'tcx>)>,
                                     mut inputs: Vec<ValueRef>) {
     let mut ext_constraints = vec![];
     let mut output_types = vec![];
 
     // Prepare the output operands
     let mut indirect_outputs = vec![];
-    for (i, (out, out_datum)) in ia.outputs.iter().zip(&outputs).enumerate() {
+    for (i, (out, &(val, ty))) in ia.outputs.iter().zip(&outputs).enumerate() {
         let val = if out.is_rw || out.is_indirect {
-            Some(base::load_ty(bcx, out_datum.val, out_datum.ty))
+            Some(base::load_ty(bcx, val, ty))
         } else {
             None
         };
@@ -46,7 +47,7 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         if out.is_indirect {
             indirect_outputs.push(val.unwrap());
         } else {
-            output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty));
+            output_types.push(type_of::type_of(bcx.ccx(), ty));
         }
     }
     if !indirect_outputs.is_empty() {
@@ -100,9 +101,9 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     // Again, based on how many outputs we have
     let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect);
-    for (i, (_, datum)) in outputs.enumerate() {
+    for (i, (_, &(val, _))) in outputs.enumerate() {
         let v = if num_outputs == 1 { r } else { ExtractValue(bcx, r, i) };
-        Store(bcx, v, datum.val);
+        Store(bcx, v, val);
     }
 
     // Store expn_id in a metadata node so we can map LLVM errors
index e0532e7476f511545d0bf7ac2ae98ac307d4548c..7fe6d2bbfe24eeb640555c2f2d81cc6862ddcd13 100644 (file)
@@ -29,7 +29,6 @@
 
 use rustc::ty::TyCtxt;
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax::parse::token::InternedString;
 
 use {ModuleSource, ModuleTranslation};
index 68a176a378172eef8251ba9c1365b83520241f03..b21785c27dae5e50967ec55912ece1c227af1118 100644 (file)
 use util::common::time;
 use util::fs::fix_windows_verbatim_for_gcc;
 use rustc::dep_graph::DepNode;
-use rustc::ty::TyCtxt;
+use rustc::hir::svh::Svh;
 use rustc_back::tempdir::TempDir;
+use rustc_incremental::IncrementalHashesMap;
 
-use rustc_incremental::SvhCalculate;
 use std::ascii;
 use std::char;
 use std::env;
@@ -42,7 +42,6 @@
 use std::str;
 use flate;
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax_pos::Span;
 
 // RLIB LLVM-BYTECODE OBJECT LAYOUT
@@ -125,12 +124,12 @@ pub fn find_crate_name(sess: Option<&Session>,
 
 }
 
-pub fn build_link_meta<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 name: &str)
-                                 -> LinkMeta {
+pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap,
+                       name: &str)
+                       -> LinkMeta {
     let r = LinkMeta {
         crate_name: name.to_owned(),
-        crate_hash: tcx.calculate_krate_hash(),
+        crate_hash: Svh::new(incremental_hashes_map[&DepNode::Krate]),
     };
     info!("{:?}", r);
     return r;
index cb990ead8e81e94ae0de9f5982d8817517e2e9d6..f2d5b128d270533ed9ebea7ccf17788d29e367a0 100644 (file)
@@ -247,29 +247,49 @@ fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
             return
         }
 
+        let mut arg = OsString::new();
         let path = tmpdir.join("list");
-        let prefix = if self.sess.target.target.options.is_like_osx {
-            "_"
-        } else {
-            ""
-        };
-        let res = (|| -> io::Result<()> {
-            let mut f = BufWriter::new(File::create(&path)?);
-            for sym in &self.info.cdylib_exports {
-                writeln!(f, "{}{}", prefix, sym)?;
+
+        if self.sess.target.target.options.is_like_solaris {
+            let res = (|| -> io::Result<()> {
+                let mut f = BufWriter::new(File::create(&path)?);
+                writeln!(f, "{{\n  global:")?;
+                for sym in &self.info.cdylib_exports {
+                    writeln!(f, "    {};", sym)?;
+                }
+                writeln!(f, "\n  local:\n    *;\n}};")?;
+                Ok(())
+            })();
+            if let Err(e) = res {
+                self.sess.fatal(&format!("failed to write version script: {}", e));
             }
-            Ok(())
-        })();
-        if let Err(e) = res {
-            self.sess.fatal(&format!("failed to write lib.def file: {}", e));
-        }
-        let mut arg = OsString::new();
-        if self.sess.target.target.options.is_like_osx {
-            arg.push("-Wl,-exported_symbols_list,");
+
+            arg.push("-Wl,-M,");
+            arg.push(&path);
         } else {
-            arg.push("-Wl,--retain-symbols-file=");
+            let prefix = if self.sess.target.target.options.is_like_osx {
+                "_"
+            } else {
+                ""
+            };
+            let res = (|| -> io::Result<()> {
+                let mut f = BufWriter::new(File::create(&path)?);
+                for sym in &self.info.cdylib_exports {
+                    writeln!(f, "{}{}", prefix, sym)?;
+                }
+                Ok(())
+            })();
+            if let Err(e) = res {
+                self.sess.fatal(&format!("failed to write lib.def file: {}", e));
+            }
+            if self.sess.target.target.options.is_like_osx {
+                arg.push("-Wl,-exported_symbols_list,");
+            } else {
+                arg.push("-Wl,--retain-symbols-file=");
+            }
+            arg.push(&path);
         }
-        arg.push(&path);
+
         self.cmd.arg(arg);
     }
 }
index 25a1479c289488c43af1001a3b26db4556300efa..9b02cbe6721f34e6dd3118250373c1345240fa02 100644 (file)
 use rustc::middle::{cstore, weak_lang_items};
 use rustc::hir::def_id::DefId;
 use rustc::hir::map as hir_map;
-use rustc::ty::{self, TyCtxt, TypeFoldable};
+use rustc::ty::{Ty, TyCtxt, TypeFoldable};
 use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
+use rustc::ty::subst::Substs;
 use rustc::hir::map::definitions::{DefPath, DefPathData};
 
 use syntax::attr;
@@ -126,14 +127,14 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                              // parameters substituted; this is
                              // included in the hash as a kind of
                              // safeguard.
-                             item_type: ty::Ty<'tcx>,
+                             item_type: Ty<'tcx>,
 
                              // values for generic type parameters,
                              // if any.
-                             parameters: &[ty::Ty<'tcx>])
+                             substs: Option<&Substs<'tcx>>)
                              -> String {
     debug!("get_symbol_hash(def_path={:?}, parameters={:?})",
-           def_path, parameters);
+           def_path, substs);
 
     let tcx = scx.tcx();
 
@@ -154,11 +155,13 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
     hash_state.input(&encoded_item_type[..]);
 
     // also include any type parameters (for generic items)
-    for t in parameters {
-       assert!(!t.has_erasable_regions());
-       assert!(!t.needs_subst());
-       let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string);
-       hash_state.input(&encoded_type[..]);
+    if let Some(substs) = substs {
+        for t in substs.types() {
+            assert!(!t.has_erasable_regions());
+            assert!(!t.needs_subst());
+            let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string);
+            hash_state.input(&encoded_type[..]);
+        }
     }
 
     return format!("h{}", truncated_hash_result(&mut *hash_state));
@@ -252,7 +255,7 @@ pub fn symbol_name(self, scx: &SharedCrateContext<'a, 'tcx>) -> String {
         // and should not matter anyhow.
         let instance_ty = scx.tcx().erase_regions(&instance_ty.ty);
 
-        let hash = get_symbol_hash(scx, &def_path, instance_ty, &substs.types);
+        let hash = get_symbol_hash(scx, &def_path, instance_ty, Some(substs));
 
         let mut buffer = SymbolPathBuffer {
             names: Vec::with_capacity(def_path.data.len())
@@ -282,14 +285,14 @@ fn push(&mut self, text: &str) {
 }
 
 pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
-                                                    t: ty::Ty<'tcx>,
+                                                    t: Ty<'tcx>,
                                                     prefix: &str)
                                                     -> String {
     let empty_def_path = DefPath {
         data: vec![],
         krate: cstore::LOCAL_CRATE,
     };
-    let hash = get_symbol_hash(scx, &empty_def_path, t, &[]);
+    let hash = get_symbol_hash(scx, &empty_def_path, t, None);
     let path = [token::intern_and_get_ident(prefix)];
     mangle(path.iter().cloned(), Some(&hash[..]))
 }
@@ -297,7 +300,7 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a,
 /// Only symbols that are invisible outside their compilation unit should use a
 /// name generated by this function.
 pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                                    t: ty::Ty<'tcx>,
+                                                    t: Ty<'tcx>,
                                                     suffix: &str)
                                                     -> String {
     let path = [token::intern(&t.to_string()).as_str(),
@@ -306,7 +309,7 @@ pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>
         data: vec![],
         krate: cstore::LOCAL_CRATE,
     };
-    let hash = get_symbol_hash(ccx.shared(), &def_path, t, &[]);
+    let hash = get_symbol_hash(ccx.shared(), &def_path, t, None);
     mangle(path.iter().cloned(), Some(&hash[..]))
 }
 
index 4b9c29d3d7db3a57b4f17063464315143175d6fb..081b4431bd7b80dfe6b9df5e7de7627705df30ea 100644 (file)
@@ -10,7 +10,7 @@
 
 use back::lto;
 use back::link::{get_linker, remove};
-use rustc_incremental::save_trans_partition;
+use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
 use session::config::{OutputFilenames, OutputTypes, Passes, SomePasses, AllPasses};
 use session::Session;
 use session::config::{self, OutputType};
@@ -328,8 +328,9 @@ struct CodegenContext<'a> {
     remark: Passes,
     // Worker thread number
     worker: usize,
-    // Directory where incremental data is stored (if any)
-    incremental: Option<PathBuf>,
+    // The incremental compilation session directory, or None if we are not
+    // compiling incrementally
+    incr_comp_session_dir: Option<PathBuf>
 }
 
 impl<'a> CodegenContext<'a> {
@@ -340,7 +341,7 @@ fn new_with_session(sess: &'a Session, reachable: &'a [String]) -> CodegenContex
             plugin_passes: sess.plugin_llvm_passes.borrow().clone(),
             remark: sess.opts.cg.remark.clone(),
             worker: 0,
-            incremental: sess.opts.incremental.clone(),
+            incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone())
         }
     }
 }
@@ -962,17 +963,20 @@ fn execute_work_item(cgcx: &CodegenContext,
                                      work_item.output_names);
             }
             ModuleSource::Preexisting(wp) => {
-                let incremental = cgcx.incremental.as_ref().unwrap();
+                let incr_comp_session_dir = cgcx.incr_comp_session_dir
+                                                .as_ref()
+                                                .unwrap();
                 let name = &work_item.mtrans.name;
                 for (kind, saved_file) in wp.saved_files {
                     let obj_out = work_item.output_names.temp_path(kind, Some(name));
-                    let source_file = incremental.join(&saved_file);
+                    let source_file = in_incr_comp_dir(&incr_comp_session_dir,
+                                                       &saved_file);
                     debug!("copying pre-existing module `{}` from {:?} to {}",
                            work_item.mtrans.name,
                            source_file,
                            obj_out.display());
                     match link_or_copy(&source_file, &obj_out) {
-                        Ok(()) => { }
+                        Ok(_) => { }
                         Err(err) => {
                             cgcx.handler.err(&format!("unable to copy {} to {}: {}",
                                                       source_file.display(),
@@ -1018,7 +1022,7 @@ fn run_work_multithreaded(sess: &Session,
         let mut tx = Some(tx);
         futures.push(rx);
 
-        let incremental = sess.opts.incremental.clone();
+        let incr_comp_session_dir = sess.incr_comp_session_dir_opt().map(|r| r.clone());
 
         thread::Builder::new().name(format!("codegen-{}", i)).spawn(move || {
             let diag_handler = Handler::with_emitter(true, false, box diag_emitter);
@@ -1031,7 +1035,7 @@ fn run_work_multithreaded(sess: &Session,
                 plugin_passes: plugin_passes,
                 remark: remark,
                 worker: i,
-                incremental: incremental,
+                incr_comp_session_dir: incr_comp_session_dir
             };
 
             loop {
index f190fbeb6feb9553d42e7cda76ceb1cf77620ac1..99126095ede3e699d85612b00ef81031b44d67ec 100644 (file)
 use assert_module_sources;
 use back::link;
 use back::linker::LinkerInfo;
-use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param};
+use llvm::{Linkage, ValueRef, Vector, get_param};
 use llvm;
-use rustc::cfg;
 use rustc::hir::def_id::DefId;
 use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
-use rustc::hir::pat_util::simple_name;
 use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::hir::map as hir_map;
 use rustc::util::common::time;
 use rustc::mir::mir_map::MirMap;
-use rustc_data_structures::graph::OUTGOING;
-use session::config::{self, NoDebugInfo, FullDebugInfo};
+use session::config::{self, NoDebugInfo};
+use rustc_incremental::IncrementalHashesMap;
 use session::Session;
-use _match;
 use abi::{self, Abi, FnType};
 use adt;
 use attributes;
 use build::*;
 use builder::{Builder, noname};
-use callee::{Callee, CallArgs, ArgExprs, ArgVals};
-use cleanup::{self, CleanupMethods, DropHint};
-use closure;
-use common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_uint, C_integral};
+use callee::{Callee};
+use common::{Block, C_bool, C_bytes_in_context, C_i32, C_uint};
 use collector::{self, TransItemCollectionMode};
 use common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef};
-use common::{CrateContext, DropFlagHintsMap, Field, FunctionContext};
-use common::{Result, NodeIdAndSpan, VariantInfo};
-use common::{node_id_type, fulfill_obligation};
-use common::{type_is_immediate, type_is_zero_size, val_ty};
+use common::{CrateContext, FunctionContext};
+use common::{Result};
+use common::{fulfill_obligation};
+use common::{type_is_zero_size, val_ty};
 use common;
 use consts;
 use context::{SharedCrateContext, CrateContextList};
-use controlflow;
-use datum;
-use debuginfo::{self, DebugLoc, ToDebugLoc};
+use debuginfo::{self, DebugLoc};
 use declare;
-use expr;
-use glue;
-use inline;
 use machine;
 use machine::{llalign_of_min, llsize_of};
 use meth;
 use symbol_map::SymbolMap;
 use symbol_names_test;
 use trans_item::TransItem;
-use tvec;
 use type_::Type;
 use type_of;
 use value::Value;
 use Disr;
-use util::common::indenter;
 use util::sha2::Sha256;
-use util::nodemap::{NodeMap, NodeSet, FnvHashSet};
+use util::nodemap::{NodeSet, FnvHashMap, FnvHashSet};
 
 use arena::TypedArena;
 use libc::c_uint;
 use std::ffi::{CStr, CString};
 use std::borrow::Cow;
 use std::cell::{Cell, RefCell};
-use std::collections::HashMap;
 use std::ptr;
 use std::rc::Rc;
 use std::str;
-use std::{i8, i16, i32, i64};
+use std::i32;
 use syntax_pos::{Span, DUMMY_SP};
-use syntax::parse::token::InternedString;
-use syntax::attr::AttrMetaMethods;
 use syntax::attr;
-use rustc::hir::intravisit::{self, Visitor};
 use rustc::hir;
 use syntax::ast;
 
@@ -191,8 +175,12 @@ fn drop(&mut self) {
     }
 }
 
-pub fn kind_for_closure(ccx: &CrateContext, closure_id: DefId) -> ty::ClosureKind {
-    *ccx.tcx().tables.borrow().closure_kinds.get(&closure_id).unwrap()
+pub fn get_meta(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
+    StructGEP(bcx, fat_ptr, abi::FAT_PTR_EXTRA)
+}
+
+pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
+    StructGEP(bcx, fat_ptr, abi::FAT_PTR_ADDR)
 }
 
 fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, info_ty: Ty<'tcx>, it: LangItem) -> DefId {
@@ -219,7 +207,7 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     // Allocate space:
     let def_id = require_alloc_fn(bcx, info_ty, ExchangeMallocFnLangItem);
     let r = Callee::def(bcx.ccx(), def_id, Substs::empty(bcx.tcx()))
-        .call(bcx, debug_loc, ArgVals(&[size, align]), None);
+        .call(bcx, debug_loc, &[size, align], None);
 
     Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr))
 }
@@ -394,154 +382,6 @@ pub fn compare_simd_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     SExt(bcx, ICmp(bcx, cmp, lhs, rhs, debug_loc), ret_ty)
 }
 
-// Iterates through the elements of a structural type.
-pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
-                                         av: ValueRef,
-                                         t: Ty<'tcx>,
-                                         mut f: F)
-                                         -> Block<'blk, 'tcx>
-    where F: FnMut(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>
-{
-    let _icx = push_ctxt("iter_structural_ty");
-
-    fn iter_variant<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
-                                   repr: &adt::Repr<'tcx>,
-                                   av: adt::MaybeSizedValue,
-                                   variant: ty::VariantDef<'tcx>,
-                                   substs: &Substs<'tcx>,
-                                   f: &mut F)
-                                   -> Block<'blk, 'tcx>
-        where F: FnMut(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>
-    {
-        let _icx = push_ctxt("iter_variant");
-        let tcx = cx.tcx();
-        let mut cx = cx;
-
-        for (i, field) in variant.fields.iter().enumerate() {
-            let arg = monomorphize::field_ty(tcx, substs, field);
-            cx = f(cx,
-                   adt::trans_field_ptr(cx, repr, av, Disr::from(variant.disr_val), i),
-                   arg);
-        }
-        return cx;
-    }
-
-    let value = if common::type_is_sized(cx.tcx(), t) {
-        adt::MaybeSizedValue::sized(av)
-    } else {
-        let data = Load(cx, expr::get_dataptr(cx, av));
-        let info = Load(cx, expr::get_meta(cx, av));
-        adt::MaybeSizedValue::unsized_(data, info)
-    };
-
-    let mut cx = cx;
-    match t.sty {
-        ty::TyStruct(..) => {
-            let repr = adt::represent_type(cx.ccx(), t);
-            let VariantInfo { fields, discr } = VariantInfo::from_ty(cx.tcx(), t, None);
-            for (i, &Field(_, field_ty)) in fields.iter().enumerate() {
-                let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr::from(discr), i);
-
-                let val = if common::type_is_sized(cx.tcx(), field_ty) {
-                    llfld_a
-                } else {
-                    let scratch = datum::rvalue_scratch_datum(cx, field_ty, "__fat_ptr_iter");
-                    Store(cx, llfld_a, expr::get_dataptr(cx, scratch.val));
-                    Store(cx, value.meta, expr::get_meta(cx, scratch.val));
-                    scratch.val
-                };
-                cx = f(cx, val, field_ty);
-            }
-        }
-        ty::TyClosure(_, ref substs) => {
-            let repr = adt::represent_type(cx.ccx(), t);
-            for (i, upvar_ty) in substs.upvar_tys.iter().enumerate() {
-                let llupvar = adt::trans_field_ptr(cx, &repr, value, Disr(0), i);
-                cx = f(cx, llupvar, upvar_ty);
-            }
-        }
-        ty::TyArray(_, n) => {
-            let (base, len) = tvec::get_fixed_base_and_len(cx, value.value, n);
-            let unit_ty = t.sequence_element_type(cx.tcx());
-            cx = tvec::iter_vec_raw(cx, base, unit_ty, len, f);
-        }
-        ty::TySlice(_) | ty::TyStr => {
-            let unit_ty = t.sequence_element_type(cx.tcx());
-            cx = tvec::iter_vec_raw(cx, value.value, unit_ty, value.meta, f);
-        }
-        ty::TyTuple(ref args) => {
-            let repr = adt::represent_type(cx.ccx(), t);
-            for (i, arg) in args.iter().enumerate() {
-                let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr(0), i);
-                cx = f(cx, llfld_a, *arg);
-            }
-        }
-        ty::TyEnum(en, substs) => {
-            let fcx = cx.fcx;
-            let ccx = fcx.ccx;
-
-            let repr = adt::represent_type(ccx, t);
-            let n_variants = en.variants.len();
-
-            // NB: we must hit the discriminant first so that structural
-            // comparison know not to proceed when the discriminants differ.
-
-            match adt::trans_switch(cx, &repr, av, false) {
-                (_match::Single, None) => {
-                    if n_variants != 0 {
-                        assert!(n_variants == 1);
-                        cx = iter_variant(cx, &repr, adt::MaybeSizedValue::sized(av),
-                                          &en.variants[0], substs, &mut f);
-                    }
-                }
-                (_match::Switch, Some(lldiscrim_a)) => {
-                    cx = f(cx, lldiscrim_a, cx.tcx().types.isize);
-
-                    // Create a fall-through basic block for the "else" case of
-                    // the switch instruction we're about to generate. Note that
-                    // we do **not** use an Unreachable instruction here, even
-                    // though most of the time this basic block will never be hit.
-                    //
-                    // When an enum is dropped it's contents are currently
-                    // overwritten to DTOR_DONE, which means the discriminant
-                    // could have changed value to something not within the actual
-                    // range of the discriminant. Currently this function is only
-                    // used for drop glue so in this case we just return quickly
-                    // from the outer function, and any other use case will only
-                    // call this for an already-valid enum in which case the `ret
-                    // void` will never be hit.
-                    let ret_void_cx = fcx.new_temp_block("enum-iter-ret-void");
-                    RetVoid(ret_void_cx, DebugLoc::None);
-                    let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb, n_variants);
-                    let next_cx = fcx.new_temp_block("enum-iter-next");
-
-                    for variant in &en.variants {
-                        let variant_cx = fcx.new_temp_block(&format!("enum-iter-variant-{}",
-                                                                     &variant.disr_val
-                                                                             .to_string()));
-                        let case_val = adt::trans_case(cx, &repr, Disr::from(variant.disr_val));
-                        AddCase(llswitch, case_val, variant_cx.llbb);
-                        let variant_cx = iter_variant(variant_cx,
-                                                      &repr,
-                                                      value,
-                                                      variant,
-                                                      substs,
-                                                      &mut f);
-                        Br(variant_cx, next_cx.llbb, DebugLoc::None);
-                    }
-                    cx = next_cx;
-                }
-                _ => ccx.sess().unimpl("value from adt::trans_switch in iter_structural_ty"),
-            }
-        }
-        _ => {
-            cx.sess().unimpl(&format!("type in iter_structural_ty: {}", t))
-        }
-    }
-    return cx;
-}
-
-
 /// Retrieve the information we are losing (making dynamic) in an unsizing
 /// adjustment.
 ///
@@ -633,12 +473,12 @@ pub fn coerce_unsized_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
             let src_repr = adt::represent_type(bcx.ccx(), src_ty);
             let src_fields = match &*src_repr {
-                &adt::Repr::Univariant(ref s, _) => &s.fields,
+                &adt::Repr::Univariant(ref s) => &s.fields,
                 _ => bug!("struct has non-univariant repr"),
             };
             let dst_repr = adt::represent_type(bcx.ccx(), dst_ty);
             let dst_fields = match &*dst_repr {
-                &adt::Repr::Univariant(ref s, _) => &s.fields,
+                &adt::Repr::Univariant(ref s) => &s.fields,
                 _ => bug!("struct has non-univariant repr"),
             };
 
@@ -672,7 +512,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx
                                              -> CustomCoerceUnsized {
     let trait_ref = ty::Binder(ty::TraitRef {
         def_id: scx.tcx().lang_items.coerce_unsized_trait().unwrap(),
-        substs: Substs::new_trait(scx.tcx(), vec![target_ty], vec![], source_ty)
+        substs: Substs::new_trait(scx.tcx(), source_ty, &[target_ty])
     });
 
     match fulfill_obligation(scx, DUMMY_SP, trait_ref) {
@@ -732,101 +572,6 @@ fn cast_shift_rhs<F, G>(op: hir::BinOp_,
     }
 }
 
-pub fn llty_and_min_for_signed_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
-                                              val_t: Ty<'tcx>)
-                                              -> (Type, u64) {
-    match val_t.sty {
-        ty::TyInt(t) => {
-            let llty = Type::int_from_ty(cx.ccx(), t);
-            let min = match t {
-                ast::IntTy::Is if llty == Type::i32(cx.ccx()) => i32::MIN as u64,
-                ast::IntTy::Is => i64::MIN as u64,
-                ast::IntTy::I8 => i8::MIN as u64,
-                ast::IntTy::I16 => i16::MIN as u64,
-                ast::IntTy::I32 => i32::MIN as u64,
-                ast::IntTy::I64 => i64::MIN as u64,
-            };
-            (llty, min)
-        }
-        _ => bug!(),
-    }
-}
-
-pub fn fail_if_zero_or_overflows<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
-                                             call_info: NodeIdAndSpan,
-                                             divrem: hir::BinOp,
-                                             lhs: ValueRef,
-                                             rhs: ValueRef,
-                                             rhs_t: Ty<'tcx>)
-                                             -> Block<'blk, 'tcx> {
-    use rustc_const_math::{ConstMathErr, Op};
-
-    let (zero_err, overflow_err) = if divrem.node == hir::BiDiv {
-        (ConstMathErr::DivisionByZero, ConstMathErr::Overflow(Op::Div))
-    } else {
-        (ConstMathErr::RemainderByZero, ConstMathErr::Overflow(Op::Rem))
-    };
-    let debug_loc = call_info.debug_loc();
-
-    let (is_zero, is_signed) = match rhs_t.sty {
-        ty::TyInt(t) => {
-            let zero = C_integral(Type::int_from_ty(cx.ccx(), t), 0, false);
-            (ICmp(cx, llvm::IntEQ, rhs, zero, debug_loc), true)
-        }
-        ty::TyUint(t) => {
-            let zero = C_integral(Type::uint_from_ty(cx.ccx(), t), 0, false);
-            (ICmp(cx, llvm::IntEQ, rhs, zero, debug_loc), false)
-        }
-        ty::TyStruct(def, _) if def.is_simd() => {
-            let mut res = C_bool(cx.ccx(), false);
-            for i in 0..rhs_t.simd_size(cx.tcx()) {
-                res = Or(cx,
-                         res,
-                         IsNull(cx, ExtractElement(cx, rhs, C_int(cx.ccx(), i as i64))),
-                         debug_loc);
-            }
-            (res, false)
-        }
-        _ => {
-            bug!("fail-if-zero on unexpected type: {}", rhs_t);
-        }
-    };
-    let bcx = with_cond(cx, is_zero, |bcx| {
-        controlflow::trans_fail(bcx, call_info, InternedString::new(zero_err.description()))
-    });
-
-    // To quote LLVM's documentation for the sdiv instruction:
-    //
-    //      Division by zero leads to undefined behavior. Overflow also leads
-    //      to undefined behavior; this is a rare case, but can occur, for
-    //      example, by doing a 32-bit division of -2147483648 by -1.
-    //
-    // In order to avoid undefined behavior, we perform runtime checks for
-    // signed division/remainder which would trigger overflow. For unsigned
-    // integers, no action beyond checking for zero need be taken.
-    if is_signed {
-        let (llty, min) = llty_and_min_for_signed_ty(cx, rhs_t);
-        let minus_one = ICmp(bcx,
-                             llvm::IntEQ,
-                             rhs,
-                             C_integral(llty, !0, false),
-                             debug_loc);
-        with_cond(bcx, minus_one, |bcx| {
-            let is_min = ICmp(bcx,
-                              llvm::IntEQ,
-                              lhs,
-                              C_integral(llty, min, true),
-                              debug_loc);
-            with_cond(bcx, is_min, |bcx| {
-                controlflow::trans_fail(bcx, call_info,
-                                        InternedString::new(overflow_err.description()))
-            })
-        })
-    } else {
-        bcx
-    }
-}
-
 pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                           llfn: ValueRef,
                           llargs: &[ValueRef],
@@ -837,21 +582,12 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         return (C_null(Type::i8(bcx.ccx())), bcx);
     }
 
-    match bcx.opt_node_id {
-        None => {
-            debug!("invoke at ???");
-        }
-        Some(id) => {
-            debug!("invoke at {}", bcx.tcx().map.node_to_string(id));
-        }
-    }
-
     if need_invoke(bcx) {
         debug!("invoking {:?} at {:?}", Value(llfn), bcx.llbb);
         for &llarg in llargs {
             debug!("arg: {:?}", Value(llarg));
         }
-        let normal_bcx = bcx.fcx.new_temp_block("normal-return");
+        let normal_bcx = bcx.fcx.new_block("normal-return");
         let landing_pad = bcx.fcx.get_landing_pad();
 
         let llresult = Invoke(bcx,
@@ -893,14 +629,6 @@ pub fn need_invoke(bcx: Block) -> bool {
     }
 }
 
-pub fn load_if_immediate<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, t: Ty<'tcx>) -> ValueRef {
-    let _icx = push_ctxt("load_if_immediate");
-    if type_is_immediate(cx.ccx(), t) {
-        return load_ty(cx, v, t);
-    }
-    return v;
-}
-
 /// Helper for loading values from memory. Does the necessary conversion if the in-memory type
 /// differs from the type used for SSA values. Also handles various special cases where the type
 /// gives us better information about what we are loading.
@@ -956,10 +684,10 @@ pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t
     if common::type_is_fat_ptr(cx.tcx(), t) {
         Store(cx,
               ExtractValue(cx, v, abi::FAT_PTR_ADDR),
-              expr::get_dataptr(cx, dst));
+              get_dataptr(cx, dst));
         Store(cx,
               ExtractValue(cx, v, abi::FAT_PTR_EXTRA),
-              expr::get_meta(cx, dst));
+              get_meta(cx, dst));
     } else {
         Store(cx, from_immediate(cx, v), dst);
     }
@@ -971,8 +699,8 @@ pub fn store_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                                  dst: ValueRef,
                                  _ty: Ty<'tcx>) {
     // FIXME: emit metadata
-    Store(cx, data, expr::get_dataptr(cx, dst));
-    Store(cx, extra, expr::get_meta(cx, dst));
+    Store(cx, data, get_dataptr(cx, dst));
+    Store(cx, extra, get_meta(cx, dst));
 }
 
 pub fn load_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
@@ -980,8 +708,8 @@ pub fn load_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                                 _ty: Ty<'tcx>)
                                 -> (ValueRef, ValueRef) {
     // FIXME: emit metadata
-    (Load(cx, expr::get_dataptr(cx, src)),
-     Load(cx, expr::get_meta(cx, src)))
+    (Load(cx, get_dataptr(cx, src)),
+     Load(cx, get_meta(cx, src)))
 }
 
 pub fn from_immediate(bcx: Block, val: ValueRef) -> ValueRef {
@@ -1000,19 +728,6 @@ pub fn to_immediate(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {
     }
 }
 
-pub fn init_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, local: &hir::Local) -> Block<'blk, 'tcx> {
-    debug!("init_local(bcx={}, local.id={})", bcx.to_str(), local.id);
-    let _indenter = indenter();
-    let _icx = push_ctxt("init_local");
-    _match::store_local(bcx, local)
-}
-
-pub fn raw_block<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>,
-                             llbb: BasicBlockRef)
-                             -> Block<'blk, 'tcx> {
-    common::BlockS::new(llbb, None, fcx)
-}
-
 pub fn with_cond<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, val: ValueRef, f: F) -> Block<'blk, 'tcx>
     where F: FnOnce(Block<'blk, 'tcx>) -> Block<'blk, 'tcx>
 {
@@ -1023,8 +738,8 @@ pub fn with_cond<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, val: ValueRef, f: F) ->
     }
 
     let fcx = bcx.fcx;
-    let next_cx = fcx.new_temp_block("next");
-    let cond_cx = fcx.new_temp_block("cond");
+    let next_cx = fcx.new_block("next");
+    let cond_cx = fcx.new_block("cond");
     CondBr(bcx, val, cond_cx.llbb, next_cx.llbb, DebugLoc::None);
     let after_cx = f(cond_cx);
     if !after_cx.terminated.get() {
@@ -1098,7 +813,7 @@ pub fn trans_unwind_resume(bcx: Block, lpval: ValueRef) {
     } else {
         let exc_ptr = ExtractValue(bcx, lpval, 0);
         bcx.fcx.eh_unwind_resume()
-            .call(bcx, DebugLoc::None, ArgVals(&[exc_ptr]), None);
+            .call(bcx, DebugLoc::None, &[exc_ptr], None);
     }
 }
 
@@ -1141,15 +856,6 @@ pub fn memcpy_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, dst: ValueRef, src: ValueRe
     }
 }
 
-pub fn drop_done_fill_mem<'blk, 'tcx>(cx: Block<'blk, 'tcx>, llptr: ValueRef, t: Ty<'tcx>) {
-    if cx.unreachable.get() {
-        return;
-    }
-    let _icx = push_ctxt("drop_done_fill_mem");
-    let bcx = cx;
-    memfill(&B(bcx), llptr, t, adt::DTOR_DONE);
-}
-
 pub fn init_zero_mem<'blk, 'tcx>(cx: Block<'blk, 'tcx>, llptr: ValueRef, t: Ty<'tcx>) {
     if cx.unreachable.get() {
         return;
@@ -1189,82 +895,11 @@ pub fn call_memset<'bcx, 'tcx>(b: &Builder<'bcx, 'tcx>,
     b.call(llintrinsicfn, &[ptr, fill_byte, size, align, volatile], None);
 }
 
-
-/// In general, when we create an scratch value in an alloca, the
-/// creator may not know if the block (that initializes the scratch
-/// with the desired value) actually dominates the cleanup associated
-/// with the scratch value.
-///
-/// To deal with this, when we do an alloca (at the *start* of whole
-/// function body), we optionally can also set the associated
-/// dropped-flag state of the alloca to "dropped."
-#[derive(Copy, Clone, Debug)]
-pub enum InitAlloca {
-    /// Indicates that the state should have its associated drop flag
-    /// set to "dropped" at the point of allocation.
-    Dropped,
-    /// Indicates the value of the associated drop flag is irrelevant.
-    /// The embedded string literal is a programmer provided argument
-    /// for why. This is a safeguard forcing compiler devs to
-    /// document; it might be a good idea to also emit this as a
-    /// comment with the alloca itself when emitting LLVM output.ll.
-    Uninit(&'static str),
-}
-
-
 pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                            t: Ty<'tcx>,
+                            ty: Ty<'tcx>,
                             name: &str) -> ValueRef {
-    // pnkfelix: I do not know why alloc_ty meets the assumptions for
-    // passing Uninit, but it was never needed (even back when we had
-    // the original boolean `zero` flag on `lvalue_scratch_datum`).
-    alloc_ty_init(bcx, t, InitAlloca::Uninit("all alloc_ty are uninit"), name)
-}
-
-/// This variant of `fn alloc_ty` does not necessarily assume that the
-/// alloca should be created with no initial value. Instead the caller
-/// controls that assumption via the `init` flag.
-///
-/// Note that if the alloca *is* initialized via `init`, then we will
-/// also inject an `llvm.lifetime.start` before that initialization
-/// occurs, and thus callers should not call_lifetime_start
-/// themselves.  But if `init` says "uninitialized", then callers are
-/// in charge of choosing where to call_lifetime_start and
-/// subsequently populate the alloca.
-///
-/// (See related discussion on PR #30823.)
-pub fn alloc_ty_init<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                             t: Ty<'tcx>,
-                             init: InitAlloca,
-                             name: &str) -> ValueRef {
-    let _icx = push_ctxt("alloc_ty");
-    let ccx = bcx.ccx();
-    let ty = type_of::type_of(ccx, t);
-    assert!(!t.has_param_types());
-    match init {
-        InitAlloca::Dropped => alloca_dropped(bcx, t, name),
-        InitAlloca::Uninit(_) => alloca(bcx, ty, name),
-    }
-}
-
-pub fn alloca_dropped<'blk, 'tcx>(cx: Block<'blk, 'tcx>, ty: Ty<'tcx>, name: &str) -> ValueRef {
-    let _icx = push_ctxt("alloca_dropped");
-    let llty = type_of::type_of(cx.ccx(), ty);
-    if cx.unreachable.get() {
-        unsafe { return llvm::LLVMGetUndef(llty.ptr_to().to_ref()); }
-    }
-    let p = alloca(cx, llty, name);
-    let b = cx.fcx.ccx.builder();
-    b.position_before(cx.fcx.alloca_insert_pt.get().unwrap());
-
-    // This is just like `call_lifetime_start` (but latter expects a
-    // Block, which we do not have for `alloca_insert_pt`).
-    core_lifetime_emit(cx.ccx(), p, Lifetime::Start, |ccx, size, lifetime_start| {
-        let ptr = b.pointercast(p, Type::i8p(ccx));
-        b.call(lifetime_start, &[C_u64(ccx, size), ptr], None);
-    });
-    memfill(&b, p, ty, adt::DTOR_DONE);
-    p
+    assert!(!ty.has_param_types());
+    alloca(bcx, type_of::type_of(bcx.ccx(), ty), name)
 }
 
 pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef {
@@ -1278,121 +913,6 @@ pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef {
     Alloca(cx, ty, name)
 }
 
-pub fn set_value_name(val: ValueRef, name: &str) {
-    unsafe {
-        let name = CString::new(name).unwrap();
-        llvm::LLVMSetValueName(val, name.as_ptr());
-    }
-}
-
-struct FindNestedReturn {
-    found: bool,
-}
-
-impl FindNestedReturn {
-    fn new() -> FindNestedReturn {
-        FindNestedReturn {
-            found: false,
-        }
-    }
-}
-
-impl<'v> Visitor<'v> for FindNestedReturn {
-    fn visit_expr(&mut self, e: &hir::Expr) {
-        match e.node {
-            hir::ExprRet(..) => {
-                self.found = true;
-            }
-            _ => intravisit::walk_expr(self, e),
-        }
-    }
-}
-
-fn build_cfg<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                       id: ast::NodeId)
-                       -> (ast::NodeId, Option<cfg::CFG>) {
-    let blk = match tcx.map.find(id) {
-        Some(hir_map::NodeItem(i)) => {
-            match i.node {
-                hir::ItemFn(_, _, _, _, _, ref blk) => {
-                    blk
-                }
-                _ => bug!("unexpected item variant in has_nested_returns"),
-            }
-        }
-        Some(hir_map::NodeTraitItem(trait_item)) => {
-            match trait_item.node {
-                hir::MethodTraitItem(_, Some(ref body)) => body,
-                _ => {
-                    bug!("unexpected variant: trait item other than a provided method in \
-                          has_nested_returns")
-                }
-            }
-        }
-        Some(hir_map::NodeImplItem(impl_item)) => {
-            match impl_item.node {
-                hir::ImplItemKind::Method(_, ref body) => body,
-                _ => {
-                    bug!("unexpected variant: non-method impl item in has_nested_returns")
-                }
-            }
-        }
-        Some(hir_map::NodeExpr(e)) => {
-            match e.node {
-                hir::ExprClosure(_, _, ref blk, _) => blk,
-                _ => bug!("unexpected expr variant in has_nested_returns"),
-            }
-        }
-        Some(hir_map::NodeVariant(..)) |
-        Some(hir_map::NodeStructCtor(..)) => return (ast::DUMMY_NODE_ID, None),
-
-        // glue, shims, etc
-        None if id == ast::DUMMY_NODE_ID => return (ast::DUMMY_NODE_ID, None),
-
-        _ => bug!("unexpected variant in has_nested_returns: {}",
-                  tcx.node_path_str(id)),
-    };
-
-    (blk.id, Some(cfg::CFG::new(tcx, blk)))
-}
-
-// Checks for the presence of "nested returns" in a function.
-// Nested returns are when the inner expression of a return expression
-// (the 'expr' in 'return expr') contains a return expression. Only cases
-// where the outer return is actually reachable are considered. Implicit
-// returns from the end of blocks are considered as well.
-//
-// This check is needed to handle the case where the inner expression is
-// part of a larger expression that may have already partially-filled the
-// return slot alloca. This can cause errors related to clean-up due to
-// the clobbering of the existing value in the return slot.
-fn has_nested_returns(tcx: TyCtxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool {
-    for index in cfg.graph.depth_traverse(cfg.entry, OUTGOING) {
-        let n = cfg.graph.node_data(index);
-        match tcx.map.find(n.id()) {
-            Some(hir_map::NodeExpr(ex)) => {
-                if let hir::ExprRet(Some(ref ret_expr)) = ex.node {
-                    let mut visitor = FindNestedReturn::new();
-                    intravisit::walk_expr(&mut visitor, &ret_expr);
-                    if visitor.found {
-                        return true;
-                    }
-                }
-            }
-            Some(hir_map::NodeBlock(blk)) if blk.id == blk_id => {
-                let mut visitor = FindNestedReturn::new();
-                walk_list!(&mut visitor, visit_expr, &blk.expr);
-                if visitor.found {
-                    return true;
-                }
-            }
-            _ => {}
-        }
-    }
-
-    return false;
-}
-
 impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
     /// Create a function context for the given function.
     /// Beware that you must call `fcx.init` or `fcx.bind_args`
@@ -1400,15 +920,15 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
     pub fn new(ccx: &'blk CrateContext<'blk, 'tcx>,
                llfndecl: ValueRef,
                fn_ty: FnType,
-               definition: Option<(Instance<'tcx>, &ty::FnSig<'tcx>, Abi, ast::NodeId)>,
+               definition: Option<(Instance<'tcx>, &ty::FnSig<'tcx>, Abi)>,
                block_arena: &'blk TypedArena<common::BlockS<'blk, 'tcx>>)
                -> FunctionContext<'blk, 'tcx> {
-        let (param_substs, def_id, inlined_id) = match definition {
-            Some((instance, _, _, inlined_id)) => {
+        let (param_substs, def_id) = match definition {
+            Some((instance, _, _)) => {
                 common::validate_substs(instance.substs);
-                (instance.substs, Some(instance.def), Some(inlined_id))
+                (instance.substs, Some(instance.def))
             }
-            None => (Substs::empty(ccx.tcx()), None, None)
+            None => (Substs::empty(ccx.tcx()), None)
         };
 
         let local_id = def_id.and_then(|id| ccx.tcx().map.as_local_node_id(id));
@@ -1416,70 +936,47 @@ pub fn new(ccx: &'blk CrateContext<'blk, 'tcx>,
         debug!("FunctionContext::new({})",
                definition.map_or(String::new(), |d| d.0.to_string()));
 
-        let cfg = inlined_id.map(|id| build_cfg(ccx.tcx(), id));
-        let nested_returns = if let Some((blk_id, Some(ref cfg))) = cfg {
-            has_nested_returns(ccx.tcx(), cfg, blk_id)
-        } else {
-            false
-        };
-
-        let check_attrs = |attrs: &[ast::Attribute]| {
-            let default_to_mir = ccx.sess().opts.debugging_opts.orbit;
-            let invert = if default_to_mir { "rustc_no_mir" } else { "rustc_mir" };
-            (default_to_mir ^ attrs.iter().any(|item| item.check_name(invert)),
-             attrs.iter().any(|item| item.check_name("no_debug")))
-        };
-
-        let (use_mir, no_debug) = if let Some(id) = local_id {
-            check_attrs(ccx.tcx().map.attrs(id))
+        let no_debug = if let Some(id) = local_id {
+            ccx.tcx().map.attrs(id)
+               .iter().any(|item| item.check_name("no_debug"))
         } else if let Some(def_id) = def_id {
-            check_attrs(&ccx.sess().cstore.item_attrs(def_id))
+            ccx.sess().cstore.item_attrs(def_id)
+               .iter().any(|item| item.check_name("no_debug"))
         } else {
-            check_attrs(&[])
+            false
         };
 
-        let mir = if use_mir {
-            def_id.and_then(|id| ccx.get_mir(id))
-        } else {
-            None
-        };
+        let mir = def_id.and_then(|id| ccx.get_mir(id));
 
-        let debug_context = if let (false, Some(definition)) = (no_debug, definition) {
-            let (instance, sig, abi, _) = definition;
-            debuginfo::create_function_debug_context(ccx, instance, sig, abi, llfndecl)
+        let debug_context = if let (false, Some((instance, sig, abi)), &Some(ref mir)) =
+                (no_debug, definition, &mir) {
+            debuginfo::create_function_debug_context(ccx, instance, sig, abi, llfndecl, mir)
         } else {
             debuginfo::empty_function_debug_context(ccx)
         };
 
         FunctionContext {
-            needs_ret_allocas: nested_returns && mir.is_none(),
             mir: mir,
             llfn: llfndecl,
             llretslotptr: Cell::new(None),
             param_env: ccx.tcx().empty_parameter_environment(),
             alloca_insert_pt: Cell::new(None),
-            llreturn: Cell::new(None),
             landingpad_alloca: Cell::new(None),
-            lllocals: RefCell::new(NodeMap()),
-            llupvars: RefCell::new(NodeMap()),
-            lldropflag_hints: RefCell::new(DropFlagHintsMap::new()),
             fn_ty: fn_ty,
             param_substs: param_substs,
-            span: inlined_id.and_then(|id| ccx.tcx().map.opt_span(id)),
+            span: None,
             block_arena: block_arena,
             lpad_arena: TypedArena::new(),
             ccx: ccx,
             debug_context: debug_context,
             scopes: RefCell::new(Vec::new()),
-            cfg: cfg.and_then(|(_, cfg)| cfg)
         }
     }
 
     /// Performs setup on a newly created function, creating the entry
     /// scope block and allocating space for the return pointer.
-    pub fn init(&'blk self, skip_retptr: bool, fn_did: Option<DefId>)
-                -> Block<'blk, 'tcx> {
-        let entry_bcx = self.new_temp_block("entry-block");
+    pub fn init(&'blk self, skip_retptr: bool) -> Block<'blk, 'tcx> {
+        let entry_bcx = self.new_block("entry-block");
 
         // Use a dummy instruction as the insertion point for all allocas.
         // This is later removed in FunctionContext::cleanup.
@@ -1497,244 +994,26 @@ pub fn init(&'blk self, skip_retptr: bool, fn_did: Option<DefId>)
             // which will hold the pointer to the right alloca which has the
             // final ret value
             let llty = self.fn_ty.ret.memory_ty(self.ccx);
-            let slot = if self.needs_ret_allocas {
-                // Let's create the stack slot
-                let slot = AllocaFcx(self, llty.ptr_to(), "llretslotptr");
-
-                // and if we're using an out pointer, then store that in our newly made slot
-                if self.fn_ty.ret.is_indirect() {
-                    let outptr = get_param(self.llfn, 0);
-
-                    let b = self.ccx.builder();
-                    b.position_before(self.alloca_insert_pt.get().unwrap());
-                    b.store(outptr, slot);
-                }
-
-                slot
+            // But if there are no nested returns, we skip the indirection
+            // and have a single retslot
+            let slot = if self.fn_ty.ret.is_indirect() {
+                get_param(self.llfn, 0)
             } else {
-                // But if there are no nested returns, we skip the indirection
-                // and have a single retslot
-                if self.fn_ty.ret.is_indirect() {
-                    get_param(self.llfn, 0)
-                } else {
-                    AllocaFcx(self, llty, "sret_slot")
-                }
+                AllocaFcx(self, llty, "sret_slot")
             };
 
             self.llretslotptr.set(Some(slot));
         }
 
-        // Create the drop-flag hints for every unfragmented path in the function.
-        let tcx = self.ccx.tcx();
-        let tables = tcx.tables.borrow();
-        let mut hints = self.lldropflag_hints.borrow_mut();
-        let fragment_infos = tcx.fragment_infos.borrow();
-
-        // Intern table for drop-flag hint datums.
-        let mut seen = HashMap::new();
-
-        let fragment_infos = fn_did.and_then(|did| fragment_infos.get(&did));
-        if let Some(fragment_infos) = fragment_infos {
-            for &info in fragment_infos {
-
-                let make_datum = |id| {
-                    let init_val = C_u8(self.ccx, adt::DTOR_NEEDED_HINT);
-                    let llname = &format!("dropflag_hint_{}", id);
-                    debug!("adding hint {}", llname);
-                    let ty = tcx.types.u8;
-                    let ptr = alloc_ty(entry_bcx, ty, llname);
-                    Store(entry_bcx, init_val, ptr);
-                    let flag = datum::Lvalue::new_dropflag_hint("FunctionContext::init");
-                    datum::Datum::new(ptr, ty, flag)
-                };
-
-                let (var, datum) = match info {
-                    ty::FragmentInfo::Moved { var, .. } |
-                    ty::FragmentInfo::Assigned { var, .. } => {
-                        let opt_datum = seen.get(&var).cloned().unwrap_or_else(|| {
-                            let ty = tables.node_types[&var];
-                            if self.type_needs_drop(ty) {
-                                let datum = make_datum(var);
-                                seen.insert(var, Some(datum.clone()));
-                                Some(datum)
-                            } else {
-                                // No drop call needed, so we don't need a dropflag hint
-                                None
-                            }
-                        });
-                        if let Some(datum) = opt_datum {
-                            (var, datum)
-                        } else {
-                            continue
-                        }
-                    }
-                };
-                match info {
-                    ty::FragmentInfo::Moved { move_expr: expr_id, .. } => {
-                        debug!("FragmentInfo::Moved insert drop hint for {}", expr_id);
-                        hints.insert(expr_id, DropHint::new(var, datum));
-                    }
-                    ty::FragmentInfo::Assigned { assignee_id: expr_id, .. } => {
-                        debug!("FragmentInfo::Assigned insert drop hint for {}", expr_id);
-                        hints.insert(expr_id, DropHint::new(var, datum));
-                    }
-                }
-            }
-        }
-
         entry_bcx
     }
 
-    /// Creates lvalue datums for each of the incoming function arguments,
-    /// matches all argument patterns against them to produce bindings,
-    /// and returns the entry block (see FunctionContext::init).
-    fn bind_args(&'blk self,
-                 args: &[hir::Arg],
-                 abi: Abi,
-                 id: ast::NodeId,
-                 closure_env: closure::ClosureEnv,
-                 arg_scope: cleanup::CustomScopeIndex)
-                 -> Block<'blk, 'tcx> {
-        let _icx = push_ctxt("FunctionContext::bind_args");
-        let fn_did = self.ccx.tcx().map.local_def_id(id);
-        let mut bcx = self.init(false, Some(fn_did));
-        let arg_scope_id = cleanup::CustomScope(arg_scope);
-
-        let mut idx = 0;
-        let mut llarg_idx = self.fn_ty.ret.is_indirect() as usize;
-
-        let has_tupled_arg = match closure_env {
-            closure::ClosureEnv::NotClosure => abi == Abi::RustCall,
-            closure::ClosureEnv::Closure(..) => {
-                closure_env.load(bcx, arg_scope_id);
-                let env_arg = &self.fn_ty.args[idx];
-                idx += 1;
-                if env_arg.pad.is_some() {
-                    llarg_idx += 1;
-                }
-                if !env_arg.is_ignore() {
-                    llarg_idx += 1;
-                }
-                false
-            }
-        };
-        let tupled_arg_id = if has_tupled_arg {
-            args[args.len() - 1].id
-        } else {
-            ast::DUMMY_NODE_ID
-        };
-
-        // Return an array wrapping the ValueRefs that we get from `get_param` for
-        // each argument into datums.
-        //
-        // For certain mode/type combinations, the raw llarg values are passed
-        // by value.  However, within the fn body itself, we want to always
-        // have all locals and arguments be by-ref so that we can cancel the
-        // cleanup and for better interaction with LLVM's debug info.  So, if
-        // the argument would be passed by value, we store it into an alloca.
-        // This alloca should be optimized away by LLVM's mem-to-reg pass in
-        // the event it's not truly needed.
-        let uninit_reason = InitAlloca::Uninit("fn_arg populate dominates dtor");
-        for hir_arg in args {
-            let arg_ty = node_id_type(bcx, hir_arg.id);
-            let arg_datum = if hir_arg.id != tupled_arg_id {
-                let arg = &self.fn_ty.args[idx];
-                idx += 1;
-                if arg.is_indirect() && bcx.sess().opts.debuginfo != FullDebugInfo {
-                    // Don't copy an indirect argument to an alloca, the caller
-                    // already put it in a temporary alloca and gave it up, unless
-                    // we emit extra-debug-info, which requires local allocas :(.
-                    let llarg = get_param(self.llfn, llarg_idx as c_uint);
-                    llarg_idx += 1;
-                    self.schedule_lifetime_end(arg_scope_id, llarg);
-                    self.schedule_drop_mem(arg_scope_id, llarg, arg_ty, None);
-
-                    datum::Datum::new(llarg,
-                                      arg_ty,
-                                      datum::Lvalue::new("FunctionContext::bind_args"))
-                } else {
-                    unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "",
-                                                                   uninit_reason,
-                                                                   arg_scope_id, |bcx, dst| {
-                        debug!("FunctionContext::bind_args: {:?}: {:?}", hir_arg, arg_ty);
-                        let b = &bcx.build();
-                        if common::type_is_fat_ptr(bcx.tcx(), arg_ty) {
-                            let meta = &self.fn_ty.args[idx];
-                            idx += 1;
-                            arg.store_fn_arg(b, &mut llarg_idx, expr::get_dataptr(bcx, dst));
-                            meta.store_fn_arg(b, &mut llarg_idx, expr::get_meta(bcx, dst));
-                        } else {
-                            arg.store_fn_arg(b, &mut llarg_idx, dst);
-                        }
-                        bcx
-                    }))
-                }
-            } else {
-                // FIXME(pcwalton): Reduce the amount of code bloat this is responsible for.
-                let tupled_arg_tys = match arg_ty.sty {
-                    ty::TyTuple(ref tys) => tys,
-                    _ => bug!("last argument of `rust-call` fn isn't a tuple?!")
-                };
-
-                unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx,
-                                                            arg_ty,
-                                                            "tupled_args",
-                                                            uninit_reason,
-                                                            arg_scope_id,
-                                                            |bcx, llval| {
-                    debug!("FunctionContext::bind_args: tupled {:?}: {:?}", hir_arg, arg_ty);
-                    for (j, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
-                        let dst = StructGEP(bcx, llval, j);
-                        let arg = &self.fn_ty.args[idx];
-                        idx += 1;
-                        let b = &bcx.build();
-                        if common::type_is_fat_ptr(bcx.tcx(), tupled_arg_ty) {
-                            let meta = &self.fn_ty.args[idx];
-                            idx += 1;
-                            arg.store_fn_arg(b, &mut llarg_idx, expr::get_dataptr(bcx, dst));
-                            meta.store_fn_arg(b, &mut llarg_idx, expr::get_meta(bcx, dst));
-                        } else {
-                            arg.store_fn_arg(b, &mut llarg_idx, dst);
-                        }
-                    }
-                    bcx
-                }))
-            };
-
-            let pat = &hir_arg.pat;
-            bcx = if let Some(name) = simple_name(pat) {
-                // Generate nicer LLVM for the common case of fn a pattern
-                // like `x: T`
-                set_value_name(arg_datum.val, &bcx.name(name));
-                self.lllocals.borrow_mut().insert(pat.id, arg_datum);
-                bcx
-            } else {
-                // General path. Copy out the values that are used in the
-                // pattern.
-                _match::bind_irrefutable_pat(bcx, pat, arg_datum.match_input(), arg_scope_id)
-            };
-            debuginfo::create_argument_metadata(bcx, hir_arg);
-        }
-
-        bcx
-    }
-
     /// Ties up the llstaticallocas -> llloadenv -> lltop edges,
     /// and builds the return block.
-    pub fn finish(&'blk self, last_bcx: Block<'blk, 'tcx>,
+    pub fn finish(&'blk self, ret_cx: Block<'blk, 'tcx>,
                   ret_debug_loc: DebugLoc) {
         let _icx = push_ctxt("FunctionContext::finish");
 
-        let ret_cx = match self.llreturn.get() {
-            Some(llreturn) => {
-                if !last_bcx.terminated.get() {
-                    Br(last_bcx, llreturn, DebugLoc::None);
-                }
-                raw_block(self, llreturn)
-            }
-            None => last_bcx,
-        };
-
         self.build_return_block(ret_cx, ret_debug_loc);
 
         DebugLoc::None.apply(self);
@@ -1746,15 +1025,11 @@ pub fn build_return_block(&self, ret_cx: Block<'blk, 'tcx>,
                               ret_debug_location: DebugLoc) {
         if self.llretslotptr.get().is_none() ||
            ret_cx.unreachable.get() ||
-           (!self.needs_ret_allocas && self.fn_ty.ret.is_indirect()) {
+           self.fn_ty.ret.is_indirect() {
             return RetVoid(ret_cx, ret_debug_location);
         }
 
-        let retslot = if self.needs_ret_allocas {
-            Load(ret_cx, self.llretslotptr.get().unwrap())
-        } else {
-            self.llretslotptr.get().unwrap()
-        };
+        let retslot = self.llretslotptr.get().unwrap();
         let retptr = Value(retslot);
         let llty = self.fn_ty.ret.original_ty;
         match (retptr.get_dominating_store(ret_cx), self.fn_ty.ret.cast) {
@@ -1813,14 +1088,10 @@ pub fn build_return_block(&self, ret_cx: Block<'blk, 'tcx>,
 ///
 /// If the function closes over its environment a closure will be returned.
 pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                               decl: &hir::FnDecl,
-                               body: &hir::Block,
                                llfndecl: ValueRef,
                                instance: Instance<'tcx>,
-                               inlined_id: ast::NodeId,
                                sig: &ty::FnSig<'tcx>,
-                               abi: Abi,
-                               closure_env: closure::ClosureEnv) {
+                               abi: Abi) {
     ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
 
     let _icx = push_ctxt("trans_closure");
@@ -1840,195 +1111,47 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     fcx = FunctionContext::new(ccx,
                                llfndecl,
                                fn_ty,
-                               Some((instance, sig, abi, inlined_id)),
+                               Some((instance, sig, abi)),
                                &arena);
 
-    if fcx.mir.is_some() {
-        return mir::trans_mir(&fcx);
+    if fcx.mir.is_none() {
+        bug!("attempted translation of `{}` w/o MIR", instance);
     }
 
-    debuginfo::fill_scope_map_for_function(&fcx, decl, body, inlined_id);
-
-    // cleanup scope for the incoming arguments
-    let fn_cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(
-        ccx, inlined_id, body.span, true);
-    let arg_scope = fcx.push_custom_cleanup_scope_with_debug_loc(fn_cleanup_debug_loc);
-
-    // Set up arguments to the function.
-    debug!("trans_closure: function: {:?}", Value(fcx.llfn));
-    let bcx = fcx.bind_args(&decl.inputs, abi, inlined_id, closure_env, arg_scope);
-
-    // Up until here, IR instructions for this function have explicitly not been annotated with
-    // source code location, so we don't step into call setup code. From here on, source location
-    // emitting should be enabled.
-    debuginfo::start_emitting_source_locations(&fcx);
-
-    let dest = if fcx.fn_ty.ret.is_ignore() {
-        expr::Ignore
-    } else {
-        expr::SaveIn(fcx.get_ret_slot(bcx, "iret_slot"))
-    };
-
-    // This call to trans_block is the place where we bridge between
-    // translation calls that don't have a return value (trans_crate,
-    // trans_mod, trans_item, et cetera) and those that do
-    // (trans_block, trans_expr, et cetera).
-    let mut bcx = controlflow::trans_block(bcx, body, dest);
-
-    match dest {
-        expr::SaveIn(slot) if fcx.needs_ret_allocas => {
-            Store(bcx, slot, fcx.llretslotptr.get().unwrap());
-        }
-        _ => {}
-    }
-
-    match fcx.llreturn.get() {
-        Some(_) => {
-            Br(bcx, fcx.return_exit_block(), DebugLoc::None);
-            fcx.pop_custom_cleanup_scope(arg_scope);
-        }
-        None => {
-            // Microoptimization writ large: avoid creating a separate
-            // llreturn basic block
-            bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope);
-        }
-    };
-
-    // Put return block after all other blocks.
-    // This somewhat improves single-stepping experience in debugger.
-    unsafe {
-        let llreturn = fcx.llreturn.get();
-        if let Some(llreturn) = llreturn {
-            llvm::LLVMMoveBasicBlockAfter(llreturn, bcx.llbb);
-        }
-    }
-
-    // Insert the mandatory first few basic blocks before lltop.
-    fcx.finish(bcx, fn_cleanup_debug_loc.debug_loc());
+    mir::trans_mir(&fcx);
 }
 
 pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) {
-    let local_instance = inline::maybe_inline_instance(ccx, instance);
-
-    let fn_node_id = ccx.tcx().map.as_local_node_id(local_instance.def).unwrap();
-
-    let _s = StatRecorder::new(ccx, ccx.tcx().node_path_str(fn_node_id));
+    let _s = StatRecorder::new(ccx, ccx.tcx().item_path_str(instance.def));
     debug!("trans_instance(instance={:?})", instance);
     let _icx = push_ctxt("trans_instance");
 
-    let item = ccx.tcx().map.find(fn_node_id).unwrap();
-
     let fn_ty = ccx.tcx().lookup_item_type(instance.def).ty;
     let fn_ty = ccx.tcx().erase_regions(&fn_ty);
-    let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &fn_ty);
+    let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);
 
     let sig = ccx.tcx().erase_late_bound_regions(fn_ty.fn_sig());
     let sig = ccx.tcx().normalize_associated_type(&sig);
     let abi = fn_ty.fn_abi();
 
-    let lldecl = match ccx.instances().borrow().get(&local_instance) {
+    let lldecl = match ccx.instances().borrow().get(&instance) {
         Some(&val) => val,
         None => bug!("Instance `{:?}` not already declared", instance)
     };
 
-    match item {
-        hir_map::NodeItem(&hir::Item {
-            node: hir::ItemFn(ref decl, _, _, _, _, ref body), ..
-        }) |
-        hir_map::NodeTraitItem(&hir::TraitItem {
-            node: hir::MethodTraitItem(
-                hir::MethodSig { ref decl, .. }, Some(ref body)), ..
-        }) |
-        hir_map::NodeImplItem(&hir::ImplItem {
-            node: hir::ImplItemKind::Method(
-                hir::MethodSig { ref decl, .. }, ref body), ..
-        }) => {
-            trans_closure(ccx, decl, body, lldecl, instance,
-                          fn_node_id, &sig, abi, closure::ClosureEnv::NotClosure);
-        }
-        _ => bug!("Instance is a {:?}?", item)
-    }
-}
-
-pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
-                                                 ctor_ty: Ty<'tcx>,
-                                                 disr: Disr,
-                                                 args: CallArgs,
-                                                 dest: expr::Dest,
-                                                 debug_loc: DebugLoc)
-                                                 -> Result<'blk, 'tcx> {
-
-    let ccx = bcx.fcx.ccx;
-
-    let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig());
-    let sig = ccx.tcx().normalize_associated_type(&sig);
-    let result_ty = sig.output;
-
-    // Get location to store the result. If the user does not care about
-    // the result, just make a stack slot
-    let llresult = match dest {
-        expr::SaveIn(d) => d,
-        expr::Ignore => {
-            if !type_is_zero_size(ccx, result_ty) {
-                let llresult = alloc_ty(bcx, result_ty, "constructor_result");
-                call_lifetime_start(bcx, llresult);
-                llresult
-            } else {
-                C_undef(type_of::type_of(ccx, result_ty).ptr_to())
-            }
-        }
-    };
-
-    if !type_is_zero_size(ccx, result_ty) {
-        match args {
-            ArgExprs(exprs) => {
-                let fields = exprs.iter().map(|x| &**x).enumerate().collect::<Vec<_>>();
-                bcx = expr::trans_adt(bcx,
-                                      result_ty,
-                                      disr,
-                                      &fields[..],
-                                      None,
-                                      expr::SaveIn(llresult),
-                                      debug_loc);
-            }
-            _ => bug!("expected expr as arguments for variant/struct tuple constructor"),
-        }
-    } else {
-        // Just eval all the expressions (if any). Since expressions in Rust can have arbitrary
-        // contents, there could be side-effects we need from them.
-        match args {
-            ArgExprs(exprs) => {
-                for expr in exprs {
-                    bcx = expr::trans_into(bcx, expr, expr::Ignore);
-                }
-            }
-            _ => (),
-        }
-    }
-
-    // If the caller doesn't care about the result
-    // drop the temporary we made
-    let bcx = match dest {
-        expr::SaveIn(_) => bcx,
-        expr::Ignore => {
-            let bcx = glue::drop_ty(bcx, llresult, result_ty, debug_loc);
-            if !type_is_zero_size(ccx, result_ty) {
-                call_lifetime_end(bcx, llresult);
-            }
-            bcx
-        }
-    };
-
-    Result::new(bcx, llresult)
+    trans_closure(ccx, lldecl, instance, &sig, abi);
 }
 
 pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                 ctor_id: ast::NodeId,
+                                 def_id: DefId,
+                                 substs: &'tcx Substs<'tcx>,
                                  disr: Disr,
-                                 param_substs: &'tcx Substs<'tcx>,
                                  llfndecl: ValueRef) {
-    let ctor_ty = ccx.tcx().node_id_to_type(ctor_id);
-    let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &ctor_ty);
+    attributes::inline(llfndecl, attributes::InlineAttr::Hint);
+    attributes::set_frame_pointer_elimination(ccx, llfndecl);
+
+    let ctor_ty = ccx.tcx().lookup_item_type(def_id).ty;
+    let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty);
 
     let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig());
     let sig = ccx.tcx().normalize_associated_type(&sig);
@@ -2037,12 +1160,10 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let (arena, fcx): (TypedArena<_>, FunctionContext);
     arena = TypedArena::new();
     fcx = FunctionContext::new(ccx, llfndecl, fn_ty, None, &arena);
-    let bcx = fcx.init(false, None);
-
-    assert!(!fcx.needs_ret_allocas);
+    let bcx = fcx.init(false);
 
     if !fcx.fn_ty.ret.is_ignore() {
-        let dest = fcx.get_ret_slot(bcx, "eret_slot");
+        let dest = fcx.llretslotptr.get().unwrap();
         let dest_val = adt::MaybeSizedValue::sized(dest); // Can return unsized value
         let repr = adt::represent_type(ccx, sig.output);
         let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
@@ -2055,8 +1176,8 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             if common::type_is_fat_ptr(bcx.tcx(), arg_ty) {
                 let meta = &fcx.fn_ty.args[arg_idx];
                 arg_idx += 1;
-                arg.store_fn_arg(b, &mut llarg_idx, expr::get_dataptr(bcx, lldestptr));
-                meta.store_fn_arg(b, &mut llarg_idx, expr::get_meta(bcx, lldestptr));
+                arg.store_fn_arg(b, &mut llarg_idx, get_dataptr(bcx, lldestptr));
+                meta.store_fn_arg(b, &mut llarg_idx, get_meta(bcx, lldestptr));
             } else {
                 arg.store_fn_arg(b, &mut llarg_idx, lldestptr);
             }
@@ -2132,7 +1253,7 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) {
         return;
     }
 
-    let main_llfn = Callee::def(ccx, main_def_id, instance.substs).reify(ccx).val;
+    let main_llfn = Callee::def(ccx, main_def_id, instance.substs).reify(ccx);
 
     let et = ccx.sess().entry_type.get().unwrap();
     match et {
@@ -2174,7 +1295,7 @@ fn create_entry_fn(ccx: &CrateContext,
                     Err(s) => ccx.sess().fatal(&s)
                 };
                 let empty_substs = Substs::empty(ccx.tcx());
-                let start_fn = Callee::def(ccx, start_def_id, empty_substs).reify(ccx).val;
+                let start_fn = Callee::def(ccx, start_def_id, empty_substs).reify(ccx);
                 let args = {
                     let opaque_rust_main =
                         llvm::LLVMBuildPointerCast(bld,
@@ -2481,7 +1602,8 @@ pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet {
 
 pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              mir_map: &MirMap<'tcx>,
-                             analysis: ty::CrateAnalysis)
+                             analysis: ty::CrateAnalysis,
+                             incremental_hashes_map: &IncrementalHashesMap)
                              -> CrateTranslation {
     let _task = tcx.dep_graph.in_task(DepNode::TransCrate);
 
@@ -2500,13 +1622,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         tcx.sess.opts.debug_assertions
     };
 
-    let check_dropflag = if let Some(v) = tcx.sess.opts.debugging_opts.force_dropflag_checks {
-        v
-    } else {
-        tcx.sess.opts.debug_assertions
-    };
-
-    let link_meta = link::build_link_meta(tcx, name);
+    let link_meta = link::build_link_meta(incremental_hashes_map, name);
 
     let shared_ccx = SharedCrateContext::new(tcx,
                                              &mir_map,
@@ -2514,8 +1630,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                              Sha256::new(),
                                              link_meta.clone(),
                                              reachable,
-                                             check_overflow,
-                                             check_dropflag);
+                                             check_overflow);
     // Translate the metadata.
     let metadata = time(tcx.sess.time_passes(), "write metadata", || {
         write_metadata(&shared_ccx, shared_ccx.reachable())
@@ -2629,10 +1744,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         println!("n_null_glues: {}", stats.n_null_glues.get());
         println!("n_real_glues: {}", stats.n_real_glues.get());
 
-        println!("n_fallback_instantiations: {}", stats.n_fallback_instantiations.get());
-
         println!("n_fns: {}", stats.n_fns.get());
-        println!("n_monos: {}", stats.n_monos.get());
         println!("n_inlines: {}", stats.n_inlines.get());
         println!("n_closures: {}", stats.n_closures.get());
         println!("fn stats:");
@@ -2782,7 +1894,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
     };
 
     let codegen_units = time(time_passes, "codegen unit partitioning", || {
-        partitioning::partition(scx.tcx(),
+        partitioning::partition(scx,
                                 items.iter().cloned(),
                                 strategy,
                                 &inlining_map,
@@ -2801,7 +1913,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
     }
 
     if scx.sess().opts.debugging_opts.print_trans_items.is_some() {
-        let mut item_to_cgus = HashMap::new();
+        let mut item_to_cgus = FnvHashMap();
 
         for cgu in &codegen_units {
             for (&trans_item, &linkage) in cgu.items() {
diff --git a/src/librustc_trans/cabi_mips64.rs b/src/librustc_trans/cabi_mips64.rs
new file mode 100644 (file)
index 0000000..e92ef1e
--- /dev/null
@@ -0,0 +1,168 @@
+// 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.
+
+#![allow(non_upper_case_globals)]
+
+use libc::c_uint;
+use std::cmp;
+use llvm;
+use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
+use abi::{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")
+    }
+}
+
+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")
+    }
+}
+
+fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
+    if is_reg_ty(ret.ty) {
+        ret.extend_integer_width_to(64);
+    } else {
+        ret.make_indirect(ccx);
+    }
+}
+
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
+    let orig_offset = *offset;
+    let size = ty_size(arg.ty) * 8;
+    let mut align = ty_align(arg.ty);
+
+    align = cmp::min(cmp::max(align, 4), 8);
+    *offset = align_up_to(*offset, align);
+    *offset += align_up_to(size, align * 8) / 8;
+
+    if !is_reg_ty(arg.ty) {
+        arg.cast = Some(struct_ty(ccx, arg.ty));
+        arg.pad = padding_ty(ccx, align, orig_offset);
+    } else {
+        arg.extend_integer_width_to(64);
+    }
+}
+
+fn is_reg_ty(ty: Type) -> bool {
+    return match ty.kind() {
+        Integer
+        | Pointer
+        | Float
+        | Double
+        | Vector => true,
+        _ => false
+    };
+}
+
+fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
+    if ((align - 1 ) & offset) > 0 {
+        Some(Type::i64(ccx))
+    } else {
+        None
+    }
+}
+
+fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
+    let int_ty = Type::i64(ccx);
+    let mut args = Vec::new();
+
+    let mut n = size / 64;
+    while n > 0 {
+        args.push(int_ty);
+        n -= 1;
+    }
+
+    let r = size % 64;
+    if r > 0 {
+        unsafe {
+            args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
+        }
+    }
+
+    args
+}
+
+fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
+    let size = ty_size(ty) * 8;
+    Type::struct_(ccx, &coerce_to_int(ccx, size), false)
+}
+
+pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(ccx, &mut fty.ret);
+    }
+
+    let mut offset = if fty.ret.is_indirect() { 8 } else { 0 };
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        classify_arg_ty(ccx, arg, &mut offset);
+    }
+}
index efbdce67a8b2ad911cd837b3d016a20be58cce46..e05c31b1d88cdce6d187d3cbfa132f1b27a86381 100644 (file)
@@ -28,11 +28,7 @@ fn align(off: usize, ty: Type) -> usize {
 
 fn ty_align(ty: Type) -> usize {
     match ty.kind() {
-        Integer => {
-            unsafe {
-                ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as usize) + 7) / 8
-            }
-        }
+        Integer => ((ty.int_width() as usize) + 7) / 8,
         Pointer => 4,
         Float => 4,
         Double => 8,
@@ -54,11 +50,7 @@ fn ty_align(ty: Type) -> usize {
 
 fn ty_size(ty: Type) -> usize {
     match ty.kind() {
-        Integer => {
-            unsafe {
-                ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as usize) + 7) / 8
-            }
-        }
+        Integer => ((ty.int_width() as usize) + 7) / 8,
         Pointer => 4,
         Float => 4,
         Double => 8,
index d50959b5ab3023d9cfaf99bec87929f8580dc6e6..33cacbe194bb0ee1c66bcdcf59d4252076546aa3 100644 (file)
 //! closure.
 
 pub use self::CalleeData::*;
-pub use self::CallArgs::*;
 
 use arena::TypedArena;
 use back::symbol_names;
 use llvm::{self, ValueRef, get_params};
-use middle::cstore::LOCAL_CRATE;
 use rustc::hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::traits;
-use rustc::hir::map as hir_map;
 use abi::{Abi, FnType};
-use adt;
 use attributes;
 use base;
 use base::*;
 use build::*;
-use cleanup;
-use cleanup::CleanupMethods;
 use closure;
-use common::{self, Block, Result, CrateContext, FunctionContext, C_undef};
+use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext};
 use consts;
-use datum::*;
 use debuginfo::DebugLoc;
 use declare;
-use expr;
-use glue;
-use inline;
-use intrinsic;
-use machine::llalign_of_min;
 use meth;
 use monomorphize::{self, Instance};
 use trans_item::TransItem;
-use type_::Type;
 use type_of;
-use value::Value;
 use Disr;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Ty, TypeFoldable};
 use rustc::hir;
 
 use syntax_pos::DUMMY_SP;
-use errors;
-use syntax::ptr::P;
 
 #[derive(Debug)]
 pub enum CalleeData {
@@ -80,10 +64,10 @@ pub struct Callee<'tcx> {
 
 impl<'tcx> Callee<'tcx> {
     /// Function pointer.
-    pub fn ptr(datum: Datum<'tcx, Rvalue>) -> Callee<'tcx> {
+    pub fn ptr(llfn: ValueRef, ty: Ty<'tcx>) -> Callee<'tcx> {
         Callee {
-            data: Fn(datum.val),
-            ty: datum.ty
+            data: Fn(llfn),
+            ty: ty
         }
     }
 
@@ -113,32 +97,28 @@ pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>,
             return Callee::trait_method(ccx, trait_id, def_id, substs);
         }
 
-        let maybe_node_id = inline::get_local_instance(ccx, def_id)
-            .and_then(|def_id| tcx.map.as_local_node_id(def_id));
-        let maybe_ast_node = maybe_node_id.and_then(|node_id| {
-            tcx.map.find(node_id)
-        });
-
-        let data = match maybe_ast_node {
-            Some(hir_map::NodeStructCtor(_)) => {
-                NamedTupleConstructor(Disr(0))
-            }
-            Some(hir_map::NodeVariant(_)) => {
-                let vinfo = common::inlined_variant_def(ccx, maybe_node_id.unwrap());
-                NamedTupleConstructor(Disr::from(vinfo.disr_val))
+        let fn_ty = def_ty(ccx.shared(), def_id, substs);
+        if let ty::TyFnDef(_, _, f) = fn_ty.sty {
+            if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic {
+                return Callee {
+                    data: Intrinsic,
+                    ty: fn_ty
+                };
             }
-            Some(hir_map::NodeForeignItem(fi)) if {
-                let abi = tcx.map.get_foreign_abi(fi.id);
-                abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic
-            } => Intrinsic,
-
-            _ => return Callee::ptr(get_fn(ccx, def_id, substs))
-        };
+        }
 
-        Callee {
-            data: data,
-            ty: def_ty(tcx, def_id, substs)
+        // FIXME(eddyb) Detect ADT constructors more efficiently.
+        if let Some(adt_def) = fn_ty.fn_ret().skip_binder().ty_adt_def() {
+            if let Some(v) = adt_def.variants.iter().find(|v| def_id == v.did) {
+                return Callee {
+                    data: NamedTupleConstructor(Disr::from(v.disr_val)),
+                    ty: fn_ty
+                };
+            }
         }
+
+        let (llfn, ty) = get_fn(ccx, def_id, substs);
+        Callee::ptr(llfn, ty)
     }
 
     /// Trait method, which has to be resolved to an impl method.
@@ -163,7 +143,8 @@ pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>,
                 // That is because default methods have the same ID as the
                 // trait method used to look up the impl method that ended
                 // up here, so calling Callee::def would infinitely recurse.
-                Callee::ptr(get_fn(ccx, mth.method.def_id, mth.substs))
+                let (llfn, ty) = get_fn(ccx, mth.method.def_id, mth.substs);
+                Callee::ptr(llfn, ty)
             }
             traits::VtableClosure(vtable_closure) => {
                 // The substitutions should have no type parameters remaining
@@ -174,30 +155,20 @@ pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>,
                                                          vtable_closure.substs,
                                                          trait_closure_kind);
 
-                let method_ty = def_ty(tcx, def_id, substs);
-                let fn_ptr_ty = match method_ty.sty {
-                    ty::TyFnDef(_, _, fty) => tcx.mk_fn_ptr(fty),
-                    _ => bug!("expected fn item type, found {}",
-                              method_ty)
-                };
-                Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
+                let method_ty = def_ty(ccx.shared(), def_id, substs);
+                Callee::ptr(llfn, method_ty)
             }
             traits::VtableFnPointer(vtable_fn_pointer) => {
                 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
                 let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, vtable_fn_pointer.fn_ty);
 
-                let method_ty = def_ty(tcx, def_id, substs);
-                let fn_ptr_ty = match method_ty.sty {
-                    ty::TyFnDef(_, _, fty) => tcx.mk_fn_ptr(fty),
-                    _ => bug!("expected fn item type, found {}",
-                              method_ty)
-                };
-                Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
+                let method_ty = def_ty(ccx.shared(), def_id, substs);
+                Callee::ptr(llfn, method_ty)
             }
             traits::VtableObject(ref data) => {
                 Callee {
                     data: Virtual(tcx.get_vtable_index_of_object_method(data, def_id)),
-                    ty: def_ty(tcx, def_id, substs)
+                    ty: def_ty(ccx.shared(), def_id, substs)
                 }
             }
             vtable => {
@@ -236,30 +207,34 @@ pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
     /// function.
     pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>,
                           debug_loc: DebugLoc,
-                          args: CallArgs<'a, 'tcx>,
-                          dest: Option<expr::Dest>)
+                          args: &[ValueRef],
+                          dest: Option<ValueRef>)
                           -> Result<'blk, 'tcx> {
         trans_call_inner(bcx, debug_loc, self, args, dest)
     }
 
     /// Turn the callee into a function pointer.
-    pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>)
-                     -> Datum<'tcx, Rvalue> {
-        let fn_ptr_ty = match self.ty.sty {
-            ty::TyFnDef(_, _, f) => ccx.tcx().mk_fn_ptr(f),
-            _ => self.ty
-        };
+    pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
         match self.data {
-            Fn(llfn) => {
-                immediate_rvalue(llfn, fn_ptr_ty)
-            }
+            Fn(llfn) => llfn,
             Virtual(idx) => {
-                let llfn = meth::trans_object_shim(ccx, self.ty, idx);
-                immediate_rvalue(llfn, fn_ptr_ty)
+                meth::trans_object_shim(ccx, self.ty, idx)
             }
-            NamedTupleConstructor(_) => match self.ty.sty {
+            NamedTupleConstructor(disr) => match self.ty.sty {
                 ty::TyFnDef(def_id, substs, _) => {
-                    return get_fn(ccx, def_id, substs);
+                    let instance = Instance::new(def_id, substs);
+                    if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
+                        return llfn;
+                    }
+
+                    let sym = ccx.symbol_map().get_or_compute(ccx.shared(),
+                                                              TransItem::Fn(instance));
+                    assert!(!ccx.codegen_unit().contains_item(&TransItem::Fn(instance)));
+                    let lldecl = declare::define_internal_fn(ccx, &sym, self.ty);
+                    base::trans_ctor_shim(ccx, def_id, substs, disr, lldecl);
+                    ccx.instances().borrow_mut().insert(instance, lldecl);
+
+                    lldecl
                 }
                 _ => bug!("expected fn item type, found {}", self.ty)
             },
@@ -269,12 +244,12 @@ pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>)
 }
 
 /// Given a DefId and some Substs, produces the monomorphic item type.
-fn def_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
                     def_id: DefId,
                     substs: &'tcx Substs<'tcx>)
                     -> Ty<'tcx> {
-    let ty = tcx.lookup_item_type(def_id).ty;
-    monomorphize::apply_param_substs(tcx, substs, &ty)
+    let ty = shared.tcx().lookup_item_type(def_id).ty;
+    monomorphize::apply_param_substs(shared, substs, &ty)
 }
 
 /// Translates an adapter that implements the `Fn` trait for a fn
@@ -310,7 +285,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
     let llfnpointer = match bare_fn_ty.sty {
         ty::TyFnDef(def_id, substs, _) => {
             // Function definitions have to be turned into a pointer.
-            let llfn = Callee::def(ccx, def_id, substs).reify(ccx).val;
+            let llfn = Callee::def(ccx, def_id, substs).reify(ccx);
             if !is_by_ref {
                 // A by-value fn item is ignored, so the shim has
                 // the same signature as the original function.
@@ -380,7 +355,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
     let (block_arena, fcx): (TypedArena<_>, FunctionContext);
     block_arena = TypedArena::new();
     fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &block_arena);
-    let mut bcx = fcx.init(false, None);
+    let mut bcx = fcx.init(false);
 
     let llargs = get_params(fcx.llfn);
 
@@ -394,17 +369,13 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
         }
     });
 
-    assert!(!fcx.needs_ret_allocas);
-
-    let dest = fcx.llretslotptr.get().map(|_|
-        expr::SaveIn(fcx.get_ret_slot(bcx, "ret_slot"))
-    );
+    let dest = fcx.llretslotptr.get();
 
     let callee = Callee {
         data: Fn(llfnpointer),
         ty: bare_fn_ty
     };
-    bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
+    bcx = callee.call(bcx, DebugLoc::None, &llargs[(self_idx + 1)..], dest).bcx;
 
     fcx.finish(bcx, DebugLoc::None);
 
@@ -424,90 +395,27 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
 fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                     def_id: DefId,
                     substs: &'tcx Substs<'tcx>)
-                    -> Datum<'tcx, Rvalue> {
+                    -> (ValueRef, Ty<'tcx>) {
     let tcx = ccx.tcx();
 
     debug!("get_fn(def_id={:?}, substs={:?})", def_id, substs);
 
-    assert!(!substs.types.needs_infer());
-    assert!(!substs.types.has_escaping_regions());
-
-    // Check whether this fn has an inlined copy and, if so, redirect
-    // def_id to the local id of the inlined copy.
-    let def_id = inline::maybe_instantiate_inline(ccx, def_id);
-
-    fn is_named_tuple_constructor(tcx: TyCtxt, def_id: DefId) -> bool {
-        let node_id = match tcx.map.as_local_node_id(def_id) {
-            Some(n) => n,
-            None => { return false; }
-        };
-        let map_node = errors::expect(
-            &tcx.sess.diagnostic(),
-            tcx.map.find(node_id),
-            || "local item should be in ast map".to_string());
-
-        match map_node {
-            hir_map::NodeVariant(v) => {
-                v.node.data.is_tuple()
-            }
-            hir_map::NodeStructCtor(_) => true,
-            _ => false
-        }
-    }
-    let must_monomorphise =
-        !substs.types.is_empty() || is_named_tuple_constructor(tcx, def_id);
-
-    debug!("get_fn({:?}) must_monomorphise: {}",
-           def_id, must_monomorphise);
-
-    // Create a monomorphic version of generic functions
-    if must_monomorphise {
-        // Should be either intra-crate or inlined.
-        assert_eq!(def_id.krate, LOCAL_CRATE);
-
-        let substs = tcx.normalize_associated_type(&substs);
-        let (val, fn_ty) = monomorphize::monomorphic_fn(ccx, def_id, substs);
-        let fn_ptr_ty = match fn_ty.sty {
-            ty::TyFnDef(_, _, fty) => {
-                // Create a fn pointer with the substituted signature.
-                tcx.mk_fn_ptr(fty)
-            }
-            _ => bug!("expected fn item type, found {}", fn_ty)
-        };
-        assert_eq!(type_of::type_of(ccx, fn_ptr_ty), common::val_ty(val));
-        return immediate_rvalue(val, fn_ptr_ty);
-    }
+    assert!(!substs.needs_infer());
+    assert!(!substs.has_escaping_regions());
+    assert!(!substs.has_param_types());
 
-    // Find the actual function pointer.
-    let ty = ccx.tcx().lookup_item_type(def_id).ty;
-    let fn_ptr_ty = match ty.sty {
-        ty::TyFnDef(_, _, ref fty) => {
-            // Create a fn pointer with the normalized signature.
-            tcx.mk_fn_ptr(tcx.normalize_associated_type(fty))
-        }
-        _ => bug!("expected fn item type, found {}", ty)
-    };
+    let substs = tcx.normalize_associated_type(&substs);
+    let instance = Instance::new(def_id, substs);
+    let item_ty = ccx.tcx().lookup_item_type(def_id).ty;
+    let fn_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &item_ty);
 
-    let instance = Instance::mono(ccx.shared(), def_id);
     if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
-        return immediate_rvalue(llfn, fn_ptr_ty);
+        return (llfn, fn_ty);
     }
 
-    let local_id = ccx.tcx().map.as_local_node_id(def_id);
-    let local_item = match local_id.and_then(|id| tcx.map.find(id)) {
-        Some(hir_map::NodeItem(&hir::Item {
-            span, node: hir::ItemFn(..), ..
-        })) |
-        Some(hir_map::NodeTraitItem(&hir::TraitItem {
-            span, node: hir::MethodTraitItem(_, Some(_)), ..
-        })) |
-        Some(hir_map::NodeImplItem(&hir::ImplItem {
-            span, node: hir::ImplItemKind::Method(..), ..
-        })) => {
-            Some(span)
-        }
-        _ => None
-    };
+    let sym = ccx.symbol_map().get_or_compute(ccx.shared(),
+                                              TransItem::Fn(instance));
+    debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym);
 
     // This is subtle and surprising, but sometimes we have to bitcast
     // the resulting fn pointer.  The reason has to do with external
@@ -533,23 +441,17 @@ fn is_named_tuple_constructor(tcx: TyCtxt, def_id: DefId) -> bool {
     // reference. It also occurs when testing libcore and in some
     // other weird situations. Annoying.
 
-    let sym = ccx.symbol_map().get_or_compute(ccx.shared(),
-                                              TransItem::Fn(instance));
-
-    let llptrty = type_of::type_of(ccx, fn_ptr_ty);
-    let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
-        if let Some(span) = local_item {
-            if declare::get_defined_value(ccx, &sym).is_some() {
-                ccx.sess().span_fatal(span,
-                    &format!("symbol `{}` is already defined", &sym));
-            }
+    let fn_ptr_ty = match fn_ty.sty {
+        ty::TyFnDef(_, _, fty) => {
+            // Create a fn pointer with the substituted signature.
+            tcx.mk_fn_ptr(fty)
         }
+        _ => bug!("expected fn item type, found {}", fn_ty)
+    };
+    let llptrty = type_of::type_of(ccx, fn_ptr_ty);
 
+    let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
         if common::val_ty(llfn) != llptrty {
-            if local_item.is_some() {
-                bug!("symbol `{}` previously declared as {:?}, now wanted as {:?}",
-                     sym, Value(llfn), llptrty);
-            }
             debug!("get_fn: casting {:?} to {:?}", llfn, llptrty);
             consts::ptrcast(llfn, llptrty)
         } else {
@@ -557,15 +459,21 @@ fn is_named_tuple_constructor(tcx: TyCtxt, def_id: DefId) -> bool {
             llfn
         }
     } else {
-        let llfn = declare::declare_fn(ccx, &sym, ty);
+        let llfn = declare::declare_fn(ccx, &sym, fn_ty);
         assert_eq!(common::val_ty(llfn), llptrty);
         debug!("get_fn: not casting pointer!");
 
         let attrs = ccx.tcx().get_attrs(def_id);
         attributes::from_fn_attrs(ccx, &attrs, llfn);
-        if local_item.is_some() {
+
+        let is_local_def = ccx.shared().translation_items().borrow()
+                              .contains(&TransItem::Fn(instance));
+        if is_local_def {
             // FIXME(eddyb) Doubt all extern fn should allow unwinding.
             attributes::unwind(llfn, true);
+            unsafe {
+                llvm::LLVMSetLinkage(llfn, llvm::ExternalLinkage);
+            }
         }
 
         llfn
@@ -573,17 +481,17 @@ fn is_named_tuple_constructor(tcx: TyCtxt, def_id: DefId) -> bool {
 
     ccx.instances().borrow_mut().insert(instance, llfn);
 
-    immediate_rvalue(llfn, fn_ptr_ty)
+    (llfn, fn_ty)
 }
 
 // ______________________________________________________________________
 // Translating calls
 
-fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
+fn trans_call_inner<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                     debug_loc: DebugLoc,
                                     callee: Callee<'tcx>,
-                                    args: CallArgs<'a, 'tcx>,
-                                    dest: Option<expr::Dest>)
+                                    args: &[ValueRef],
+                                    opt_llretslot: Option<ValueRef>)
                                     -> Result<'blk, 'tcx> {
     // Introduce a temporary cleanup scope that will contain cleanups
     // for the arguments while they are being evaluated. The purpose
@@ -595,65 +503,16 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
     let fcx = bcx.fcx;
     let ccx = fcx.ccx;
 
-    let abi = callee.ty.fn_abi();
-    let sig = callee.ty.fn_sig();
-    let output = bcx.tcx().erase_late_bound_regions(&sig.output());
-    let output = bcx.tcx().normalize_associated_type(&output);
-
-    let extra_args = match args {
-        ArgExprs(args) if abi != Abi::RustCall => {
-            args[sig.0.inputs.len()..].iter().map(|expr| {
-                common::expr_ty_adjusted(bcx, expr)
-            }).collect()
-        }
-        _ => vec![]
-    };
-    let fn_ty = callee.direct_fn_type(ccx, &extra_args);
+    let fn_ret = callee.ty.fn_ret();
+    let fn_ty = callee.direct_fn_type(ccx, &[]);
 
     let mut callee = match callee.data {
-        Intrinsic => {
-            assert!(abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic);
-            assert!(dest.is_some());
-
-            return intrinsic::trans_intrinsic_call(bcx, callee.ty, &fn_ty,
-                                                   args, dest.unwrap(),
-                                                   debug_loc);
-        }
-        NamedTupleConstructor(disr) => {
-            assert!(dest.is_some());
-
-            return base::trans_named_tuple_constructor(bcx,
-                                                       callee.ty,
-                                                       disr,
-                                                       args,
-                                                       dest.unwrap(),
-                                                       debug_loc);
+        NamedTupleConstructor(_) | Intrinsic => {
+            bug!("{:?} calls should not go through Callee::call", callee);
         }
         f => f
     };
 
-    // Generate a location to store the result. If the user does
-    // not care about the result, just make a stack slot.
-    let opt_llretslot = dest.and_then(|dest| match dest {
-        expr::SaveIn(dst) => Some(dst),
-        expr::Ignore => {
-            let needs_drop = || bcx.fcx.type_needs_drop(output);
-            if fn_ty.ret.is_indirect() || fn_ty.ret.cast.is_some() || needs_drop() {
-                // Push the out-pointer if we use an out-pointer for this
-                // return type, otherwise push "undef".
-                if fn_ty.ret.is_ignore() {
-                    Some(C_undef(fn_ty.ret.original_ty.ptr_to()))
-                } else {
-                    let llresult = alloca(bcx, fn_ty.ret.original_ty, "__llret");
-                    call_lifetime_start(bcx, llresult);
-                    Some(llresult)
-                }
-            } else {
-                None
-            }
-        }
-    });
-
     // If there no destination, return must be direct, with no cast.
     if opt_llretslot.is_none() {
         assert!(!fn_ty.ret.is_indirect() && fn_ty.ret.cast.is_none());
@@ -669,17 +528,24 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         llargs.push(llretslot);
     }
 
-    let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
-    bcx = trans_args(bcx, abi, &fn_ty, &mut callee, args, &mut llargs,
-                     cleanup::CustomScope(arg_cleanup_scope));
-    fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
+    match callee {
+        Virtual(idx) => {
+            llargs.push(args[0]);
+
+            let fn_ptr = meth::get_virtual_method(bcx, args[1], idx);
+            let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
+            callee = Fn(PointerCast(bcx, fn_ptr, llty));
+            llargs.extend_from_slice(&args[2..]);
+        }
+        _ => llargs.extend_from_slice(args)
+    }
 
     let llfn = match callee {
         Fn(f) => f,
         _ => bug!("expected fn pointer callee, found {:?}", callee)
     };
 
-    let (llret, mut bcx) = base::invoke(bcx, llfn, &llargs, debug_loc);
+    let (llret, bcx) = base::invoke(bcx, llfn, &llargs, debug_loc);
     if !bcx.unreachable.get() {
         fn_ty.apply_attrs_callsite(llret);
 
@@ -695,283 +561,9 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         }
     }
 
-    fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_cleanup_scope);
-
-    // If the caller doesn't care about the result of this fn call,
-    // drop the temporary slot we made.
-    match (dest, opt_llretslot) {
-        (Some(expr::Ignore), Some(llretslot)) => {
-            // drop the value if it is not being saved.
-            bcx = glue::drop_ty(bcx, llretslot, output, debug_loc);
-            call_lifetime_end(bcx, llretslot);
-        }
-        _ => {}
-    }
-
-    // FIXME(canndrew): This is_never should really be an is_uninhabited
-    if output.is_never() {
+    if fn_ret.0.is_never() {
         Unreachable(bcx);
     }
 
     Result::new(bcx, llret)
 }
-
-pub enum CallArgs<'a, 'tcx> {
-    /// Supply value of arguments as a list of expressions that must be
-    /// translated. This is used in the common case of `foo(bar, qux)`.
-    ArgExprs(&'a [P<hir::Expr>]),
-
-    /// Supply value of arguments as a list of LLVM value refs; frequently
-    /// used with lang items and so forth, when the argument is an internal
-    /// value.
-    ArgVals(&'a [ValueRef]),
-
-    /// For overloaded operators: `(lhs, Option(rhs))`.
-    /// `lhs` is the left-hand-side and `rhs` is the datum
-    /// of the right-hand-side argument (if any).
-    ArgOverloadedOp(Datum<'tcx, Expr>, Option<Datum<'tcx, Expr>>),
-
-    /// Supply value of arguments as a list of expressions that must be
-    /// translated, for overloaded call operators.
-    ArgOverloadedCall(Vec<&'a hir::Expr>),
-}
-
-fn trans_args_under_call_abi<'blk, 'tcx>(
-                             mut bcx: Block<'blk, 'tcx>,
-                             arg_exprs: &[P<hir::Expr>],
-                             callee: &mut CalleeData,
-                             fn_ty: &FnType,
-                             llargs: &mut Vec<ValueRef>,
-                             arg_cleanup_scope: cleanup::ScopeId)
-                             -> Block<'blk, 'tcx>
-{
-    let mut arg_idx = 0;
-
-    // Translate the `self` argument first.
-    let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0]));
-    bcx = trans_arg_datum(bcx,
-                          arg_datum,
-                          callee, fn_ty, &mut arg_idx,
-                          arg_cleanup_scope,
-                          llargs);
-
-    // Now untuple the rest of the arguments.
-    let tuple_expr = &arg_exprs[1];
-    let tuple_type = common::node_id_type(bcx, tuple_expr.id);
-
-    match tuple_type.sty {
-        ty::TyTuple(ref field_types) => {
-            let tuple_datum = unpack_datum!(bcx,
-                                            expr::trans(bcx, &tuple_expr));
-            let tuple_lvalue_datum =
-                unpack_datum!(bcx,
-                              tuple_datum.to_lvalue_datum(bcx,
-                                                          "args",
-                                                          tuple_expr.id));
-            let repr = adt::represent_type(bcx.ccx(), tuple_type);
-            let repr_ptr = &repr;
-            for (i, field_type) in field_types.iter().enumerate() {
-                let arg_datum = tuple_lvalue_datum.get_element(
-                    bcx,
-                    field_type,
-                    |srcval| {
-                        adt::trans_field_ptr(bcx, repr_ptr, srcval, Disr(0), i)
-                    }).to_expr_datum();
-                bcx = trans_arg_datum(bcx,
-                                      arg_datum,
-                                      callee, fn_ty, &mut arg_idx,
-                                      arg_cleanup_scope,
-                                      llargs);
-            }
-        }
-        _ => {
-            span_bug!(tuple_expr.span,
-                      "argument to `.call()` wasn't a tuple?!")
-        }
-    };
-
-    bcx
-}
-
-pub fn trans_args<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                  abi: Abi,
-                                  fn_ty: &FnType,
-                                  callee: &mut CalleeData,
-                                  args: CallArgs<'a, 'tcx>,
-                                  llargs: &mut Vec<ValueRef>,
-                                  arg_cleanup_scope: cleanup::ScopeId)
-                                  -> Block<'blk, 'tcx> {
-    debug!("trans_args(abi={})", abi);
-
-    let _icx = push_ctxt("trans_args");
-
-    let mut bcx = bcx;
-    let mut arg_idx = 0;
-
-    // First we figure out the caller's view of the types of the arguments.
-    // This will be needed if this is a generic call, because the callee has
-    // to cast her view of the arguments to the caller's view.
-    match args {
-        ArgExprs(arg_exprs) => {
-            if abi == Abi::RustCall {
-                // This is only used for direct calls to the `call`,
-                // `call_mut` or `call_once` functions.
-                return trans_args_under_call_abi(bcx,
-                                                 arg_exprs, callee, fn_ty,
-                                                 llargs,
-                                                 arg_cleanup_scope)
-            }
-
-            for arg_expr in arg_exprs {
-                let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_expr));
-                bcx = trans_arg_datum(bcx,
-                                      arg_datum,
-                                      callee, fn_ty, &mut arg_idx,
-                                      arg_cleanup_scope,
-                                      llargs);
-            }
-        }
-        ArgOverloadedCall(arg_exprs) => {
-            for expr in arg_exprs {
-                let arg_datum =
-                    unpack_datum!(bcx, expr::trans(bcx, expr));
-                bcx = trans_arg_datum(bcx,
-                                      arg_datum,
-                                      callee, fn_ty, &mut arg_idx,
-                                      arg_cleanup_scope,
-                                      llargs);
-            }
-        }
-        ArgOverloadedOp(lhs, rhs) => {
-            bcx = trans_arg_datum(bcx, lhs,
-                                  callee, fn_ty, &mut arg_idx,
-                                  arg_cleanup_scope,
-                                  llargs);
-
-            if let Some(rhs) = rhs {
-                bcx = trans_arg_datum(bcx, rhs,
-                                      callee, fn_ty, &mut arg_idx,
-                                      arg_cleanup_scope,
-                                      llargs);
-            }
-        }
-        ArgVals(vs) => {
-            match *callee {
-                Virtual(idx) => {
-                    llargs.push(vs[0]);
-
-                    let fn_ptr = meth::get_virtual_method(bcx, vs[1], idx);
-                    let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
-                    *callee = Fn(PointerCast(bcx, fn_ptr, llty));
-                    llargs.extend_from_slice(&vs[2..]);
-                }
-                _ => llargs.extend_from_slice(vs)
-            }
-        }
-    }
-
-    bcx
-}
-
-fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                               arg_datum: Datum<'tcx, Expr>,
-                               callee: &mut CalleeData,
-                               fn_ty: &FnType,
-                               next_idx: &mut usize,
-                               arg_cleanup_scope: cleanup::ScopeId,
-                               llargs: &mut Vec<ValueRef>)
-                               -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_arg_datum");
-    let mut bcx = bcx;
-
-    debug!("trans_arg_datum({:?})", arg_datum);
-
-    let arg = &fn_ty.args[*next_idx];
-    *next_idx += 1;
-
-    // Fill padding with undef value, where applicable.
-    if let Some(ty) = arg.pad {
-        llargs.push(C_undef(ty));
-    }
-
-    // Determine whether we want a by-ref datum even if not appropriate.
-    let want_by_ref = arg.is_indirect() || arg.cast.is_some();
-
-    let fat_ptr = common::type_is_fat_ptr(bcx.tcx(), arg_datum.ty);
-    let (by_ref, val) = if fat_ptr && !bcx.fcx.type_needs_drop(arg_datum.ty) {
-        (true, arg_datum.val)
-    } else {
-        // Make this an rvalue, since we are going to be
-        // passing ownership.
-        let arg_datum = unpack_datum!(
-            bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
-
-        // Now that arg_datum is owned, get it into the appropriate
-        // mode (ref vs value).
-        let arg_datum = unpack_datum!(bcx, if want_by_ref {
-            arg_datum.to_ref_datum(bcx)
-        } else {
-            arg_datum.to_appropriate_datum(bcx)
-        });
-
-        // Technically, ownership of val passes to the callee.
-        // However, we must cleanup should we panic before the
-        // callee is actually invoked.
-        (arg_datum.kind.is_by_ref(),
-         arg_datum.add_clean(bcx.fcx, arg_cleanup_scope))
-    };
-
-    if arg.is_ignore() {
-        return bcx;
-    }
-
-    debug!("--- trans_arg_datum passing {:?}", Value(val));
-
-    if fat_ptr {
-        // Fat pointers should be passed without any transformations.
-        assert!(!arg.is_indirect() && arg.cast.is_none());
-        llargs.push(Load(bcx, expr::get_dataptr(bcx, val)));
-
-        let info_arg = &fn_ty.args[*next_idx];
-        *next_idx += 1;
-        assert!(!info_arg.is_indirect() && info_arg.cast.is_none());
-        let info = Load(bcx, expr::get_meta(bcx, val));
-
-        if let Virtual(idx) = *callee {
-            // We have to grab the fn pointer from the vtable when
-            // handling the first argument, ensure that here.
-            assert_eq!(*next_idx, 2);
-            assert!(info_arg.is_ignore());
-            let fn_ptr = meth::get_virtual_method(bcx, info, idx);
-            let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
-            *callee = Fn(PointerCast(bcx, fn_ptr, llty));
-        } else {
-            assert!(!info_arg.is_ignore());
-            llargs.push(info);
-        }
-        return bcx;
-    }
-
-    let mut val = val;
-    if by_ref && !arg.is_indirect() {
-        // Have to load the argument, maybe while casting it.
-        if arg.original_ty == Type::i1(bcx.ccx()) {
-            // We store bools as i8 so we need to truncate to i1.
-            val = LoadRangeAssert(bcx, val, 0, 2, llvm::False);
-            val = Trunc(bcx, val, arg.original_ty);
-        } else if let Some(ty) = arg.cast {
-            val = Load(bcx, PointerCast(bcx, val, ty.ptr_to()));
-            if !bcx.unreachable.get() {
-                let llalign = llalign_of_min(bcx.ccx(), arg.ty);
-                unsafe {
-                    llvm::LLVMSetAlignment(val, llalign);
-                }
-            }
-        } else {
-            val = Load(bcx, val);
-        }
-    }
-
-    llargs.push(val);
-    bcx
-}
index 3081f055bb4dd1065b975e7d99153f1856dd3052..d368ce47430b7e586a96137a5b1418095c95f3e2 100644 (file)
 //! code for `expr` itself is responsible for freeing any other byproducts
 //! that may be in play.
 
-pub use self::ScopeId::*;
-pub use self::CleanupScopeKind::*;
 pub use self::EarlyExitLabel::*;
-pub use self::Heap::*;
 
 use llvm::{BasicBlockRef, ValueRef};
 use base;
 use build;
 use common;
-use common::{Block, FunctionContext, NodeIdAndSpan, LandingPad};
-use datum::{Datum, Lvalue};
-use debuginfo::{DebugLoc, ToDebugLoc};
+use common::{Block, FunctionContext, LandingPad};
+use debuginfo::{DebugLoc};
 use glue;
-use middle::region;
 use type_::Type;
 use value::Value;
-use rustc::ty::{Ty, TyCtxt};
-
-use std::fmt;
-use syntax::ast;
-
-pub struct CleanupScope<'blk, 'tcx: 'blk> {
-    // The id of this cleanup scope. If the id is None,
-    // this is a *temporary scope* that is pushed during trans to
-    // cleanup miscellaneous garbage that trans may generate whose
-    // lifetime is a subset of some expression.  See module doc for
-    // more details.
-    kind: CleanupScopeKind<'blk, 'tcx>,
+use rustc::ty::Ty;
 
+pub struct CleanupScope<'tcx> {
     // Cleanups to run upon scope exit.
-    cleanups: Vec<CleanupObj<'tcx>>,
+    cleanups: Vec<DropValue<'tcx>>,
 
     // The debug location any drop calls generated for this scope will be
     // associated with.
@@ -159,37 +144,9 @@ pub struct CustomScopeIndex {
     index: usize
 }
 
-pub const EXIT_BREAK: usize = 0;
-pub const EXIT_LOOP: usize = 1;
-pub const EXIT_MAX: usize = 2;
-
-pub enum CleanupScopeKind<'blk, 'tcx: 'blk> {
-    CustomScopeKind,
-    AstScopeKind(ast::NodeId),
-    LoopScopeKind(ast::NodeId, [Block<'blk, 'tcx>; EXIT_MAX])
-}
-
-impl<'blk, 'tcx: 'blk> fmt::Debug for CleanupScopeKind<'blk, 'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            CustomScopeKind => write!(f, "CustomScopeKind"),
-            AstScopeKind(nid) => write!(f, "AstScopeKind({})", nid),
-            LoopScopeKind(nid, ref blks) => {
-                write!(f, "LoopScopeKind({}, [", nid)?;
-                for blk in blks {
-                    write!(f, "{:p}, ", blk)?;
-                }
-                write!(f, "])")
-            }
-        }
-    }
-}
-
 #[derive(Copy, Clone, PartialEq, Debug)]
 pub enum EarlyExitLabel {
     UnwindExit(UnwindKind),
-    ReturnExit,
-    LoopExit(ast::NodeId, usize)
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -205,97 +162,8 @@ pub struct CachedEarlyExit {
     last_cleanup: usize,
 }
 
-pub trait Cleanup<'tcx> {
-    fn must_unwind(&self) -> bool;
-    fn is_lifetime_end(&self) -> bool;
-    fn trans<'blk>(&self,
-                   bcx: Block<'blk, 'tcx>,
-                   debug_loc: DebugLoc)
-                   -> Block<'blk, 'tcx>;
-}
-
-pub type CleanupObj<'tcx> = Box<Cleanup<'tcx>+'tcx>;
-
-#[derive(Copy, Clone, Debug)]
-pub enum ScopeId {
-    AstScope(ast::NodeId),
-    CustomScope(CustomScopeIndex)
-}
-
-#[derive(Copy, Clone, Debug)]
-pub struct DropHint<K>(pub ast::NodeId, pub K);
-
-pub type DropHintDatum<'tcx> = DropHint<Datum<'tcx, Lvalue>>;
-pub type DropHintValue = DropHint<ValueRef>;
-
-impl<K> DropHint<K> {
-    pub fn new(id: ast::NodeId, k: K) -> DropHint<K> { DropHint(id, k) }
-}
-
-impl DropHint<ValueRef> {
-    pub fn value(&self) -> ValueRef { self.1 }
-}
-
-pub trait DropHintMethods {
-    type ValueKind;
-    fn to_value(&self) -> Self::ValueKind;
-}
-impl<'tcx> DropHintMethods for DropHintDatum<'tcx> {
-    type ValueKind = DropHintValue;
-    fn to_value(&self) -> DropHintValue { DropHint(self.0, self.1.val) }
-}
-
-impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
-    /// Invoked when we start to trans the code contained within a new cleanup scope.
-    fn push_ast_cleanup_scope(&self, debug_loc: NodeIdAndSpan) {
-        debug!("push_ast_cleanup_scope({})",
-               self.ccx.tcx().map.node_to_string(debug_loc.id));
-
-        // FIXME(#2202) -- currently closure bodies have a parent
-        // region, which messes up the assertion below, since there
-        // are no cleanup scopes on the stack at the start of
-        // trans'ing a closure body.  I think though that this should
-        // eventually be fixed by closure bodies not having a parent
-        // region, though that's a touch unclear, and it might also be
-        // better just to narrow this assertion more (i.e., by
-        // excluding id's that correspond to closure bodies only). For
-        // now we just say that if there is already an AST scope on the stack,
-        // this new AST scope had better be its immediate child.
-        let top_scope = self.top_ast_scope();
-        let region_maps = &self.ccx.tcx().region_maps;
-        if top_scope.is_some() {
-            assert!((region_maps
-                     .opt_encl_scope(region_maps.node_extent(debug_loc.id))
-                     .map(|s|s.node_id(region_maps)) == top_scope)
-                    ||
-                    (region_maps
-                     .opt_encl_scope(region_maps.lookup_code_extent(
-                         region::CodeExtentData::DestructionScope(debug_loc.id)))
-                     .map(|s|s.node_id(region_maps)) == top_scope));
-        }
-
-        self.push_scope(CleanupScope::new(AstScopeKind(debug_loc.id),
-                                          debug_loc.debug_loc()));
-    }
-
-    fn push_loop_cleanup_scope(&self,
-                               id: ast::NodeId,
-                               exits: [Block<'blk, 'tcx>; EXIT_MAX]) {
-        debug!("push_loop_cleanup_scope({})",
-               self.ccx.tcx().map.node_to_string(id));
-        assert_eq!(Some(id), self.top_ast_scope());
-
-        // Just copy the debuginfo source location from the enclosing scope
-        let debug_loc = self.scopes
-                            .borrow()
-                            .last()
-                            .unwrap()
-                            .debug_loc;
-
-        self.push_scope(CleanupScope::new(LoopScopeKind(id, exits), debug_loc));
-    }
-
-    fn push_custom_cleanup_scope(&self) -> CustomScopeIndex {
+impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
+    pub fn push_custom_cleanup_scope(&self) -> CustomScopeIndex {
         let index = self.scopes_len();
         debug!("push_custom_cleanup_scope(): {}", index);
 
@@ -306,53 +174,14 @@ fn push_custom_cleanup_scope(&self) -> CustomScopeIndex {
                             .map(|opt_scope| opt_scope.debug_loc)
                             .unwrap_or(DebugLoc::None);
 
-        self.push_scope(CleanupScope::new(CustomScopeKind, debug_loc));
-        CustomScopeIndex { index: index }
-    }
-
-    fn push_custom_cleanup_scope_with_debug_loc(&self,
-                                                debug_loc: NodeIdAndSpan)
-                                                -> CustomScopeIndex {
-        let index = self.scopes_len();
-        debug!("push_custom_cleanup_scope(): {}", index);
-
-        self.push_scope(CleanupScope::new(CustomScopeKind,
-                                          debug_loc.debug_loc()));
+        self.push_scope(CleanupScope::new(debug_loc));
         CustomScopeIndex { index: index }
     }
 
-    /// Removes the cleanup scope for id `cleanup_scope`, which must be at the top of the cleanup
-    /// stack, and generates the code to do its cleanups for normal exit.
-    fn pop_and_trans_ast_cleanup_scope(&self,
-                                       bcx: Block<'blk, 'tcx>,
-                                       cleanup_scope: ast::NodeId)
-                                       -> Block<'blk, 'tcx> {
-        debug!("pop_and_trans_ast_cleanup_scope({})",
-               self.ccx.tcx().map.node_to_string(cleanup_scope));
-
-        assert!(self.top_scope(|s| s.kind.is_ast_with_id(cleanup_scope)));
-
-        let scope = self.pop_scope();
-        self.trans_scope_cleanups(bcx, &scope)
-    }
-
-    /// Removes the loop cleanup scope for id `cleanup_scope`, which must be at the top of the
-    /// cleanup stack. Does not generate any cleanup code, since loop scopes should exit by
-    /// branching to a block generated by `normal_exit_block`.
-    fn pop_loop_cleanup_scope(&self,
-                              cleanup_scope: ast::NodeId) {
-        debug!("pop_loop_cleanup_scope({})",
-               self.ccx.tcx().map.node_to_string(cleanup_scope));
-
-        assert!(self.top_scope(|s| s.kind.is_loop_with_id(cleanup_scope)));
-
-        let _ = self.pop_scope();
-    }
-
     /// Removes the top cleanup scope from the stack without executing its cleanups. The top
     /// cleanup scope must be the temporary scope `custom_scope`.
-    fn pop_custom_cleanup_scope(&self,
-                                custom_scope: CustomScopeIndex) {
+    pub fn pop_custom_cleanup_scope(&self,
+                                    custom_scope: CustomScopeIndex) {
         debug!("pop_custom_cleanup_scope({})", custom_scope.index);
         assert!(self.is_valid_to_pop_custom_scope(custom_scope));
         let _ = self.pop_scope();
@@ -360,10 +189,10 @@ fn pop_custom_cleanup_scope(&self,
 
     /// Removes the top cleanup scope from the stack, which must be a temporary scope, and
     /// generates the code to do its cleanups for normal exit.
-    fn pop_and_trans_custom_cleanup_scope(&self,
-                                          bcx: Block<'blk, 'tcx>,
-                                          custom_scope: CustomScopeIndex)
-                                          -> Block<'blk, 'tcx> {
+    pub fn pop_and_trans_custom_cleanup_scope(&self,
+                                              bcx: Block<'blk, 'tcx>,
+                                              custom_scope: CustomScopeIndex)
+                                              -> Block<'blk, 'tcx> {
         debug!("pop_and_trans_custom_cleanup_scope({:?})", custom_scope);
         assert!(self.is_valid_to_pop_custom_scope(custom_scope));
 
@@ -371,100 +200,27 @@ fn pop_and_trans_custom_cleanup_scope(&self,
         self.trans_scope_cleanups(bcx, &scope)
     }
 
-    /// Returns the id of the top-most loop scope
-    fn top_loop_scope(&self) -> ast::NodeId {
-        for scope in self.scopes.borrow().iter().rev() {
-            if let LoopScopeKind(id, _) = scope.kind {
-                return id;
-            }
-        }
-        bug!("no loop scope found");
-    }
-
-    /// Returns a block to branch to which will perform all pending cleanups and
-    /// then break/continue (depending on `exit`) out of the loop with id
-    /// `cleanup_scope`
-    fn normal_exit_block(&'blk self,
-                         cleanup_scope: ast::NodeId,
-                         exit: usize) -> BasicBlockRef {
-        self.trans_cleanups_to_exit_scope(LoopExit(cleanup_scope, exit))
-    }
-
-    /// Returns a block to branch to which will perform all pending cleanups and
-    /// then return from this function
-    fn return_exit_block(&'blk self) -> BasicBlockRef {
-        self.trans_cleanups_to_exit_scope(ReturnExit)
-    }
-
-    fn schedule_lifetime_end(&self,
-                             cleanup_scope: ScopeId,
-                             val: ValueRef) {
-        let drop = box LifetimeEnd {
-            ptr: val,
-        };
-
-        debug!("schedule_lifetime_end({:?}, val={:?})",
-               cleanup_scope, Value(val));
-
-        self.schedule_clean(cleanup_scope, drop as CleanupObj);
-    }
-
     /// Schedules a (deep) drop of `val`, which is a pointer to an instance of
     /// `ty`
-    fn schedule_drop_mem(&self,
-                         cleanup_scope: ScopeId,
-                         val: ValueRef,
-                         ty: Ty<'tcx>,
-                         drop_hint: Option<DropHintDatum<'tcx>>) {
+    pub fn schedule_drop_mem(&self,
+                             cleanup_scope: CustomScopeIndex,
+                             val: ValueRef,
+                             ty: Ty<'tcx>) {
         if !self.type_needs_drop(ty) { return; }
-        let drop_hint = drop_hint.map(|hint|hint.to_value());
-        let drop = box DropValue {
+        let drop = DropValue {
             is_immediate: false,
             val: val,
             ty: ty,
-            fill_on_drop: false,
             skip_dtor: false,
-            drop_hint: drop_hint,
         };
 
-        debug!("schedule_drop_mem({:?}, val={:?}, ty={:?}) fill_on_drop={} skip_dtor={}",
+        debug!("schedule_drop_mem({:?}, val={:?}, ty={:?}) skip_dtor={}",
                cleanup_scope,
                Value(val),
                ty,
-               drop.fill_on_drop,
                drop.skip_dtor);
 
-        self.schedule_clean(cleanup_scope, drop as CleanupObj);
-    }
-
-    /// Schedules a (deep) drop and filling of `val`, which is a pointer to an instance of `ty`
-    fn schedule_drop_and_fill_mem(&self,
-                                  cleanup_scope: ScopeId,
-                                  val: ValueRef,
-                                  ty: Ty<'tcx>,
-                                  drop_hint: Option<DropHintDatum<'tcx>>) {
-        if !self.type_needs_drop(ty) { return; }
-
-        let drop_hint = drop_hint.map(|datum|datum.to_value());
-        let drop = box DropValue {
-            is_immediate: false,
-            val: val,
-            ty: ty,
-            fill_on_drop: true,
-            skip_dtor: false,
-            drop_hint: drop_hint,
-        };
-
-        debug!("schedule_drop_and_fill_mem({:?}, val={:?}, ty={:?},
-                fill_on_drop={}, skip_dtor={}, has_drop_hint={})",
-               cleanup_scope,
-               Value(val),
-               ty,
-               drop.fill_on_drop,
-               drop.skip_dtor,
-               drop_hint.is_some());
-
-        self.schedule_clean(cleanup_scope, drop as CleanupObj);
+        self.schedule_clean(cleanup_scope, drop);
     }
 
     /// Issue #23611: Schedules a (deep) drop of the contents of
@@ -472,110 +228,55 @@ fn schedule_drop_and_fill_mem(&self,
     /// `ty`. The scheduled code handles extracting the discriminant
     /// and dropping the contents associated with that variant
     /// *without* executing any associated drop implementation.
-    fn schedule_drop_adt_contents(&self,
-                                  cleanup_scope: ScopeId,
-                                  val: ValueRef,
-                                  ty: Ty<'tcx>) {
+    pub fn schedule_drop_adt_contents(&self,
+                                      cleanup_scope: CustomScopeIndex,
+                                      val: ValueRef,
+                                      ty: Ty<'tcx>) {
         // `if` below could be "!contents_needs_drop"; skipping drop
         // is just an optimization, so sound to be conservative.
         if !self.type_needs_drop(ty) { return; }
 
-        let drop = box DropValue {
+        let drop = DropValue {
             is_immediate: false,
             val: val,
             ty: ty,
-            fill_on_drop: false,
             skip_dtor: true,
-            drop_hint: None,
         };
 
-        debug!("schedule_drop_adt_contents({:?}, val={:?}, ty={:?}) fill_on_drop={} skip_dtor={}",
+        debug!("schedule_drop_adt_contents({:?}, val={:?}, ty={:?}) skip_dtor={}",
                cleanup_scope,
                Value(val),
                ty,
-               drop.fill_on_drop,
                drop.skip_dtor);
 
-        self.schedule_clean(cleanup_scope, drop as CleanupObj);
+        self.schedule_clean(cleanup_scope, drop);
     }
 
     /// Schedules a (deep) drop of `val`, which is an instance of `ty`
-    fn schedule_drop_immediate(&self,
-                               cleanup_scope: ScopeId,
-                               val: ValueRef,
-                               ty: Ty<'tcx>) {
+    pub fn schedule_drop_immediate(&self,
+                                   cleanup_scope: CustomScopeIndex,
+                                   val: ValueRef,
+                                   ty: Ty<'tcx>) {
 
         if !self.type_needs_drop(ty) { return; }
-        let drop = Box::new(DropValue {
+        let drop = DropValue {
             is_immediate: true,
             val: val,
             ty: ty,
-            fill_on_drop: false,
             skip_dtor: false,
-            drop_hint: None,
-        });
+        };
 
-        debug!("schedule_drop_immediate({:?}, val={:?}, ty={:?}) fill_on_drop={} skip_dtor={}",
+        debug!("schedule_drop_immediate({:?}, val={:?}, ty={:?}) skip_dtor={}",
                cleanup_scope,
                Value(val),
                ty,
-               drop.fill_on_drop,
                drop.skip_dtor);
 
-        self.schedule_clean(cleanup_scope, drop as CleanupObj);
-    }
-
-    /// Schedules a call to `free(val)`. Note that this is a shallow operation.
-    fn schedule_free_value(&self,
-                           cleanup_scope: ScopeId,
-                           val: ValueRef,
-                           heap: Heap,
-                           content_ty: Ty<'tcx>) {
-        let drop = box FreeValue { ptr: val, heap: heap, content_ty: content_ty };
-
-        debug!("schedule_free_value({:?}, val={:?}, heap={:?})",
-               cleanup_scope, Value(val), heap);
-
-        self.schedule_clean(cleanup_scope, drop as CleanupObj);
-    }
-
-    fn schedule_clean(&self,
-                      cleanup_scope: ScopeId,
-                      cleanup: CleanupObj<'tcx>) {
-        match cleanup_scope {
-            AstScope(id) => self.schedule_clean_in_ast_scope(id, cleanup),
-            CustomScope(id) => self.schedule_clean_in_custom_scope(id, cleanup),
-        }
-    }
-
-    /// Schedules a cleanup to occur upon exit from `cleanup_scope`. If `cleanup_scope` is not
-    /// provided, then the cleanup is scheduled in the topmost scope, which must be a temporary
-    /// scope.
-    fn schedule_clean_in_ast_scope(&self,
-                                   cleanup_scope: ast::NodeId,
-                                   cleanup: CleanupObj<'tcx>) {
-        debug!("schedule_clean_in_ast_scope(cleanup_scope={})",
-               cleanup_scope);
-
-        for scope in self.scopes.borrow_mut().iter_mut().rev() {
-            if scope.kind.is_ast_with_id(cleanup_scope) {
-                scope.cleanups.push(cleanup);
-                scope.cached_landing_pad = None;
-                return;
-            } else {
-                // will be adding a cleanup to some enclosing scope
-                scope.clear_cached_exits();
-            }
-        }
-
-        bug!("no cleanup scope {} found",
-             self.ccx.tcx().map.node_to_string(cleanup_scope));
+        self.schedule_clean(cleanup_scope, drop);
     }
 
     /// Schedules a cleanup to occur in the top-most scope, which must be a temporary scope.
-    fn schedule_clean_in_custom_scope(&self,
-                                      custom_scope: CustomScopeIndex,
-                                      cleanup: CleanupObj<'tcx>) {
+    fn schedule_clean(&self, custom_scope: CustomScopeIndex, cleanup: DropValue<'tcx>) {
         debug!("schedule_clean_in_custom_scope(custom_scope={})",
                custom_scope.index);
 
@@ -588,14 +289,14 @@ fn schedule_clean_in_custom_scope(&self,
     }
 
     /// Returns true if there are pending cleanups that should execute on panic.
-    fn needs_invoke(&self) -> bool {
+    pub fn needs_invoke(&self) -> bool {
         self.scopes.borrow().iter().rev().any(|s| s.needs_invoke())
     }
 
     /// Returns a basic block to branch to in the event of a panic. This block
     /// will run the panic cleanups and eventually resume the exception that
     /// caused the landing pad to be run.
-    fn get_landing_pad(&'blk self) -> BasicBlockRef {
+    pub fn get_landing_pad(&'blk self) -> BasicBlockRef {
         let _icx = base::push_ctxt("get_landing_pad");
 
         debug!("get_landing_pad");
@@ -625,25 +326,6 @@ fn get_landing_pad(&'blk self) -> BasicBlockRef {
 
         return llbb;
     }
-}
-
-impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
-    /// Returns the id of the current top-most AST scope, if any.
-    fn top_ast_scope(&self) -> Option<ast::NodeId> {
-        for scope in self.scopes.borrow().iter().rev() {
-            match scope.kind {
-                CustomScopeKind | LoopScopeKind(..) => {}
-                AstScopeKind(i) => {
-                    return Some(i);
-                }
-            }
-        }
-        None
-    }
-
-    fn top_nonempty_cleanup_scope(&self) -> Option<usize> {
-        self.scopes.borrow().iter().rev().position(|s| !s.cleanups.is_empty())
-    }
 
     fn is_valid_to_pop_custom_scope(&self, custom_scope: CustomScopeIndex) -> bool {
         self.is_valid_custom_scope(custom_scope) &&
@@ -652,14 +334,13 @@ fn is_valid_to_pop_custom_scope(&self, custom_scope: CustomScopeIndex) -> bool {
 
     fn is_valid_custom_scope(&self, custom_scope: CustomScopeIndex) -> bool {
         let scopes = self.scopes.borrow();
-        custom_scope.index < scopes.len() &&
-            (*scopes)[custom_scope.index].kind.is_temp()
+        custom_scope.index < scopes.len()
     }
 
     /// Generates the cleanups for `scope` into `bcx`
     fn trans_scope_cleanups(&self, // cannot borrow self, will recurse
                             bcx: Block<'blk, 'tcx>,
-                            scope: &CleanupScope<'blk, 'tcx>) -> Block<'blk, 'tcx> {
+                            scope: &CleanupScope<'tcx>) -> Block<'blk, 'tcx> {
 
         let mut bcx = bcx;
         if !bcx.unreachable.get() {
@@ -674,11 +355,11 @@ fn scopes_len(&self) -> usize {
         self.scopes.borrow().len()
     }
 
-    fn push_scope(&self, scope: CleanupScope<'blk, 'tcx>) {
+    fn push_scope(&self, scope: CleanupScope<'tcx>) {
         self.scopes.borrow_mut().push(scope)
     }
 
-    fn pop_scope(&self) -> CleanupScope<'blk, 'tcx> {
+    fn pop_scope(&self) -> CleanupScope<'tcx> {
         debug!("popping cleanup scope {}, {} scopes remaining",
                self.top_scope(|s| s.block_name("")),
                self.scopes_len() - 1);
@@ -686,7 +367,7 @@ fn pop_scope(&self) -> CleanupScope<'blk, 'tcx> {
         self.scopes.borrow_mut().pop().unwrap()
     }
 
-    fn top_scope<R, F>(&self, f: F) -> R where F: FnOnce(&CleanupScope<'blk, 'tcx>) -> R {
+    fn top_scope<R, F>(&self, f: F) -> R where F: FnOnce(&CleanupScope<'tcx>) -> R {
         f(self.scopes.borrow().last().unwrap())
     }
 
@@ -738,7 +419,7 @@ fn trans_cleanups_to_exit_scope(&'blk self,
                     UnwindExit(val) => {
                         // Generate a block that will resume unwinding to the
                         // calling function
-                        let bcx = self.new_block("resume", None);
+                        let bcx = self.new_block("resume");
                         match val {
                             UnwindKind::LandingPad => {
                                 let addr = self.landingpad_alloca.get()
@@ -755,15 +436,6 @@ fn trans_cleanups_to_exit_scope(&'blk self,
                         prev_llbb = bcx.llbb;
                         break;
                     }
-
-                    ReturnExit => {
-                        prev_llbb = self.get_llreturn();
-                        break
-                    }
-
-                    LoopExit(id, _) => {
-                        bug!("cannot exit from scope {}, not in scope", id);
-                    }
                 }
             }
 
@@ -782,20 +454,6 @@ fn trans_cleanups_to_exit_scope(&'blk self,
                 skip = last_cleanup;
                 break;
             }
-
-            // If we are searching for a loop exit,
-            // and this scope is that loop, then stop popping and set
-            // `prev_llbb` to the appropriate exit block from the loop.
-            let scope = popped_scopes.last().unwrap();
-            match label {
-                UnwindExit(..) | ReturnExit => { }
-                LoopExit(id, exit) => {
-                    if let Some(exit) = scope.kind.early_exit_block(id, exit) {
-                        prev_llbb = exit;
-                        break
-                    }
-                }
-            }
         }
 
         debug!("trans_cleanups_to_exit_scope: popped {} scopes",
@@ -826,7 +484,7 @@ fn trans_cleanups_to_exit_scope(&'blk self,
                 let name = scope.block_name("clean");
                 debug!("generating cleanups for {}", name);
 
-                let bcx_in = self.new_block(&name[..], None);
+                let bcx_in = self.new_block(&name[..]);
                 let exit_label = label.start(bcx_in);
                 let mut bcx_out = bcx_in;
                 let len = scope.cleanups.len();
@@ -869,7 +527,7 @@ fn get_or_create_landing_pad(&'blk self) -> BasicBlockRef {
                 Some(llbb) => return llbb,
                 None => {
                     let name = last_scope.block_name("unwind");
-                    pad_bcx = self.new_block(&name[..], None);
+                    pad_bcx = self.new_block(&name[..]);
                     last_scope.cached_landing_pad = Some(pad_bcx.llbb);
                 }
             }
@@ -923,12 +581,9 @@ fn get_or_create_landing_pad(&'blk self) -> BasicBlockRef {
     }
 }
 
-impl<'blk, 'tcx> CleanupScope<'blk, 'tcx> {
-    fn new(kind: CleanupScopeKind<'blk, 'tcx>,
-           debug_loc: DebugLoc)
-        -> CleanupScope<'blk, 'tcx> {
+impl<'tcx> CleanupScope<'tcx> {
+    fn new(debug_loc: DebugLoc) -> CleanupScope<'tcx> {
         CleanupScope {
-            kind: kind,
             debug_loc: debug_loc,
             cleanups: vec!(),
             cached_early_exits: vec!(),
@@ -936,11 +591,6 @@ fn new(kind: CleanupScopeKind<'blk, 'tcx>,
         }
     }
 
-    fn clear_cached_exits(&mut self) {
-        self.cached_early_exits = vec!();
-        self.cached_landing_pad = None;
-    }
-
     fn cached_early_exit(&self,
                          label: EarlyExitLabel)
                          -> Option<(BasicBlockRef, usize)> {
@@ -961,62 +611,13 @@ fn add_cached_early_exit(&mut self,
 
     /// True if this scope has cleanups that need unwinding
     fn needs_invoke(&self) -> bool {
-
         self.cached_landing_pad.is_some() ||
-            self.cleanups.iter().any(|c| c.must_unwind())
+            !self.cleanups.is_empty()
     }
 
     /// Returns a suitable name to use for the basic block that handles this cleanup scope
     fn block_name(&self, prefix: &str) -> String {
-        match self.kind {
-            CustomScopeKind => format!("{}_custom_", prefix),
-            AstScopeKind(id) => format!("{}_ast_{}_", prefix, id),
-            LoopScopeKind(id, _) => format!("{}_loop_{}_", prefix, id),
-        }
-    }
-
-    /// Manipulate cleanup scope for call arguments. Conceptually, each
-    /// argument to a call is an lvalue, and performing the call moves each
-    /// of the arguments into a new rvalue (which gets cleaned up by the
-    /// callee). As an optimization, instead of actually performing all of
-    /// those moves, trans just manipulates the cleanup scope to obtain the
-    /// same effect.
-    pub fn drop_non_lifetime_clean(&mut self) {
-        self.cleanups.retain(|c| c.is_lifetime_end());
-        self.clear_cached_exits();
-    }
-}
-
-impl<'blk, 'tcx> CleanupScopeKind<'blk, 'tcx> {
-    fn is_temp(&self) -> bool {
-        match *self {
-            CustomScopeKind => true,
-            LoopScopeKind(..) | AstScopeKind(..) => false,
-        }
-    }
-
-    fn is_ast_with_id(&self, id: ast::NodeId) -> bool {
-        match *self {
-            CustomScopeKind | LoopScopeKind(..) => false,
-            AstScopeKind(i) => i == id
-        }
-    }
-
-    fn is_loop_with_id(&self, id: ast::NodeId) -> bool {
-        match *self {
-            CustomScopeKind | AstScopeKind(..) => false,
-            LoopScopeKind(i, _) => i == id
-        }
-    }
-
-    /// If this is a loop scope with id `id`, return the early exit block `exit`, else `None`
-    fn early_exit_block(&self,
-                        id: ast::NodeId,
-                        exit: usize) -> Option<BasicBlockRef> {
-        match *self {
-            LoopScopeKind(i, ref exits) if id == i => Some(exits[exit].llbb),
-            _ => None,
-        }
+        format!("{}_custom_", prefix)
     }
 }
 
@@ -1057,7 +658,6 @@ fn start(&self, bcx: Block) -> EarlyExitLabel {
                 bcx.lpad.set(Some(bcx.fcx.lpad_arena.alloc(LandingPad::gnu())));
                 *self
             }
-            label => label,
         }
     }
 }
@@ -1080,20 +680,10 @@ pub struct DropValue<'tcx> {
     is_immediate: bool,
     val: ValueRef,
     ty: Ty<'tcx>,
-    fill_on_drop: bool,
     skip_dtor: bool,
-    drop_hint: Option<DropHintValue>,
 }
 
-impl<'tcx> Cleanup<'tcx> for DropValue<'tcx> {
-    fn must_unwind(&self) -> bool {
-        true
-    }
-
-    fn is_lifetime_end(&self) -> bool {
-        false
-    }
-
+impl<'tcx> DropValue<'tcx> {
     fn trans<'blk>(&self,
                    bcx: Block<'blk, 'tcx>,
                    debug_loc: DebugLoc)
@@ -1107,180 +697,8 @@ fn trans<'blk>(&self,
         let bcx = if self.is_immediate {
             glue::drop_ty_immediate(bcx, self.val, self.ty, debug_loc, self.skip_dtor)
         } else {
-            glue::drop_ty_core(bcx, self.val, self.ty, debug_loc, self.skip_dtor, self.drop_hint)
+            glue::drop_ty_core(bcx, self.val, self.ty, debug_loc, self.skip_dtor)
         };
-        if self.fill_on_drop {
-            base::drop_done_fill_mem(bcx, self.val, self.ty);
-        }
         bcx
     }
 }
-
-#[derive(Copy, Clone, Debug)]
-pub enum Heap {
-    HeapExchange
-}
-
-#[derive(Copy, Clone)]
-pub struct FreeValue<'tcx> {
-    ptr: ValueRef,
-    heap: Heap,
-    content_ty: Ty<'tcx>
-}
-
-impl<'tcx> Cleanup<'tcx> for FreeValue<'tcx> {
-    fn must_unwind(&self) -> bool {
-        true
-    }
-
-    fn is_lifetime_end(&self) -> bool {
-        false
-    }
-
-    fn trans<'blk>(&self,
-                   bcx: Block<'blk, 'tcx>,
-                   debug_loc: DebugLoc)
-                   -> Block<'blk, 'tcx> {
-        match self.heap {
-            HeapExchange => {
-                glue::trans_exchange_free_ty(bcx,
-                                             self.ptr,
-                                             self.content_ty,
-                                             debug_loc)
-            }
-        }
-    }
-}
-
-#[derive(Copy, Clone)]
-pub struct LifetimeEnd {
-    ptr: ValueRef,
-}
-
-impl<'tcx> Cleanup<'tcx> for LifetimeEnd {
-    fn must_unwind(&self) -> bool {
-        false
-    }
-
-    fn is_lifetime_end(&self) -> bool {
-        true
-    }
-
-    fn trans<'blk>(&self,
-                   bcx: Block<'blk, 'tcx>,
-                   debug_loc: DebugLoc)
-                   -> Block<'blk, 'tcx> {
-        debug_loc.apply(bcx.fcx);
-        base::call_lifetime_end(bcx, self.ptr);
-        bcx
-    }
-}
-
-pub fn temporary_scope(tcx: TyCtxt,
-                       id: ast::NodeId)
-                       -> ScopeId {
-    match tcx.region_maps.temporary_scope(id) {
-        Some(scope) => {
-            let r = AstScope(scope.node_id(&tcx.region_maps));
-            debug!("temporary_scope({}) = {:?}", id, r);
-            r
-        }
-        None => {
-            bug!("no temporary scope available for expr {}", id)
-        }
-    }
-}
-
-pub fn var_scope(tcx: TyCtxt,
-                 id: ast::NodeId)
-                 -> ScopeId {
-    let r = AstScope(tcx.region_maps.var_scope(id).node_id(&tcx.region_maps));
-    debug!("var_scope({}) = {:?}", id, r);
-    r
-}
-
-///////////////////////////////////////////////////////////////////////////
-// These traits just exist to put the methods into this file.
-
-pub trait CleanupMethods<'blk, 'tcx> {
-    fn push_ast_cleanup_scope(&self, id: NodeIdAndSpan);
-    fn push_loop_cleanup_scope(&self,
-                               id: ast::NodeId,
-                               exits: [Block<'blk, 'tcx>; EXIT_MAX]);
-    fn push_custom_cleanup_scope(&self) -> CustomScopeIndex;
-    fn push_custom_cleanup_scope_with_debug_loc(&self,
-                                                debug_loc: NodeIdAndSpan)
-                                                -> CustomScopeIndex;
-    fn pop_and_trans_ast_cleanup_scope(&self,
-                                       bcx: Block<'blk, 'tcx>,
-                                       cleanup_scope: ast::NodeId)
-                                       -> Block<'blk, 'tcx>;
-    fn pop_loop_cleanup_scope(&self,
-                              cleanup_scope: ast::NodeId);
-    fn pop_custom_cleanup_scope(&self,
-                                custom_scope: CustomScopeIndex);
-    fn pop_and_trans_custom_cleanup_scope(&self,
-                                          bcx: Block<'blk, 'tcx>,
-                                          custom_scope: CustomScopeIndex)
-                                          -> Block<'blk, 'tcx>;
-    fn top_loop_scope(&self) -> ast::NodeId;
-    fn normal_exit_block(&'blk self,
-                         cleanup_scope: ast::NodeId,
-                         exit: usize) -> BasicBlockRef;
-    fn return_exit_block(&'blk self) -> BasicBlockRef;
-    fn schedule_lifetime_end(&self,
-                         cleanup_scope: ScopeId,
-                         val: ValueRef);
-    fn schedule_drop_mem(&self,
-                         cleanup_scope: ScopeId,
-                         val: ValueRef,
-                         ty: Ty<'tcx>,
-                         drop_hint: Option<DropHintDatum<'tcx>>);
-    fn schedule_drop_and_fill_mem(&self,
-                                  cleanup_scope: ScopeId,
-                                  val: ValueRef,
-                                  ty: Ty<'tcx>,
-                                  drop_hint: Option<DropHintDatum<'tcx>>);
-    fn schedule_drop_adt_contents(&self,
-                                  cleanup_scope: ScopeId,
-                                  val: ValueRef,
-                                  ty: Ty<'tcx>);
-    fn schedule_drop_immediate(&self,
-                               cleanup_scope: ScopeId,
-                               val: ValueRef,
-                               ty: Ty<'tcx>);
-    fn schedule_free_value(&self,
-                           cleanup_scope: ScopeId,
-                           val: ValueRef,
-                           heap: Heap,
-                           content_ty: Ty<'tcx>);
-    fn schedule_clean(&self,
-                      cleanup_scope: ScopeId,
-                      cleanup: CleanupObj<'tcx>);
-    fn schedule_clean_in_ast_scope(&self,
-                                   cleanup_scope: ast::NodeId,
-                                   cleanup: CleanupObj<'tcx>);
-    fn schedule_clean_in_custom_scope(&self,
-                                    custom_scope: CustomScopeIndex,
-                                    cleanup: CleanupObj<'tcx>);
-    fn needs_invoke(&self) -> bool;
-    fn get_landing_pad(&'blk self) -> BasicBlockRef;
-}
-
-trait CleanupHelperMethods<'blk, 'tcx> {
-    fn top_ast_scope(&self) -> Option<ast::NodeId>;
-    fn top_nonempty_cleanup_scope(&self) -> Option<usize>;
-    fn is_valid_to_pop_custom_scope(&self, custom_scope: CustomScopeIndex) -> bool;
-    fn is_valid_custom_scope(&self, custom_scope: CustomScopeIndex) -> bool;
-    fn trans_scope_cleanups(&self,
-                            bcx: Block<'blk, 'tcx>,
-                            scope: &CleanupScope<'blk, 'tcx>) -> Block<'blk, 'tcx>;
-    fn trans_cleanups_to_exit_scope(&'blk self,
-                                    label: EarlyExitLabel)
-                                    -> BasicBlockRef;
-    fn get_or_create_landing_pad(&'blk self) -> BasicBlockRef;
-    fn scopes_len(&self) -> usize;
-    fn push_scope(&self, scope: CleanupScope<'blk, 'tcx>);
-    fn pop_scope(&self) -> CleanupScope<'blk, 'tcx>;
-    fn top_scope<R, F>(&self, f: F) -> R where F: FnOnce(&CleanupScope<'blk, 'tcx>) -> R;
-}
index 77b2c43167cfd280b20122f7c4bc233740141c4d..842a8fddb83e199e03af4a917d117f6a38a236b2 100644 (file)
 
 use arena::TypedArena;
 use back::symbol_names;
-use llvm::{self, ValueRef, get_param, get_params};
+use llvm::{self, ValueRef, get_params};
 use rustc::hir::def_id::DefId;
 use abi::{Abi, FnType};
-use adt;
 use attributes;
 use base::*;
-use build::*;
-use callee::{self, ArgVals, Callee};
-use cleanup::{CleanupMethods, CustomScope, ScopeId};
+use callee::{self, Callee};
 use common::*;
-use datum::{ByRef, Datum, lvalue_scratch_datum};
-use datum::{rvalue_scratch_datum, Rvalue};
-use debuginfo::{self, DebugLoc};
+use debuginfo::{DebugLoc};
 use declare;
-use expr;
 use monomorphize::{Instance};
 use value::Value;
-use Disr;
 use rustc::ty::{self, Ty, TyCtxt};
-use session::config::FullDebugInfo;
-
-use syntax::ast;
 
 use rustc::hir;
 
-use libc::c_uint;
-
-fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                        closure_def_id: DefId,
-                                        arg_scope_id: ScopeId,
-                                        id: ast::NodeId) {
-    let _icx = push_ctxt("closure::load_closure_environment");
-    let kind = kind_for_closure(bcx.ccx(), closure_def_id);
-
-    let env_arg = &bcx.fcx.fn_ty.args[0];
-    let mut env_idx = bcx.fcx.fn_ty.ret.is_indirect() as usize;
-
-    // Special case for small by-value selfs.
-    let llenv = if kind == ty::ClosureKind::FnOnce && !env_arg.is_indirect() {
-        let closure_ty = node_id_type(bcx, id);
-        let llenv = rvalue_scratch_datum(bcx, closure_ty, "closure_env").val;
-        env_arg.store_fn_arg(&bcx.build(), &mut env_idx, llenv);
-        llenv
-    } else {
-        get_param(bcx.fcx.llfn, env_idx as c_uint)
-    };
-
-    // Store the pointer to closure data in an alloca for debug info because that's what the
-    // llvm.dbg.declare intrinsic expects
-    let env_pointer_alloca = if bcx.sess().opts.debuginfo == FullDebugInfo {
-        let alloc = alloca(bcx, val_ty(llenv), "__debuginfo_env_ptr");
-        Store(bcx, llenv, alloc);
-        Some(alloc)
-    } else {
-        None
-    };
-
-    bcx.tcx().with_freevars(id, |fv| {
-        for (i, freevar) in fv.iter().enumerate() {
-            let upvar_id = ty::UpvarId { var_id: freevar.def.var_id(),
-                                        closure_expr_id: id };
-            let upvar_capture = bcx.tcx().upvar_capture(upvar_id).unwrap();
-            let mut upvar_ptr = StructGEP(bcx, llenv, i);
-            let captured_by_ref = match upvar_capture {
-                ty::UpvarCapture::ByValue => false,
-                ty::UpvarCapture::ByRef(..) => {
-                    upvar_ptr = Load(bcx, upvar_ptr);
-                    true
-                }
-            };
-            let node_id = freevar.def.var_id();
-            bcx.fcx.llupvars.borrow_mut().insert(node_id, upvar_ptr);
-
-            if kind == ty::ClosureKind::FnOnce && !captured_by_ref {
-                let hint = bcx.fcx.lldropflag_hints.borrow().hint_datum(upvar_id.var_id);
-                bcx.fcx.schedule_drop_mem(arg_scope_id,
-                                        upvar_ptr,
-                                        node_id_type(bcx, node_id),
-                                        hint)
-            }
-
-            if let Some(env_pointer_alloca) = env_pointer_alloca {
-                debuginfo::create_captured_var_metadata(
-                    bcx,
-                    node_id,
-                    env_pointer_alloca,
-                    i,
-                    captured_by_ref,
-                    freevar.span);
-            }
-        }
-    })
-}
-
-pub enum ClosureEnv {
-    NotClosure,
-    Closure(DefId, ast::NodeId),
-}
-
-impl ClosureEnv {
-    pub fn load<'blk,'tcx>(self, bcx: Block<'blk, 'tcx>, arg_scope: ScopeId) {
-        if let ClosureEnv::Closure(def_id, id) = self {
-            load_closure_environment(bcx, def_id, arg_scope, id);
-        }
-    }
-}
-
 fn get_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            closure_id: DefId,
                            fn_ty: Ty<'tcx>)
@@ -181,68 +89,15 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     llfn
 }
 
-fn translating_closure_body_via_mir_will_fail(ccx: &CrateContext,
-                                              closure_def_id: DefId)
-                                              -> bool {
-    let default_to_mir = ccx.sess().opts.debugging_opts.orbit;
-    let invert = if default_to_mir { "rustc_no_mir" } else { "rustc_mir" };
-    let use_mir = default_to_mir ^ ccx.tcx().has_attr(closure_def_id, invert);
-
-    !use_mir
-}
-
 pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                             closure_def_id: DefId,
                                             closure_substs: ty::ClosureSubsts<'tcx>) {
-    use syntax::ast::DUMMY_NODE_ID;
-    use syntax_pos::DUMMY_SP;
-    use syntax::ptr::P;
-
-    trans_closure_expr(Dest::Ignore(ccx),
-                       &hir::FnDecl {
-                           inputs: P::new(),
-                           output: hir::Return(P(hir::Ty {
-                               id: DUMMY_NODE_ID,
-                               span: DUMMY_SP,
-                               node: hir::Ty_::TyNever,
-                           })),
-                           variadic: false
-                       },
-                       &hir::Block {
-                           stmts: P::new(),
-                           expr: None,
-                           id: DUMMY_NODE_ID,
-                           rules: hir::DefaultBlock,
-                           span: DUMMY_SP
-                       },
-                       DUMMY_NODE_ID,
-                       closure_def_id,
-                       closure_substs);
-}
-
-pub enum Dest<'a, 'tcx: 'a> {
-    SaveIn(Block<'a, 'tcx>, ValueRef),
-    Ignore(&'a CrateContext<'a, 'tcx>)
-}
-
-pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
-                                    decl: &hir::FnDecl,
-                                    body: &hir::Block,
-                                    id: ast::NodeId,
-                                    closure_def_id: DefId, // (*)
-                                    closure_substs: ty::ClosureSubsts<'tcx>)
-                                    -> Option<Block<'a, 'tcx>>
-{
     // (*) Note that in the case of inlined functions, the `closure_def_id` will be the
     // defid of the closure in its original crate, whereas `id` will be the id of the local
     // inlined copy.
-    debug!("trans_closure_expr(id={:?}, closure_def_id={:?}, closure_substs={:?})",
-           id, closure_def_id, closure_substs);
+    debug!("trans_closure_body_via_mir(closure_def_id={:?}, closure_substs={:?})",
+           closure_def_id, closure_substs);
 
-    let ccx = match dest {
-        Dest::SaveIn(bcx, _) => bcx.ccx(),
-        Dest::Ignore(ccx) => ccx
-    };
     let tcx = ccx.tcx();
     let _icx = push_ctxt("closure::trans_closure_expr");
 
@@ -285,52 +140,13 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
         };
 
         trans_closure(ccx,
-                      decl,
-                      body,
                       llfn,
                       Instance::new(closure_def_id, param_substs),
-                      id,
                       &sig,
-                      Abi::RustCall,
-                      ClosureEnv::Closure(closure_def_id, id));
+                      Abi::RustCall);
 
         ccx.instances().borrow_mut().insert(instance, llfn);
     }
-
-    // Don't hoist this to the top of the function. It's perfectly legitimate
-    // to have a zero-size closure (in which case dest will be `Ignore`) and
-    // we must still generate the closure body.
-    let (mut bcx, dest_addr) = match dest {
-        Dest::SaveIn(bcx, p) => (bcx, p),
-        Dest::Ignore(_) => {
-            debug!("trans_closure_expr() ignoring result");
-            return None;
-        }
-    };
-
-    let repr = adt::represent_type(ccx, node_id_type(bcx, id));
-
-    // Create the closure.
-    tcx.with_freevars(id, |fv| {
-        for (i, freevar) in fv.iter().enumerate() {
-            let datum = expr::trans_var(bcx, freevar.def);
-            let upvar_slot_dest = adt::trans_field_ptr(
-                bcx, &repr, adt::MaybeSizedValue::sized(dest_addr), Disr(0), i);
-            let upvar_id = ty::UpvarId { var_id: freevar.def.var_id(),
-                                        closure_expr_id: id };
-            match tcx.upvar_capture(upvar_id).unwrap() {
-                ty::UpvarCapture::ByValue => {
-                    bcx = datum.store_to(bcx, upvar_slot_dest);
-                }
-                ty::UpvarCapture::ByRef(..) => {
-                    Store(bcx, datum.to_llref(), upvar_slot_dest);
-                }
-            }
-        }
-    });
-    adt::trans_set_discr(bcx, &repr, dest_addr, Disr(0));
-
-    Some(bcx)
 }
 
 pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
@@ -347,32 +163,7 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
     if !ccx.sess().target.target.options.allows_weak_linkage &&
        !ccx.sess().opts.single_codegen_unit() {
 
-        if let Some(node_id) = ccx.tcx().map.as_local_node_id(closure_def_id) {
-            // If the closure is defined in the local crate, we can always just
-            // translate it.
-            let (decl, body) = match ccx.tcx().map.expect_expr(node_id).node {
-                hir::ExprClosure(_, ref decl, ref body, _) => (decl, body),
-                _ => { unreachable!() }
-            };
-
-            trans_closure_expr(Dest::Ignore(ccx),
-                               decl,
-                               body,
-                               node_id,
-                               closure_def_id,
-                               substs);
-        } else {
-            // If the closure is defined in an upstream crate, we can only
-            // translate it if MIR-trans is active.
-
-            if translating_closure_body_via_mir_will_fail(ccx, closure_def_id) {
-                ccx.sess().fatal("You have run into a known limitation of the \
-                                  MingW toolchain. Either compile with -Zorbit or \
-                                  with -Ccodegen-units=1 to work around it.");
-            }
-
-            trans_closure_body_via_mir(ccx, closure_def_id, substs);
-        }
+        trans_closure_body_via_mir(ccx, closure_def_id, substs);
     }
 
     // If the closure is a Fn closure, but a FnOnce is needed (etc),
@@ -472,28 +263,21 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     let (block_arena, fcx): (TypedArena<_>, FunctionContext);
     block_arena = TypedArena::new();
     fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, &block_arena);
-    let mut bcx = fcx.init(false, None);
+    let mut bcx = fcx.init(false);
 
 
     // the first argument (`self`) will be the (by value) closure env.
-    let self_scope = fcx.push_custom_cleanup_scope();
-    let self_scope_id = CustomScope(self_scope);
 
     let mut llargs = get_params(fcx.llfn);
     let mut self_idx = fcx.fn_ty.ret.is_indirect() as usize;
     let env_arg = &fcx.fn_ty.args[0];
     let llenv = if env_arg.is_indirect() {
-        Datum::new(llargs[self_idx], closure_ty, Rvalue::new(ByRef))
-            .add_clean(&fcx, self_scope_id)
+        llargs[self_idx]
     } else {
-        unpack_datum!(bcx, lvalue_scratch_datum(bcx, closure_ty, "self",
-                                                InitAlloca::Dropped,
-                                                self_scope_id, |bcx, llval| {
-            let mut llarg_idx = self_idx;
-            env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, llval);
-            bcx.fcx.schedule_lifetime_end(self_scope_id, llval);
-            bcx
-        })).val
+        let scratch = alloc_ty(bcx, closure_ty, "self");
+        let mut llarg_idx = self_idx;
+        env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, scratch);
+        scratch
     };
 
     debug!("trans_fn_once_adapter_shim: env={:?}", Value(llenv));
@@ -510,15 +294,19 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
         llargs[self_idx] = llenv;
     }
 
-    let dest =
-        fcx.llretslotptr.get().map(
-            |_| expr::SaveIn(fcx.get_ret_slot(bcx, "ret_slot")));
+    let dest = fcx.llretslotptr.get();
 
     let callee = Callee {
         data: callee::Fn(llreffn),
         ty: llref_fn_ty
     };
-    bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[self_idx..]), dest).bcx;
+
+    // Call the by-ref closure body with `self` in a cleanup scope,
+    // to drop `self` when the body returns, or in case it unwinds.
+    let self_scope = fcx.push_custom_cleanup_scope();
+    fcx.schedule_drop_mem(self_scope, llenv, closure_ty);
+
+    bcx = callee.call(bcx, DebugLoc::None, &llargs[self_idx..], dest).bcx;
 
     fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope);
 
index 76910304eebb0e40c43717fbe1c4f8cf1c3ad2ff..c82bfa5c91ba1cbdd74ccd9703336cadc826c194 100644 (file)
 use rustc::mir::repr as mir;
 use rustc::mir::visit as mir_visit;
 use rustc::mir::visit::Visitor as MirVisitor;
+use rustc::mir::repr::Location;
 
 use rustc_const_eval as const_eval;
 
@@ -446,7 +447,7 @@ struct MirNeighborCollector<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
 
-    fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>) {
+    fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
         debug!("visiting rvalue {:?}", *rvalue);
 
         match *rvalue {
@@ -458,7 +459,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>) {
                     format!("Could not find MIR for closure: {:?}", def_id)
                 });
 
-                let concrete_substs = monomorphize::apply_param_substs(self.scx.tcx(),
+                let concrete_substs = monomorphize::apply_param_substs(self.scx,
                                                                        self.param_substs,
                                                                        &substs.func_substs);
                 let concrete_substs = self.scx.tcx().erase_regions(&concrete_substs);
@@ -476,11 +477,11 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>) {
             // have to instantiate all methods of the trait being cast to, so we
             // can build the appropriate vtable.
             mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => {
-                let target_ty = monomorphize::apply_param_substs(self.scx.tcx(),
+                let target_ty = monomorphize::apply_param_substs(self.scx,
                                                                  self.param_substs,
                                                                  &target_ty);
                 let source_ty = operand.ty(self.mir, self.scx.tcx());
-                let source_ty = monomorphize::apply_param_substs(self.scx.tcx(),
+                let source_ty = monomorphize::apply_param_substs(self.scx,
                                                                  self.param_substs,
                                                                  &source_ty);
                 let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx,
@@ -507,7 +508,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>) {
                 assert!(can_have_local_instance(self.scx.tcx(), exchange_malloc_fn_def_id));
                 let empty_substs = self.scx.empty_substs_for_def_id(exchange_malloc_fn_def_id);
                 let exchange_malloc_fn_trans_item =
-                    create_fn_trans_item(self.scx.tcx(),
+                    create_fn_trans_item(self.scx,
                                          exchange_malloc_fn_def_id,
                                          empty_substs,
                                          self.param_substs);
@@ -517,19 +518,20 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>) {
             _ => { /* not interesting */ }
         }
 
-        self.super_rvalue(rvalue);
+        self.super_rvalue(rvalue, location);
     }
 
     fn visit_lvalue(&mut self,
                     lvalue: &mir::Lvalue<'tcx>,
-                    context: mir_visit::LvalueContext) {
+                    context: mir_visit::LvalueContext,
+                    location: Location) {
         debug!("visiting lvalue {:?}", *lvalue);
 
         if let mir_visit::LvalueContext::Drop = context {
             let ty = lvalue.ty(self.mir, self.scx.tcx())
                            .to_ty(self.scx.tcx());
 
-            let ty = monomorphize::apply_param_substs(self.scx.tcx(),
+            let ty = monomorphize::apply_param_substs(self.scx,
                                                       self.param_substs,
                                                       &ty);
             assert!(ty.is_normalized_for_trans());
@@ -537,10 +539,10 @@ fn visit_lvalue(&mut self,
             self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
         }
 
-        self.super_lvalue(lvalue, context);
+        self.super_lvalue(lvalue, context, location);
     }
 
-    fn visit_operand(&mut self, operand: &mir::Operand<'tcx>) {
+    fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
         debug!("visiting operand {:?}", *operand);
 
         let callee = match *operand {
@@ -553,7 +555,7 @@ fn visit_operand(&mut self, operand: &mir::Operand<'tcx>) {
                     // references to `const` items
                     if let mir::Literal::Item { def_id, substs } = constant.literal {
                         let tcx = self.scx.tcx();
-                        let substs = monomorphize::apply_param_substs(tcx,
+                        let substs = monomorphize::apply_param_substs(self.scx,
                                                                       self.param_substs,
                                                                       &substs);
 
@@ -611,7 +613,7 @@ fn visit_operand(&mut self, operand: &mir::Operand<'tcx>) {
                 // result in a translation item ...
                 if can_result_in_trans_item(self.scx.tcx(), callee_def_id) {
                     // ... and create one if it does.
-                    let trans_item = create_fn_trans_item(self.scx.tcx(),
+                    let trans_item = create_fn_trans_item(self.scx,
                                                           callee_def_id,
                                                           callee_substs,
                                                           self.param_substs);
@@ -620,7 +622,7 @@ fn visit_operand(&mut self, operand: &mir::Operand<'tcx>) {
             }
         }
 
-        self.super_operand(operand);
+        self.super_operand(operand, location);
 
         fn can_result_in_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                               def_id: DefId)
@@ -654,7 +656,8 @@ fn can_result_in_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // we would not register drop-glues.
     fn visit_terminator_kind(&mut self,
                              block: mir::BasicBlock,
-                             kind: &mir::TerminatorKind<'tcx>) {
+                             kind: &mir::TerminatorKind<'tcx>,
+                             location: Location) {
         let tcx = self.scx.tcx();
         match *kind {
             mir::TerminatorKind::Call {
@@ -667,7 +670,7 @@ fn visit_terminator_kind(&mut self,
                         if is_drop_in_place_intrinsic(tcx, def_id, bare_fn_ty) => {
                         let operand_ty = args[0].ty(self.mir, tcx);
                         if let ty::TyRawPtr(mt) = operand_ty.sty {
-                            let operand_ty = monomorphize::apply_param_substs(tcx,
+                            let operand_ty = monomorphize::apply_param_substs(self.scx,
                                                                               self.param_substs,
                                                                               &mt.ty);
                             let ty = glue::get_drop_glue_type(tcx, operand_ty);
@@ -682,7 +685,7 @@ fn visit_terminator_kind(&mut self,
             _ => { /* Nothing to do. */ }
         }
 
-        self.super_terminator_kind(block, kind);
+        self.super_terminator_kind(block, kind, location);
 
         fn is_drop_in_place_intrinsic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 def_id: DefId,
@@ -729,7 +732,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
         assert!(can_have_local_instance(scx.tcx(), exchange_free_fn_def_id));
         let fn_substs = scx.empty_substs_for_def_id(exchange_free_fn_def_id);
         let exchange_free_fn_trans_item =
-            create_fn_trans_item(scx.tcx(),
+            create_fn_trans_item(scx,
                                  exchange_free_fn_def_id,
                                  fn_substs,
                                  Substs::empty(scx.tcx()));
@@ -753,7 +756,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                                    .drop_trait()
                                    .unwrap();
 
-        let self_type_substs = Substs::new_trait(scx.tcx(), vec![], vec![], ty);
+        let self_type_substs = Substs::new_trait(scx.tcx(), ty, &[]);
 
         let trait_ref = ty::TraitRef {
             def_id: drop_trait_def_id,
@@ -766,7 +769,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
         };
 
         if can_have_local_instance(scx.tcx(), destructor_did) {
-            let trans_item = create_fn_trans_item(scx.tcx(),
+            let trans_item = create_fn_trans_item(scx,
                                                   destructor_did,
                                                   substs,
                                                   Substs::empty(scx.tcx()));
@@ -797,7 +800,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
         ty::TyStruct(ref adt_def, substs) |
         ty::TyEnum(ref adt_def, substs) => {
             for field in adt_def.all_fields() {
-                let field_type = monomorphize::apply_param_substs(scx.tcx(),
+                let field_type = monomorphize::apply_param_substs(scx,
                                                                   substs,
                                                                   &field.unsubst_ty());
                 let field_type = glue::get_drop_glue_type(scx.tcx(), field_type);
@@ -891,8 +894,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
            callee_substs,
            param_substs);
 
-
-    let rcvr_substs = monomorphize::apply_param_substs(tcx,
+    let rcvr_substs = monomorphize::apply_param_substs(scx,
                                                        param_substs,
                                                        &callee_substs);
     let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
@@ -1013,11 +1015,13 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
     }
 }
 
-fn create_fn_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+fn create_fn_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                                   def_id: DefId,
                                   fn_substs: &'tcx Substs<'tcx>,
                                   param_substs: &'tcx Substs<'tcx>)
                                   -> TransItem<'tcx> {
+    let tcx = scx.tcx();
+
     debug!("create_fn_trans_item(def_id={}, fn_substs={:?}, param_substs={:?})",
             def_id_to_string(tcx, def_id),
             fn_substs,
@@ -1026,7 +1030,7 @@ fn create_fn_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // We only get here, if fn_def_id either designates a local item or
     // an inlineable external item. Non-inlineable external items are
     // ignored because we don't want to generate any code for them.
-    let concrete_substs = monomorphize::apply_param_substs(tcx,
+    let concrete_substs = monomorphize::apply_param_substs(scx,
                                                            param_substs,
                                                            &fn_substs);
     assert!(concrete_substs.is_normalized_for_trans());
@@ -1060,7 +1064,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
                         // create translation items
                         .filter_map(|impl_method| {
                             if can_have_local_instance(scx.tcx(), impl_method.method.def_id) {
-                                Some(create_fn_trans_item(scx.tcx(),
+                                Some(create_fn_trans_item(scx,
                                     impl_method.method.def_id,
                                     impl_method.substs,
                                     Substs::empty(scx.tcx())))
@@ -1111,7 +1115,7 @@ fn visit_item(&mut self, item: &'v hir::Item) {
 
             hir::ItemImpl(..) => {
                 if self.mode == TransItemCollectionMode::Eager {
-                    create_trans_items_for_default_impls(self.scx.tcx(),
+                    create_trans_items_for_default_impls(self.scx,
                                                          item,
                                                          self.output);
                 }
@@ -1199,9 +1203,10 @@ fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
     }
 }
 
-fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                                                   item: &'tcx hir::Item,
                                                   output: &mut Vec<TransItem<'tcx>>) {
+    let tcx = scx.tcx();
     match item.node {
         hir::ItemImpl(_,
                       _,
@@ -1235,7 +1240,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     // The substitutions we have are on the impl, so we grab
                     // the method type from the impl to substitute into.
                     let impl_substs = Substs::for_item(tcx, impl_def_id,
-                                                       |_, _| ty::ReErased,
+                                                       |_, _| tcx.mk_region(ty::ReErased),
                                                        |_, _| tcx.types.err);
                     let mth = meth::get_impl_method(tcx,
                                                     callee_substs,
@@ -1252,7 +1257,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
                     if can_have_local_instance(tcx, method.def_id) {
                         let empty_substs = tcx.erase_regions(&mth.substs);
-                        let item = create_fn_trans_item(tcx,
+                        let item = create_fn_trans_item(scx,
                                                         method.def_id,
                                                         callee_substs,
                                                         empty_substs);
index b1aaea7d984c9ee4d20b04927b1f04ba8b578ac0..f4682de7dff6af3aceec52ab6699a8bc6dd04fb3 100644 (file)
@@ -16,7 +16,6 @@
 use llvm;
 use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef, TypeKind};
 use llvm::{True, False, Bool, OperandBundleDef};
-use rustc::cfg;
 use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::infer::TransNormalize;
@@ -30,7 +29,6 @@
 use callee::Callee;
 use cleanup;
 use consts;
-use datum;
 use debuginfo::{self, DebugLoc};
 use declare;
 use machine;
@@ -43,7 +41,6 @@
 use rustc::traits::{self, SelectionContext, Reveal};
 use rustc::ty::fold::TypeFoldable;
 use rustc::hir;
-use util::nodemap::NodeMap;
 
 use arena::TypedArena;
 use libc::{c_uint, c_char};
@@ -127,18 +124,7 @@ pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
 /// Returns true if the type is represented as a pair of immediates.
 pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
                                   -> bool {
-    let tcx = ccx.tcx();
-    let layout = tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
-        match ty.layout(&infcx) {
-            Ok(layout) => layout,
-            Err(err) => {
-                bug!("type_is_imm_pair: layout for `{:?}` failed: {}",
-                     ty, err);
-            }
-        }
-    });
-
-    match *layout {
+    match *ccx.layout_of(ty) {
         Layout::FatPointer { .. } => true,
         Layout::Univariant { ref variant, .. } => {
             // There must be only 2 fields.
@@ -202,16 +188,6 @@ pub fn gensym_name(name: &str) -> ast::Name {
 
 use Disr;
 
-#[derive(Copy, Clone)]
-pub struct NodeIdAndSpan {
-    pub id: ast::NodeId,
-    pub span: Span,
-}
-
-pub fn expr_info(expr: &hir::Expr) -> NodeIdAndSpan {
-    NodeIdAndSpan { id: expr.id, span: expr.span }
-}
-
 /// The concrete version of ty::FieldDef. The name is the field index if
 /// the field is numeric.
 pub struct Field<'tcx>(pub ast::Name, pub Ty<'tcx>);
@@ -257,17 +233,6 @@ pub fn from_ty(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
         }
     }
-
-    /// Return the variant corresponding to a given node (e.g. expr)
-    pub fn of_node(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, id: ast::NodeId) -> Self {
-        Self::from_ty(tcx, ty, Some(tcx.expect_def(id)))
-    }
-
-    pub fn field_index(&self, name: ast::Name) -> usize {
-        self.fields.iter().position(|&Field(n,_)| n == name).unwrap_or_else(|| {
-            bug!("unknown field `{}`", name)
-        })
-    }
 }
 
 pub struct BuilderRef_res {
@@ -289,38 +254,7 @@ pub fn BuilderRef_res(b: BuilderRef) -> BuilderRef_res {
 }
 
 pub fn validate_substs(substs: &Substs) {
-    assert!(!substs.types.needs_infer());
-}
-
-// work around bizarre resolve errors
-type RvalueDatum<'tcx> = datum::Datum<'tcx, datum::Rvalue>;
-pub type LvalueDatum<'tcx> = datum::Datum<'tcx, datum::Lvalue>;
-
-#[derive(Clone, Debug)]
-struct HintEntry<'tcx> {
-    // The datum for the dropflag-hint itself; note that many
-    // source-level Lvalues will be associated with the same
-    // dropflag-hint datum.
-    datum: cleanup::DropHintDatum<'tcx>,
-}
-
-pub struct DropFlagHintsMap<'tcx> {
-    // Maps NodeId for expressions that read/write unfragmented state
-    // to that state's drop-flag "hint."  (A stack-local hint
-    // indicates either that (1.) it is certain that no-drop is
-    // needed, or (2.)  inline drop-flag must be consulted.)
-    node_map: NodeMap<HintEntry<'tcx>>,
-}
-
-impl<'tcx> DropFlagHintsMap<'tcx> {
-    pub fn new() -> DropFlagHintsMap<'tcx> { DropFlagHintsMap { node_map: NodeMap() } }
-    pub fn has_hint(&self, id: ast::NodeId) -> bool { self.node_map.contains_key(&id) }
-    pub fn insert(&mut self, id: ast::NodeId, datum: cleanup::DropHintDatum<'tcx>) {
-        self.node_map.insert(id, HintEntry { datum: datum });
-    }
-    pub fn hint_datum(&self, id: ast::NodeId) -> Option<cleanup::DropHintDatum<'tcx>> {
-        self.node_map.get(&id).map(|t|t.datum)
-    }
+    assert!(!substs.needs_infer());
 }
 
 // Function context.  Every LLVM function we create will have one of
@@ -352,12 +286,6 @@ pub struct FunctionContext<'a, 'tcx: 'a> {
     // A marker for the place where we want to insert the function's static
     // allocas, so that LLVM will coalesce them into a single alloca call.
     pub alloca_insert_pt: Cell<Option<ValueRef>>,
-    pub llreturn: Cell<Option<BasicBlockRef>>,
-
-    // If the function has any nested return's, including something like:
-    // fn foo() -> Option<Foo> { Some(Foo { x: return None }) }, then
-    // we use a separate alloca for each return
-    pub needs_ret_allocas: bool,
 
     // When working with landingpad-based exceptions this value is alloca'd and
     // later loaded when using the resume instruction. This ends up being
@@ -367,17 +295,6 @@ pub struct FunctionContext<'a, 'tcx: 'a> {
     // Note that for cleanuppad-based exceptions this is not used.
     pub landingpad_alloca: Cell<Option<ValueRef>>,
 
-    // Maps the DefId's for local variables to the allocas created for
-    // them in llallocas.
-    pub lllocals: RefCell<NodeMap<LvalueDatum<'tcx>>>,
-
-    // Same as above, but for closure upvars
-    pub llupvars: RefCell<NodeMap<ValueRef>>,
-
-    // Carries info about drop-flags for local bindings (longer term,
-    // paths) for the code being compiled.
-    pub lldropflag_hints: RefCell<DropFlagHintsMap<'tcx>>,
-
     // Describes the return/argument LLVM types and their ABI handling.
     pub fn_ty: FnType,
 
@@ -402,9 +319,7 @@ pub struct FunctionContext<'a, 'tcx: 'a> {
     pub debug_context: debuginfo::FunctionDebugContext,
 
     // Cleanup scopes.
-    pub scopes: RefCell<Vec<cleanup::CleanupScope<'a, 'tcx>>>,
-
-    pub cfg: Option<cfg::CFG>,
+    pub scopes: RefCell<Vec<cleanup::CleanupScope<'tcx>>>,
 }
 
 impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
@@ -420,74 +335,22 @@ pub fn cleanup(&self) {
         }
     }
 
-    pub fn get_llreturn(&self) -> BasicBlockRef {
-        if self.llreturn.get().is_none() {
-
-            self.llreturn.set(Some(unsafe {
-                llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn,
-                                                    "return\0".as_ptr() as *const _)
-            }))
-        }
-
-        self.llreturn.get().unwrap()
-    }
-
-    pub fn get_ret_slot(&self, bcx: Block<'a, 'tcx>, name: &str) -> ValueRef {
-        if self.needs_ret_allocas {
-            base::alloca(bcx, self.fn_ty.ret.memory_ty(self.ccx), name)
-        } else {
-            self.llretslotptr.get().unwrap()
-        }
-    }
-
     pub fn new_block(&'a self,
-                     name: &str,
-                     opt_node_id: Option<ast::NodeId>)
+                     name: &str)
                      -> Block<'a, 'tcx> {
         unsafe {
             let name = CString::new(name).unwrap();
             let llbb = llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(),
                                                            self.llfn,
                                                            name.as_ptr());
-            BlockS::new(llbb, opt_node_id, self)
+            BlockS::new(llbb, self)
         }
     }
 
-    pub fn new_id_block(&'a self,
-                        name: &str,
-                        node_id: ast::NodeId)
-                        -> Block<'a, 'tcx> {
-        self.new_block(name, Some(node_id))
-    }
-
-    pub fn new_temp_block(&'a self,
-                          name: &str)
-                          -> Block<'a, 'tcx> {
-        self.new_block(name, None)
-    }
-
-    pub fn join_blocks(&'a self,
-                       id: ast::NodeId,
-                       in_cxs: &[Block<'a, 'tcx>])
-                       -> Block<'a, 'tcx> {
-        let out = self.new_id_block("join", id);
-        let mut reachable = false;
-        for bcx in in_cxs {
-            if !bcx.unreachable.get() {
-                build::Br(*bcx, out.llbb, DebugLoc::None);
-                reachable = true;
-            }
-        }
-        if !reachable {
-            build::Unreachable(out);
-        }
-        return out;
-    }
-
     pub fn monomorphize<T>(&self, value: &T) -> T
         where T: TransNormalize<'tcx>
     {
-        monomorphize::apply_param_substs(self.ccx.tcx(),
+        monomorphize::apply_param_substs(self.ccx.shared(),
                                          self.param_substs,
                                          value)
     }
@@ -523,7 +386,7 @@ pub fn eh_personality(&self) -> ValueRef {
         let tcx = ccx.tcx();
         match tcx.lang_items.eh_personality() {
             Some(def_id) if !base::wants_msvc_seh(ccx.sess()) => {
-                Callee::def(ccx, def_id, Substs::empty(tcx)).reify(ccx).val
+                Callee::def(ccx, def_id, Substs::empty(tcx)).reify(ccx)
             }
             _ => {
                 if let Some(llpersonality) = ccx.eh_personality().get() {
@@ -565,12 +428,12 @@ pub fn eh_unwind_resume(&self) -> Callee<'tcx> {
 
         let unwresume = ccx.eh_unwind_resume();
         if let Some(llfn) = unwresume.get() {
-            return Callee::ptr(datum::immediate_rvalue(llfn, ty));
+            return Callee::ptr(llfn, ty);
         }
         let llfn = declare::declare_fn(ccx, "rust_eh_unwind_resume", ty);
         attributes::unwind(llfn, true);
         unwresume.set(Some(llfn));
-        Callee::ptr(datum::immediate_rvalue(llfn, ty))
+        Callee::ptr(llfn, ty)
     }
 }
 
@@ -593,10 +456,6 @@ pub struct BlockS<'blk, 'tcx: 'blk> {
     // kind of landing pad its in, otherwise this is none.
     pub lpad: Cell<Option<&'blk LandingPad>>,
 
-    // AST node-id associated with this block, if any. Used for
-    // debugging purposes only.
-    pub opt_node_id: Option<ast::NodeId>,
-
     // The function context for the function to which this block is
     // attached.
     pub fcx: &'blk FunctionContext<'blk, 'tcx>,
@@ -606,7 +465,6 @@ pub struct BlockS<'blk, 'tcx: 'blk> {
 
 impl<'blk, 'tcx> BlockS<'blk, 'tcx> {
     pub fn new(llbb: BasicBlockRef,
-               opt_node_id: Option<ast::NodeId>,
                fcx: &'blk FunctionContext<'blk, 'tcx>)
                -> Block<'blk, 'tcx> {
         fcx.block_arena.alloc(BlockS {
@@ -614,7 +472,6 @@ pub fn new(llbb: BasicBlockRef,
             terminated: Cell::new(false),
             unreachable: Cell::new(false),
             lpad: Cell::new(None),
-            opt_node_id: opt_node_id,
             fcx: fcx
         })
     }
@@ -662,7 +519,7 @@ pub fn to_str(&self) -> String {
     pub fn monomorphize<T>(&self, value: &T) -> T
         where T: TransNormalize<'tcx>
     {
-        monomorphize::apply_param_substs(self.tcx(),
+        monomorphize::apply_param_substs(self.fcx.ccx.shared(),
                                          self.fcx.param_substs,
                                          value)
     }
@@ -883,13 +740,6 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef {
     }
 }
 
-pub fn C_floating(s: &str, t: Type) -> ValueRef {
-    unsafe {
-        let s = CString::new(s).unwrap();
-        llvm::LLVMConstRealOfString(t.to_ref(), s.as_ptr())
-    }
-}
-
 pub fn C_floating_f64(f: f64, t: Type) -> ValueRef {
     unsafe {
         llvm::LLVMConstReal(t.to_ref(), f)
@@ -916,19 +766,6 @@ pub fn C_u64(ccx: &CrateContext, i: u64) -> ValueRef {
     C_integral(Type::i64(ccx), i, false)
 }
 
-pub fn C_int<I: AsI64>(ccx: &CrateContext, i: I) -> ValueRef {
-    let v = i.as_i64();
-
-    let bit_size = machine::llbitsize_of_real(ccx, ccx.int_type());
-
-    if bit_size < 64 {
-        // make sure it doesn't overflow
-        assert!(v < (1<<(bit_size-1)) && v >= -(1<<(bit_size-1)));
-    }
-
-    C_integral(ccx.int_type(), v as u64, true)
-}
-
 pub fn C_uint<I: AsU64>(ccx: &CrateContext, i: I) -> ValueRef {
     let v = i.as_u64();
 
@@ -1099,24 +936,6 @@ pub fn is_null(val: ValueRef) -> bool {
     }
 }
 
-pub fn monomorphize_type<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, t: Ty<'tcx>) -> Ty<'tcx> {
-    bcx.fcx.monomorphize(&t)
-}
-
-pub fn node_id_type<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, id: ast::NodeId) -> Ty<'tcx> {
-    let tcx = bcx.tcx();
-    let t = tcx.node_id_to_type(id);
-    monomorphize_type(bcx, t)
-}
-
-pub fn expr_ty<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, ex: &hir::Expr) -> Ty<'tcx> {
-    node_id_type(bcx, ex.id)
-}
-
-pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, ex: &hir::Expr) -> Ty<'tcx> {
-    monomorphize_type(bcx, bcx.tcx().expr_ty_adjusted(ex))
-}
-
 /// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we
 /// do not (necessarily) resolve all nested obligations on the impl. Note that type check should
 /// guarantee to us that all nested obligations *could be* resolved if we wanted to.
@@ -1136,7 +955,7 @@ pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 
         // Do the initial selection for the obligation. This yields the
         // shallow result we are looking for -- that is, what specific impl.
-        tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
+        tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
             let mut selcx = SelectionContext::new(&infcx);
 
             let obligation_cause = traits::ObligationCause::misc(span,
@@ -1195,7 +1014,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     debug!("normalize_and_test_predicates(predicates={:?})",
            predicates);
 
-    tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
+    tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
         let mut selcx = SelectionContext::new(&infcx);
         let mut fulfill_cx = traits::FulfillmentContext::new();
         let cause = traits::ObligationCause::dummy();
@@ -1209,7 +1028,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             fulfill_cx.register_predicate_obligation(&infcx, obligation);
         }
 
-        infcx.drain_fulfillment_cx(&mut fulfill_cx, &()).is_ok()
+        fulfill_cx.select_all_or_error(&infcx).is_ok()
     })
 }
 
@@ -1230,34 +1049,6 @@ pub fn langcall(tcx: TyCtxt,
     }
 }
 
-/// Return the VariantDef corresponding to an inlined variant node
-pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                     inlined_vid: ast::NodeId)
-                                     -> ty::VariantDef<'tcx>
-{
-    let ctor_ty = ccx.tcx().node_id_to_type(inlined_vid);
-    debug!("inlined_variant_def: ctor_ty={:?} inlined_vid={:?}", ctor_ty,
-           inlined_vid);
-    let adt_def = match ctor_ty.sty {
-        ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
-            output, ..
-        }), ..}) => output,
-        _ => ctor_ty
-    }.ty_adt_def().unwrap();
-    let variant_def_id = if ccx.tcx().map.is_inlined_node_id(inlined_vid) {
-        ccx.defid_for_inlined_node(inlined_vid).unwrap()
-    } else {
-        ccx.tcx().map.local_def_id(inlined_vid)
-    };
-
-    adt_def.variants
-           .iter()
-           .find(|v| variant_def_id == v.did)
-           .unwrap_or_else(|| {
-                bug!("no variant for {:?}::{}", adt_def, inlined_vid)
-            })
-}
-
 // To avoid UB from LLVM, these two functions mask RHS with an
 // appropriate mask unconditionally (i.e. the fallback behavior for
 // all shifts). For 32- and 64-bit types, this matches the semantics
index 0e9898896778c0a0b577b5f864694db6c1927493..2b6e2a23261bdf21c073c45f6f7d047c22f05616 100644 (file)
 
 use llvm;
 use llvm::{SetUnnamedAddr};
-use llvm::{InternalLinkage, ValueRef, Bool, True};
-use middle::const_qualif::ConstQualif;
-use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, lookup_const_by_id, ErrKind};
-use rustc_const_eval::{eval_length, report_const_eval_err, note_const_eval_err};
-use rustc::hir::def::Def;
+use llvm::{InternalLinkage, ValueRef, True};
+use rustc_const_eval::ConstEvalErr;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map as hir_map;
-use {abi, adt, closure, debuginfo, expr, machine};
+use {debuginfo, machine};
 use base::{self, push_ctxt};
-use callee::Callee;
 use trans_item::TransItem;
-use common::{type_is_sized, C_nil, const_get_elt};
-use common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty};
-use common::{C_struct, C_undef, const_to_opt_int, const_to_opt_uint, VariantInfo, C_uint};
-use common::{type_is_fat_ptr, Field, C_vector, C_array, C_null};
-use datum::{Datum, Lvalue};
+use common::{CrateContext, val_ty};
 use declare;
-use monomorphize::{self, Instance};
+use monomorphize::{Instance};
 use type_::Type;
 use type_of;
-use value::Value;
-use Disr;
-use rustc::ty::subst::Substs;
-use rustc::ty::adjustment::{AdjustNeverToAny, AdjustDerefRef, AdjustReifyFnPointer};
-use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::cast::{CastTy,IntTy};
-use util::nodemap::NodeMap;
-use rustc_const_math::{ConstInt, ConstUsize, ConstIsize};
+use rustc::ty;
 
 use rustc::hir;
 
 use std::ffi::{CStr, CString};
-use libc::c_uint;
-use syntax::ast::{self, LitKind};
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::ast;
+use syntax::attr;
 use syntax::parse::token;
-use syntax::ptr::P;
-use syntax_pos::Span;
-
-pub type FnArgMap<'a> = Option<&'a NodeMap<ValueRef>>;
-
-pub fn const_lit(cx: &CrateContext, e: &hir::Expr, lit: &ast::Lit)
-    -> ValueRef {
-    let _icx = push_ctxt("trans_lit");
-    debug!("const_lit: {:?}", lit);
-    match lit.node {
-        LitKind::Byte(b) => C_integral(Type::uint_from_ty(cx, ast::UintTy::U8), b as u64, false),
-        LitKind::Char(i) => C_integral(Type::char(cx), i as u64, false),
-        LitKind::Int(i, ast::LitIntType::Signed(t)) => {
-            C_integral(Type::int_from_ty(cx, t), i, true)
-        }
-        LitKind::Int(u, ast::LitIntType::Unsigned(t)) => {
-            C_integral(Type::uint_from_ty(cx, t), u, false)
-        }
-        LitKind::Int(i, ast::LitIntType::Unsuffixed) => {
-            let lit_int_ty = cx.tcx().node_id_to_type(e.id);
-            match lit_int_ty.sty {
-                ty::TyInt(t) => {
-                    C_integral(Type::int_from_ty(cx, t), i as u64, true)
-                }
-                ty::TyUint(t) => {
-                    C_integral(Type::uint_from_ty(cx, t), i as u64, false)
-                }
-                _ => span_bug!(lit.span,
-                        "integer literal has type {:?} (expected int \
-                         or usize)",
-                        lit_int_ty)
-            }
-        }
-        LitKind::Float(ref fs, t) => {
-            C_floating(&fs, Type::float_from_ty(cx, t))
-        }
-        LitKind::FloatUnsuffixed(ref fs) => {
-            let lit_float_ty = cx.tcx().node_id_to_type(e.id);
-            match lit_float_ty.sty {
-                ty::TyFloat(t) => {
-                    C_floating(&fs, Type::float_from_ty(cx, t))
-                }
-                _ => {
-                    span_bug!(lit.span,
-                        "floating point literal doesn't have the right type");
-                }
-            }
-        }
-        LitKind::Bool(b) => C_bool(cx, b),
-        LitKind::Str(ref s, _) => C_str_slice(cx, (*s).clone()),
-        LitKind::ByteStr(ref data) => {
-            addr_of(cx, C_bytes(cx, &data[..]), 1, "byte_str")
-        }
-    }
-}
 
 pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef {
     unsafe {
@@ -154,868 +82,13 @@ pub fn addr_of(ccx: &CrateContext,
     gv
 }
 
-/// Deref a constant pointer
-pub fn load_const(cx: &CrateContext, v: ValueRef, t: Ty) -> ValueRef {
-    let v = match cx.const_unsized().borrow().get(&v) {
-        Some(&v) => v,
-        None => v
-    };
-    let d = unsafe { llvm::LLVMGetInitializer(v) };
-    if !d.is_null() && t.is_bool() {
-        unsafe { llvm::LLVMConstTrunc(d, Type::i1(cx).to_ref()) }
-    } else {
-        d
-    }
-}
-
-fn const_deref<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                         v: ValueRef,
-                         ty: Ty<'tcx>)
-                         -> (ValueRef, Ty<'tcx>) {
-    match ty.builtin_deref(true, ty::NoPreference) {
-        Some(mt) => {
-            if type_is_sized(cx.tcx(), mt.ty) {
-                (load_const(cx, v, mt.ty), mt.ty)
-            } else {
-                // Derefing a fat pointer does not change the representation,
-                // just the type to the unsized contents.
-                (v, mt.ty)
-            }
-        }
-        None => {
-            bug!("unexpected dereferenceable type {:?}", ty)
-        }
-    }
-}
-
-fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                           def_id: DefId,
-                           substs: &'tcx Substs<'tcx>,
-                           arg_vals: &[ValueRef],
-                           param_substs: &'tcx Substs<'tcx>,
-                           trueconst: TrueConst) -> Result<ValueRef, ConstEvalFailure> {
-    let fn_like = lookup_const_fn_by_id(ccx.tcx(), def_id);
-    let fn_like = fn_like.expect("lookup_const_fn_by_id failed in const_fn_call");
-
-    let body = match fn_like.body().expr {
-        Some(ref expr) => expr,
-        None => return Ok(C_nil(ccx))
-    };
-
-    let args = &fn_like.decl().inputs;
-    assert_eq!(args.len(), arg_vals.len());
-
-    let arg_ids = args.iter().map(|arg| arg.pat.id);
-    let fn_args = arg_ids.zip(arg_vals.iter().cloned()).collect();
-
-    let substs = ccx.tcx().erase_regions(&substs);
-    let substs = monomorphize::apply_param_substs(ccx.tcx(),
-                                                  param_substs,
-                                                  &substs);
-
-    const_expr(ccx, body, substs, Some(&fn_args), trueconst).map(|(res, _)| res)
-}
-
-pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                def_id: DefId,
-                                ref_expr: &hir::Expr,
-                                param_substs: &'tcx Substs<'tcx>)
-                                -> &'tcx hir::Expr {
-    let substs = ccx.tcx().node_id_item_substs(ref_expr.id).substs;
-    let substs = ccx.tcx().erase_regions(&substs);
-    let substs = monomorphize::apply_param_substs(ccx.tcx(),
-                                                  param_substs,
-                                                  &substs);
-    match lookup_const_by_id(ccx.tcx(), def_id, Some(substs)) {
-        Some((ref expr, _ty)) => expr,
-        None => {
-            span_bug!(ref_expr.span, "constant item not found")
-        }
-    }
-}
-
-pub enum ConstEvalFailure {
-    /// in case the const evaluator failed on something that panic at runtime
-    /// as defined in RFC 1229
-    Runtime(ConstEvalErr),
-    // in case we found a true constant
-    Compiletime(ConstEvalErr),
-}
-
-impl ConstEvalFailure {
-    fn into_inner(self) -> ConstEvalErr {
-        match self {
-            Runtime(e) => e,
-            Compiletime(e) => e,
-        }
-    }
-
-    pub fn as_inner(&self) -> &ConstEvalErr {
-        match self {
-            &Runtime(ref e) => e,
-            &Compiletime(ref e) => e,
-        }
-    }
-}
-
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub enum TrueConst {
-    Yes, No
-}
-
-use self::ConstEvalFailure::*;
-
-fn get_const_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                           def_id: DefId,
-                           ref_expr: &hir::Expr,
-                           param_substs: &'tcx Substs<'tcx>)
-                           -> Result<ValueRef, ConstEvalFailure> {
-    let expr = get_const_expr(ccx, def_id, ref_expr, param_substs);
-    let empty_substs = Substs::empty(ccx.tcx());
-    match get_const_expr_as_global(ccx, expr, ConstQualif::empty(), empty_substs, TrueConst::Yes) {
-        Err(Runtime(err)) => {
-            report_const_eval_err(ccx.tcx(), &err, expr.span, "expression").emit();
-            Err(Compiletime(err))
-        },
-        other => other,
-    }
-}
-
-pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                          expr: &hir::Expr,
-                                          qualif: ConstQualif,
-                                          param_substs: &'tcx Substs<'tcx>,
-                                          trueconst: TrueConst)
-                                          -> Result<ValueRef, ConstEvalFailure> {
-    debug!("get_const_expr_as_global: {:?}", expr.id);
-    // Special-case constants to cache a common global for all uses.
-    if let hir::ExprPath(..) = expr.node {
-        // `def` must be its own statement and cannot be in the `match`
-        // otherwise the `def_map` will be borrowed for the entire match instead
-        // of just to get the `def` value
-        match ccx.tcx().expect_def(expr.id) {
-            Def::Const(def_id) | Def::AssociatedConst(def_id) => {
-                if !ccx.tcx().tables.borrow().adjustments.contains_key(&expr.id) {
-                    debug!("get_const_expr_as_global ({:?}): found const {:?}",
-                           expr.id, def_id);
-                    return get_const_val(ccx, def_id, expr, param_substs);
-                }
-            },
-            _ => {},
-        }
-    }
-
-    let key = (expr.id, param_substs);
-    if let Some(&val) = ccx.const_values().borrow().get(&key) {
-        return Ok(val);
-    }
-    let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs,
-                                              &ccx.tcx().expr_ty(expr));
-    let val = if qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
-        // Avoid autorefs as they would create global instead of stack
-        // references, even when only the latter are correct.
-        const_expr_unadjusted(ccx, expr, ty, param_substs, None, trueconst)?
-    } else {
-        const_expr(ccx, expr, param_substs, None, trueconst)?.0
-    };
-
-    // boolean SSA values are i1, but they have to be stored in i8 slots,
-    // otherwise some LLVM optimization passes don't work as expected
-    let val = unsafe {
-        if llvm::LLVMTypeOf(val) == Type::i1(ccx).to_ref() {
-            llvm::LLVMConstZExt(val, Type::i8(ccx).to_ref())
-        } else {
-            val
-        }
-    };
-
-    let lvalue = addr_of(ccx, val, type_of::align_of(ccx, ty), "const");
-    ccx.const_values().borrow_mut().insert(key, lvalue);
-    Ok(lvalue)
-}
-
-pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                            e: &hir::Expr,
-                            param_substs: &'tcx Substs<'tcx>,
-                            fn_args: FnArgMap,
-                            trueconst: TrueConst)
-                            -> Result<(ValueRef, Ty<'tcx>), ConstEvalFailure> {
-    let ety = monomorphize::apply_param_substs(cx.tcx(), param_substs,
-                                               &cx.tcx().expr_ty(e));
-    let llconst = const_expr_unadjusted(cx, e, ety, param_substs, fn_args, trueconst)?;
-    let mut llconst = llconst;
-    let mut ety_adjusted = monomorphize::apply_param_substs(cx.tcx(), param_substs,
-                                                            &cx.tcx().expr_ty_adjusted(e));
-    let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned();
-    match opt_adj {
-        Some(AdjustNeverToAny(..)) => span_bug!(e.span, "const expression of type ! encountered"),
-        Some(AdjustReifyFnPointer) => {
-            match ety.sty {
-                ty::TyFnDef(def_id, substs, _) => {
-                    llconst = Callee::def(cx, def_id, substs).reify(cx).val;
-                }
-                _ => {
-                    bug!("{} cannot be reified to a fn ptr", ety)
-                }
-            }
-        }
-        Some(AdjustUnsafeFnPointer) | Some(AdjustMutToConstPointer) => {
-            // purely a type-level thing
-        }
-        Some(AdjustDerefRef(adj)) => {
-            let mut ty = ety;
-            // Save the last autoderef in case we can avoid it.
-            if adj.autoderefs > 0 {
-                for _ in 0..adj.autoderefs-1 {
-                    let (dv, dt) = const_deref(cx, llconst, ty);
-                    llconst = dv;
-                    ty = dt;
-                }
-            }
-
-            if adj.autoref.is_some() {
-                if adj.autoderefs == 0 {
-                    // Don't copy data to do a deref+ref
-                    // (i.e., skip the last auto-deref).
-                    llconst = addr_of(cx, llconst, type_of::align_of(cx, ty), "autoref");
-                    ty = cx.tcx().mk_imm_ref(cx.tcx().mk_region(ty::ReErased), ty);
-                }
-            } else if adj.autoderefs > 0 {
-                let (dv, dt) = const_deref(cx, llconst, ty);
-                llconst = dv;
-
-                // If we derefed a fat pointer then we will have an
-                // open type here. So we need to update the type with
-                // the one returned from const_deref.
-                ety_adjusted = dt;
-            }
-
-            if let Some(target) = adj.unsize {
-                let target = monomorphize::apply_param_substs(cx.tcx(),
-                                                              param_substs,
-                                                              &target);
-
-                let pointee_ty = ty.builtin_deref(true, ty::NoPreference)
-                    .expect("consts: unsizing got non-pointer type").ty;
-                let (base, old_info) = if !type_is_sized(cx.tcx(), pointee_ty) {
-                    // Normally, the source is a thin pointer and we are
-                    // adding extra info to make a fat pointer. The exception
-                    // is when we are upcasting an existing object fat pointer
-                    // to use a different vtable. In that case, we want to
-                    // load out the original data pointer so we can repackage
-                    // it.
-                    (const_get_elt(llconst, &[abi::FAT_PTR_ADDR as u32]),
-                     Some(const_get_elt(llconst, &[abi::FAT_PTR_EXTRA as u32])))
-                } else {
-                    (llconst, None)
-                };
-
-                let unsized_ty = target.builtin_deref(true, ty::NoPreference)
-                    .expect("consts: unsizing got non-pointer target type").ty;
-                let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
-                let base = ptrcast(base, ptr_ty);
-                let info = base::unsized_info(cx, pointee_ty, unsized_ty, old_info);
-
-                if old_info.is_none() {
-                    let prev_const = cx.const_unsized().borrow_mut()
-                                       .insert(base, llconst);
-                    assert!(prev_const.is_none() || prev_const == Some(llconst));
-                }
-                assert_eq!(abi::FAT_PTR_ADDR, 0);
-                assert_eq!(abi::FAT_PTR_EXTRA, 1);
-                llconst = C_struct(cx, &[base, info], false);
-            }
-        }
-        None => {}
-    };
-
-    let llty = type_of::sizing_type_of(cx, ety_adjusted);
-    let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
-    let tsize = machine::llsize_of_alloc(cx, llty);
-    if csize != tsize {
-        cx.sess().abort_if_errors();
-        unsafe {
-            // FIXME these values could use some context
-            llvm::LLVMDumpValue(llconst);
-            llvm::LLVMDumpValue(C_undef(llty));
-        }
-        bug!("const {:?} of type {:?} has size {} instead of {}",
-             e, ety_adjusted,
-             csize, tsize);
-    }
-    Ok((llconst, ety_adjusted))
-}
-
-fn check_unary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
-                             te: ValueRef, trueconst: TrueConst) -> Result<(), ConstEvalFailure> {
-    // The only kind of unary expression that we check for validity
-    // here is `-expr`, to check if it "overflows" (e.g. `-i32::MIN`).
-    if let hir::ExprUnary(hir::UnNeg, ref inner_e) = e.node {
-
-        // An unfortunate special case: we parse e.g. -128 as a
-        // negation of the literal 128, which means if we're expecting
-        // a i8 (or if it was already suffixed, e.g. `-128_i8`), then
-        // 128 will have already overflowed to -128, and so then the
-        // constant evaluator thinks we're trying to negate -128.
-        //
-        // Catch this up front by looking for ExprLit directly,
-        // and just accepting it.
-        if let hir::ExprLit(_) = inner_e.node { return Ok(()); }
-        let cval = match to_const_int(te, t, cx.tcx()) {
-            Some(v) => v,
-            None => return Ok(()),
-        };
-        const_err(cx, e.span, (-cval).map_err(ErrKind::Math), trueconst)?;
-    }
-    Ok(())
-}
-
-pub fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
-    match t.sty {
-        ty::TyInt(int_type) => const_to_opt_int(value).and_then(|input| match int_type {
-            ast::IntTy::I8 => {
-                assert_eq!(input as i8 as i64, input);
-                Some(ConstInt::I8(input as i8))
-            },
-            ast::IntTy::I16 => {
-                assert_eq!(input as i16 as i64, input);
-                Some(ConstInt::I16(input as i16))
-            },
-            ast::IntTy::I32 => {
-                assert_eq!(input as i32 as i64, input);
-                Some(ConstInt::I32(input as i32))
-            },
-            ast::IntTy::I64 => {
-                Some(ConstInt::I64(input))
-            },
-            ast::IntTy::Is => {
-                ConstIsize::new(input, tcx.sess.target.int_type)
-                    .ok().map(ConstInt::Isize)
-            },
-        }),
-        ty::TyUint(uint_type) => const_to_opt_uint(value).and_then(|input| match uint_type {
-            ast::UintTy::U8 => {
-                assert_eq!(input as u8 as u64, input);
-                Some(ConstInt::U8(input as u8))
-            },
-            ast::UintTy::U16 => {
-                assert_eq!(input as u16 as u64, input);
-                Some(ConstInt::U16(input as u16))
-            },
-            ast::UintTy::U32 => {
-                assert_eq!(input as u32 as u64, input);
-                Some(ConstInt::U32(input as u32))
-            },
-            ast::UintTy::U64 => {
-                Some(ConstInt::U64(input))
-            },
-            ast::UintTy::Us => {
-                ConstUsize::new(input, tcx.sess.target.uint_type)
-                    .ok().map(ConstInt::Usize)
-            },
-        }),
-        _ => None,
-    }
-}
-
-pub fn const_err<T>(cx: &CrateContext,
-                    span: Span,
-                    result: Result<T, ErrKind>,
-                    trueconst: TrueConst)
-                    -> Result<T, ConstEvalFailure> {
-    match (result, trueconst) {
-        (Ok(x), _) => Ok(x),
-        (Err(err), TrueConst::Yes) => {
-            let err = ConstEvalErr{ span: span, kind: err };
-            report_const_eval_err(cx.tcx(), &err, span, "expression").emit();
-            Err(Compiletime(err))
-        },
-        (Err(err), TrueConst::No) => {
-            let err = ConstEvalErr{ span: span, kind: err };
-            let mut diag = cx.tcx().sess.struct_span_warn(
-                span, "this expression will panic at run-time");
-            note_const_eval_err(cx.tcx(), &err, span, "expression", &mut diag);
-            diag.emit();
-            Err(Runtime(err))
-        },
-    }
-}
-
-fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
-                              te1: ValueRef, te2: ValueRef,
-                              trueconst: TrueConst) -> Result<(), ConstEvalFailure> {
-    let b = if let hir::ExprBinary(b, _, _) = e.node { b } else { bug!() };
-    let (lhs, rhs) = match (to_const_int(te1, t, cx.tcx()), to_const_int(te2, t, cx.tcx())) {
-        (Some(v1), Some(v2)) => (v1, v2),
-        _ => return Ok(()),
-    };
-    let result = match b.node {
-        hir::BiAdd => lhs + rhs,
-        hir::BiSub => lhs - rhs,
-        hir::BiMul => lhs * rhs,
-        hir::BiDiv => lhs / rhs,
-        hir::BiRem => lhs % rhs,
-        hir::BiShl => lhs << rhs,
-        hir::BiShr => lhs >> rhs,
-        _ => return Ok(()),
-    };
-    const_err(cx, e.span, result.map_err(ErrKind::Math), trueconst)?;
-    Ok(())
-}
-
-fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                                   e: &hir::Expr,
-                                   ety: Ty<'tcx>,
-                                   param_substs: &'tcx Substs<'tcx>,
-                                   fn_args: FnArgMap,
-                                   trueconst: TrueConst)
-                                   -> Result<ValueRef, ConstEvalFailure>
-{
-    debug!("const_expr_unadjusted(e={:?}, ety={:?}, param_substs={:?})",
-           e,
-           ety,
-           param_substs);
-
-    let map_list = |exprs: &[P<hir::Expr>]| -> Result<Vec<ValueRef>, ConstEvalFailure> {
-        exprs.iter()
-             .map(|e| const_expr(cx, &e, param_substs, fn_args, trueconst).map(|(l, _)| l))
-             .collect::<Vec<Result<ValueRef, ConstEvalFailure>>>()
-             .into_iter()
-             .collect()
-         // this dance is necessary to eagerly run const_expr so all errors are reported
-    };
-    let _icx = push_ctxt("const_expr");
-    Ok(match e.node {
-        hir::ExprLit(ref lit) => const_lit(cx, e, &lit),
-        hir::ExprBinary(b, ref e1, ref e2) => {
-            /* Neither type is bottom, and we expect them to be unified
-             * already, so the following is safe. */
-            let (te1, ty) = const_expr(cx, &e1, param_substs, fn_args, trueconst)?;
-            debug!("const_expr_unadjusted: te1={:?}, ty={:?}",
-                   Value(te1), ty);
-            assert!(!ty.is_simd());
-            let is_float = ty.is_fp();
-            let signed = ty.is_signed();
-
-            let (te2, ty2) = const_expr(cx, &e2, param_substs, fn_args, trueconst)?;
-            debug!("const_expr_unadjusted: te2={:?}, ty={:?}",
-                   Value(te2), ty2);
-
-            check_binary_expr_validity(cx, e, ty, te1, te2, trueconst)?;
-
-            unsafe { match b.node {
-                hir::BiAdd if is_float => llvm::LLVMConstFAdd(te1, te2),
-                hir::BiAdd             => llvm::LLVMConstAdd(te1, te2),
-
-                hir::BiSub if is_float => llvm::LLVMConstFSub(te1, te2),
-                hir::BiSub             => llvm::LLVMConstSub(te1, te2),
-
-                hir::BiMul if is_float => llvm::LLVMConstFMul(te1, te2),
-                hir::BiMul             => llvm::LLVMConstMul(te1, te2),
-
-                hir::BiDiv if is_float => llvm::LLVMConstFDiv(te1, te2),
-                hir::BiDiv if signed   => llvm::LLVMConstSDiv(te1, te2),
-                hir::BiDiv             => llvm::LLVMConstUDiv(te1, te2),
-
-                hir::BiRem if is_float => llvm::LLVMConstFRem(te1, te2),
-                hir::BiRem if signed   => llvm::LLVMConstSRem(te1, te2),
-                hir::BiRem             => llvm::LLVMConstURem(te1, te2),
-
-                hir::BiAnd    => llvm::LLVMConstAnd(te1, te2),
-                hir::BiOr     => llvm::LLVMConstOr(te1, te2),
-                hir::BiBitXor => llvm::LLVMConstXor(te1, te2),
-                hir::BiBitAnd => llvm::LLVMConstAnd(te1, te2),
-                hir::BiBitOr  => llvm::LLVMConstOr(te1, te2),
-                hir::BiShl    => {
-                    let te2 = base::cast_shift_const_rhs(b.node, te1, te2);
-                    llvm::LLVMConstShl(te1, te2)
-                },
-                hir::BiShr    => {
-                    let te2 = base::cast_shift_const_rhs(b.node, te1, te2);
-                    if signed { llvm::LLVMConstAShr(te1, te2) }
-                    else      { llvm::LLVMConstLShr(te1, te2) }
-                },
-                hir::BiEq | hir::BiNe | hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe => {
-                    if is_float {
-                        let cmp = base::bin_op_to_fcmp_predicate(b.node);
-                        llvm::LLVMConstFCmp(cmp, te1, te2)
-                    } else {
-                        let cmp = base::bin_op_to_icmp_predicate(b.node, signed);
-                        llvm::LLVMConstICmp(cmp, te1, te2)
-                    }
-                },
-            } } // unsafe { match b.node {
-        },
-        hir::ExprUnary(u, ref inner_e) => {
-            let (te, ty) = const_expr(cx, &inner_e, param_substs, fn_args, trueconst)?;
-
-            check_unary_expr_validity(cx, e, ty, te, trueconst)?;
-
-            let is_float = ty.is_fp();
-            unsafe { match u {
-                hir::UnDeref           => const_deref(cx, te, ty).0,
-                hir::UnNot             => llvm::LLVMConstNot(te),
-                hir::UnNeg if is_float => llvm::LLVMConstFNeg(te),
-                hir::UnNeg             => llvm::LLVMConstNeg(te),
-            } }
-        },
-        hir::ExprField(ref base, field) => {
-            let (bv, bt) = const_expr(cx, &base, param_substs, fn_args, trueconst)?;
-            let brepr = adt::represent_type(cx, bt);
-            let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None);
-            let ix = vinfo.field_index(field.node);
-            adt::const_get_field(&brepr, bv, vinfo.discr, ix)
-        },
-        hir::ExprTupField(ref base, idx) => {
-            let (bv, bt) = const_expr(cx, &base, param_substs, fn_args, trueconst)?;
-            let brepr = adt::represent_type(cx, bt);
-            let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None);
-            adt::const_get_field(&brepr, bv, vinfo.discr, idx.node)
-        },
-        hir::ExprIndex(ref base, ref index) => {
-            let (bv, bt) = const_expr(cx, &base, param_substs, fn_args, trueconst)?;
-            let iv = const_expr(cx, &index, param_substs, fn_args, TrueConst::Yes)?.0;
-            let iv = if let Some(iv) = const_to_opt_uint(iv) {
-                iv
-            } else {
-                span_bug!(index.span, "index is not an integer-constant expression");
-            };
-            let (arr, len) = match bt.sty {
-                ty::TyArray(_, u) => (bv, C_uint(cx, u)),
-                ty::TySlice(..) | ty::TyStr => {
-                    let e1 = const_get_elt(bv, &[0]);
-                    (load_const(cx, e1, bt), const_get_elt(bv, &[1]))
-                },
-                ty::TyRef(_, mt) => match mt.ty.sty {
-                    ty::TyArray(_, u) => {
-                        (load_const(cx, bv, mt.ty), C_uint(cx, u))
-                    },
-                    _ => span_bug!(base.span,
-                                   "index-expr base must be a vector \
-                                    or string type, found {:?}",
-                                   bt),
-                },
-                _ => span_bug!(base.span,
-                               "index-expr base must be a vector \
-                                or string type, found {:?}",
-                               bt),
-            };
-
-            let len = unsafe { llvm::LLVMConstIntGetZExtValue(len) as u64 };
-            let len = match bt.sty {
-                ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) => match ty.sty {
-                    ty::TyStr => {
-                        assert!(len > 0);
-                        len - 1
-                    },
-                    _ => len,
-                },
-                _ => len,
-            };
-            if iv >= len {
-                // FIXME #3170: report this earlier on in the const-eval
-                // pass. Reporting here is a bit late.
-                const_err(cx, e.span, Err(ErrKind::IndexOutOfBounds {
-                    len: len,
-                    index: iv
-                }), trueconst)?;
-                C_undef(val_ty(arr).element_type())
-            } else {
-                const_get_elt(arr, &[iv as c_uint])
-            }
-        },
-        hir::ExprCast(ref base, _) => {
-            let t_cast = ety;
-            let llty = type_of::type_of(cx, t_cast);
-            let (v, t_expr) = const_expr(cx, &base, param_substs, fn_args, trueconst)?;
-            debug!("trans_const_cast({:?} as {:?})", t_expr, t_cast);
-            if expr::cast_is_noop(cx.tcx(), base, t_expr, t_cast) {
-                return Ok(v);
-            }
-            if type_is_fat_ptr(cx.tcx(), t_expr) {
-                // Fat pointer casts.
-                let t_cast_inner =
-                    t_cast.builtin_deref(true, ty::NoPreference).expect("cast to non-pointer").ty;
-                let ptr_ty = type_of::in_memory_type_of(cx, t_cast_inner).ptr_to();
-                let addr = ptrcast(const_get_elt(v, &[abi::FAT_PTR_ADDR as u32]),
-                                   ptr_ty);
-                if type_is_fat_ptr(cx.tcx(), t_cast) {
-                    let info = const_get_elt(v, &[abi::FAT_PTR_EXTRA as u32]);
-                    return Ok(C_struct(cx, &[addr, info], false))
-                } else {
-                    return Ok(addr);
-                }
-            }
-            unsafe { match (
-                CastTy::from_ty(t_expr).expect("bad input type for cast"),
-                CastTy::from_ty(t_cast).expect("bad output type for cast"),
-            ) {
-                (CastTy::Int(IntTy::CEnum), CastTy::Int(_)) => {
-                    let repr = adt::represent_type(cx, t_expr);
-                    let discr = adt::const_get_discrim(&repr, v);
-                    let iv = C_integral(cx.int_type(), discr.0, false);
-                    let s = adt::is_discr_signed(&repr) as Bool;
-                    llvm::LLVMConstIntCast(iv, llty.to_ref(), s)
-                },
-                (CastTy::Int(_), CastTy::Int(_)) => {
-                    let s = t_expr.is_signed() as Bool;
-                    llvm::LLVMConstIntCast(v, llty.to_ref(), s)
-                },
-                (CastTy::Int(_), CastTy::Float) => {
-                    if t_expr.is_signed() {
-                        llvm::LLVMConstSIToFP(v, llty.to_ref())
-                    } else {
-                        llvm::LLVMConstUIToFP(v, llty.to_ref())
-                    }
-                },
-                (CastTy::Float, CastTy::Float) => llvm::LLVMConstFPCast(v, llty.to_ref()),
-                (CastTy::Float, CastTy::Int(IntTy::I)) => llvm::LLVMConstFPToSI(v, llty.to_ref()),
-                (CastTy::Float, CastTy::Int(_)) => llvm::LLVMConstFPToUI(v, llty.to_ref()),
-                (CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_))
-                | (CastTy::RPtr(_), CastTy::Ptr(_)) => {
-                    ptrcast(v, llty)
-                },
-                (CastTy::FnPtr, CastTy::FnPtr) => ptrcast(v, llty), // isn't this a coercion?
-                (CastTy::Int(_), CastTy::Ptr(_)) => llvm::LLVMConstIntToPtr(v, llty.to_ref()),
-                (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => {
-                  llvm::LLVMConstPtrToInt(v, llty.to_ref())
-                },
-                _ => {
-                  span_bug!(e.span, "bad combination of types for cast")
-                },
-            } } // unsafe { match ( ... ) {
-        },
-        hir::ExprAddrOf(hir::MutImmutable, ref sub) => {
-            // If this is the address of some static, then we need to return
-            // the actual address of the static itself (short circuit the rest
-            // of const eval).
-            let mut cur = sub;
-            loop {
-                match cur.node {
-                    hir::ExprBlock(ref blk) => {
-                        if let Some(ref sub) = blk.expr {
-                            cur = sub;
-                        } else {
-                            break;
-                        }
-                    },
-                    _ => break,
-                }
-            }
-            if let Some(Def::Static(def_id, _)) = cx.tcx().expect_def_or_none(cur.id) {
-                get_static(cx, def_id).val
-            } else {
-                // If this isn't the address of a static, then keep going through
-                // normal constant evaluation.
-                let (v, ty) = const_expr(cx, &sub, param_substs, fn_args, trueconst)?;
-                addr_of(cx, v, type_of::align_of(cx, ty), "ref")
-            }
-        },
-        hir::ExprAddrOf(hir::MutMutable, ref sub) => {
-            let (v, ty) = const_expr(cx, &sub, param_substs, fn_args, trueconst)?;
-            addr_of_mut(cx, v, type_of::align_of(cx, ty), "ref_mut_slice")
-        },
-        hir::ExprTup(ref es) => {
-            let repr = adt::represent_type(cx, ety);
-            let vals = map_list(&es[..])?;
-            adt::trans_const(cx, &repr, Disr(0), &vals[..])
-        },
-        hir::ExprStruct(_, ref fs, ref base_opt) => {
-            let repr = adt::represent_type(cx, ety);
-
-            let base_val = match *base_opt {
-                Some(ref base) => Some(const_expr(
-                    cx,
-                    &base,
-                    param_substs,
-                    fn_args,
-                    trueconst,
-                )?),
-                None => None
-            };
-
-            let VariantInfo { discr, fields } = VariantInfo::of_node(cx.tcx(), ety, e.id);
-            let cs = fields.iter().enumerate().map(|(ix, &Field(f_name, _))| {
-                match (fs.iter().find(|f| f_name == f.name.node), base_val) {
-                    (Some(ref f), _) => {
-                        const_expr(cx, &f.expr, param_substs, fn_args, trueconst).map(|(l, _)| l)
-                    },
-                    (_, Some((bv, _))) => Ok(adt::const_get_field(&repr, bv, discr, ix)),
-                    (_, None) => span_bug!(e.span, "missing struct field"),
-                }
-            })
-            .collect::<Vec<Result<_, ConstEvalFailure>>>()
-            .into_iter()
-            .collect::<Result<Vec<_>,ConstEvalFailure>>();
-            let cs = cs?;
-            if ety.is_simd() {
-                C_vector(&cs[..])
-            } else {
-                adt::trans_const(cx, &repr, discr, &cs[..])
-            }
-        },
-        hir::ExprVec(ref es) => {
-            let unit_ty = ety.sequence_element_type(cx.tcx());
-            let llunitty = type_of::type_of(cx, unit_ty);
-            let vs = es.iter()
-                       .map(|e| const_expr(
-                           cx,
-                           &e,
-                           param_substs,
-                           fn_args,
-                           trueconst,
-                       ).map(|(l, _)| l))
-                       .collect::<Vec<Result<_, ConstEvalFailure>>>()
-                       .into_iter()
-                       .collect::<Result<Vec<_>, ConstEvalFailure>>();
-            let vs = vs?;
-            // If the vector contains enums, an LLVM array won't work.
-            if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
-                C_struct(cx, &vs[..], false)
-            } else {
-                C_array(llunitty, &vs[..])
-            }
-        },
-        hir::ExprRepeat(ref elem, ref count) => {
-            let unit_ty = ety.sequence_element_type(cx.tcx());
-            let llunitty = type_of::type_of(cx, unit_ty);
-            let n = eval_length(cx.tcx(), count, "repeat count").unwrap();
-            let unit_val = const_expr(cx, &elem, param_substs, fn_args, trueconst)?.0;
-            let vs = vec![unit_val; n];
-            if val_ty(unit_val) != llunitty {
-                C_struct(cx, &vs[..], false)
-            } else {
-                C_array(llunitty, &vs[..])
-            }
-        },
-        hir::ExprPath(..) => {
-            match cx.tcx().expect_def(e.id) {
-                Def::Local(_, id) => {
-                    if let Some(val) = fn_args.and_then(|args| args.get(&id).cloned()) {
-                        val
-                    } else {
-                        span_bug!(e.span, "const fn argument not found")
-                    }
-                }
-                Def::Fn(..) | Def::Method(..) => C_nil(cx),
-                Def::Const(def_id) | Def::AssociatedConst(def_id) => {
-                    load_const(cx, get_const_val(cx, def_id, e, param_substs)?,
-                               ety)
-                }
-                Def::Variant(enum_did, variant_did) => {
-                    let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did);
-                    match vinfo.kind {
-                        ty::VariantKind::Unit => {
-                            let repr = adt::represent_type(cx, ety);
-                            adt::trans_const(cx, &repr, Disr::from(vinfo.disr_val), &[])
-                        }
-                        ty::VariantKind::Tuple => C_nil(cx),
-                        ty::VariantKind::Struct => {
-                            span_bug!(e.span, "path-expr refers to a dict variant!")
-                        }
-                    }
-                }
-                // Unit struct or ctor.
-                Def::Struct(..) => C_null(type_of::type_of(cx, ety)),
-                _ => {
-                    span_bug!(e.span, "expected a const, fn, struct, \
-                                       or variant def")
-                }
-            }
-        },
-        hir::ExprCall(ref callee, ref args) => {
-            let mut callee = &**callee;
-            loop {
-                callee = match callee.node {
-                    hir::ExprBlock(ref block) => match block.expr {
-                        Some(ref tail) => &tail,
-                        None => break,
-                    },
-                    _ => break,
-                };
-            }
-            let arg_vals = map_list(args)?;
-            match cx.tcx().expect_def(callee.id) {
-                Def::Fn(did) | Def::Method(did) => {
-                    const_fn_call(
-                        cx,
-                        did,
-                        cx.tcx().node_id_item_substs(callee.id).substs,
-                        &arg_vals,
-                        param_substs,
-                        trueconst,
-                    )?
-                }
-                Def::Struct(..) => {
-                    if ety.is_simd() {
-                        C_vector(&arg_vals[..])
-                    } else {
-                        let repr = adt::represent_type(cx, ety);
-                        adt::trans_const(cx, &repr, Disr(0), &arg_vals[..])
-                    }
-                }
-                Def::Variant(enum_did, variant_did) => {
-                    let repr = adt::represent_type(cx, ety);
-                    let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did);
-                    adt::trans_const(cx,
-                                     &repr,
-                                     Disr::from(vinfo.disr_val),
-                                     &arg_vals[..])
-                }
-                _ => span_bug!(e.span, "expected a struct, variant, or const fn def"),
-            }
-        },
-        hir::ExprMethodCall(_, _, ref args) => {
-            let arg_vals = map_list(args)?;
-            let method_call = ty::MethodCall::expr(e.id);
-            let method = cx.tcx().tables.borrow().method_map[&method_call];
-            const_fn_call(cx, method.def_id, method.substs,
-                          &arg_vals, param_substs, trueconst)?
-        },
-        hir::ExprType(ref e, _) => const_expr(cx, &e, param_substs, fn_args, trueconst)?.0,
-        hir::ExprBlock(ref block) => {
-            match block.expr {
-                Some(ref expr) => const_expr(
-                    cx,
-                    &expr,
-                    param_substs,
-                    fn_args,
-                    trueconst,
-                )?.0,
-                None => C_nil(cx),
-            }
-        },
-        hir::ExprClosure(_, ref decl, ref body, _) => {
-            match ety.sty {
-                ty::TyClosure(def_id, substs) => {
-                    closure::trans_closure_expr(closure::Dest::Ignore(cx),
-                                                decl,
-                                                body,
-                                                e.id,
-                                                def_id,
-                                                substs);
-                }
-                _ =>
-                    span_bug!(
-                        e.span,
-                        "bad type for closure expr: {:?}", ety)
-            }
-            C_null(type_of::type_of(cx, ety))
-        },
-        _ => span_bug!(e.span,
-                       "bad constant expression type in consts::const_expr"),
-    })
-}
-
-pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId)
-                            -> Datum<'tcx, Lvalue> {
-    let ty = ccx.tcx().lookup_item_type(def_id).ty;
-
+pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
     let instance = Instance::mono(ccx.shared(), def_id);
     if let Some(&g) = ccx.instances().borrow().get(&instance) {
-        return Datum::new(g, ty, Lvalue::new("static"));
+        return g;
     }
 
+    let ty = ccx.tcx().lookup_item_type(def_id).ty;
     let g = if let Some(id) = ccx.tcx().map.as_local_node_id(def_id) {
 
         let llty = type_of::type_of(ccx, ty);
@@ -1032,14 +105,10 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId)
                 let defined_in_current_codegen_unit = ccx.codegen_unit()
                                                          .items()
                                                          .contains_key(&TransItem::Static(id));
-                if defined_in_current_codegen_unit {
-                    if declare::get_declared_value(ccx, sym).is_none() {
-                        span_bug!(span, "trans: Static not properly pre-defined?");
-                    }
-                } else {
-                    if declare::get_declared_value(ccx, sym).is_some() {
-                        span_bug!(span, "trans: Conflicting symbol names for static?");
-                    }
+                assert!(!defined_in_current_codegen_unit);
+
+                if declare::get_declared_value(ccx, sym).is_some() {
+                    span_bug!(span, "trans: Conflicting symbol names for static?");
                 }
 
                 let g = declare::define_global(ccx, sym, llty).unwrap();
@@ -1136,34 +205,20 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId)
 
     ccx.instances().borrow_mut().insert(instance, g);
     ccx.statics().borrow_mut().insert(g, def_id);
-    Datum::new(g, ty, Lvalue::new("static"))
+    g
 }
 
 pub fn trans_static(ccx: &CrateContext,
                     m: hir::Mutability,
-                    expr: &hir::Expr,
                     id: ast::NodeId,
                     attrs: &[ast::Attribute])
                     -> Result<ValueRef, ConstEvalErr> {
     unsafe {
         let _icx = push_ctxt("trans_static");
         let def_id = ccx.tcx().map.local_def_id(id);
-        let datum = get_static(ccx, def_id);
+        let g = get_static(ccx, def_id);
 
-        let check_attrs = |attrs: &[ast::Attribute]| {
-            let default_to_mir = ccx.sess().opts.debugging_opts.orbit;
-            let invert = if default_to_mir { "rustc_no_mir" } else { "rustc_mir" };
-            default_to_mir ^ attrs.iter().any(|item| item.check_name(invert))
-        };
-        let use_mir = check_attrs(ccx.tcx().map.attrs(id));
-
-        let v = if use_mir {
-            ::mir::trans_static_initializer(ccx, def_id)
-        } else {
-            let empty_substs = Substs::empty(ccx.tcx());
-            const_expr(ccx, expr, empty_substs, None, TrueConst::Yes)
-                .map(|(v, _)| v)
-        }.map_err(|e| e.into_inner())?;
+        let v = ::mir::trans_static_initializer(ccx, def_id)?;
 
         // boolean SSA values are i1, but they have to be stored in i8 slots,
         // otherwise some LLVM optimization passes don't work as expected
@@ -1175,31 +230,32 @@ pub fn trans_static(ccx: &CrateContext,
             v
         };
 
-        let llty = type_of::type_of(ccx, datum.ty);
+        let ty = ccx.tcx().lookup_item_type(def_id).ty;
+        let llty = type_of::type_of(ccx, ty);
         let g = if val_llty == llty {
-            datum.val
+            g
         } else {
             // If we created the global with the wrong type,
             // correct the type.
             let empty_string = CString::new("").unwrap();
-            let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(datum.val));
+            let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(g));
             let name_string = CString::new(name_str_ref.to_bytes()).unwrap();
-            llvm::LLVMSetValueName(datum.val, empty_string.as_ptr());
+            llvm::LLVMSetValueName(g, empty_string.as_ptr());
             let new_g = llvm::LLVMRustGetOrInsertGlobal(
                 ccx.llmod(), name_string.as_ptr(), val_llty.to_ref());
             // To avoid breaking any invariants, we leave around the old
             // global for the moment; we'll replace all references to it
             // with the new global later. (See base::trans_crate.)
-            ccx.statics_to_rauw().borrow_mut().push((datum.val, new_g));
+            ccx.statics_to_rauw().borrow_mut().push((g, new_g));
             new_g
         };
-        llvm::LLVMSetAlignment(g, type_of::align_of(ccx, datum.ty));
+        llvm::LLVMSetAlignment(g, type_of::align_of(ccx, ty));
         llvm::LLVMSetInitializer(g, v);
 
         // As an optimization, all shared statics which do not have interior
         // mutability are placed into read-only memory.
         if m != hir::MutMutable {
-            let tcontents = datum.ty.type_contents(ccx.tcx());
+            let tcontents = ty.type_contents(ccx.tcx());
             if !tcontents.interior_unsafe() {
                 llvm::LLVMSetGlobalConstant(g, llvm::True);
             }
index c31dbf8943e08972e2daee47d320e78d97c74a70..2422b9f30069b16a38bbc0fa1817bf4c0b86ce85 100644 (file)
@@ -53,9 +53,7 @@ pub struct Stats {
     pub n_glues_created: Cell<usize>,
     pub n_null_glues: Cell<usize>,
     pub n_real_glues: Cell<usize>,
-    pub n_fallback_instantiations: Cell<usize>,
     pub n_fns: Cell<usize>,
-    pub n_monos: Cell<usize>,
     pub n_inlines: Cell<usize>,
     pub n_closures: Cell<usize>,
     pub n_llvm_insns: Cell<usize>,
@@ -79,7 +77,6 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     stats: Stats,
     check_overflow: bool,
-    check_drop_flag_for_sanity: bool,
     mir_map: &'a MirMap<'tcx>,
     mir_cache: RefCell<DepTrackingMap<MirCache<'tcx>>>,
 
@@ -87,6 +84,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
 
     translation_items: RefCell<FnvHashSet<TransItem<'tcx>>>,
     trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
+    project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>,
 }
 
 /// The local portion of a `CrateContext`.  There is one `LocalCrateContext`
@@ -104,7 +102,6 @@ pub struct LocalCrateContext<'tcx> {
     drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, (ValueRef, FnType)>>,
     /// Cache instances of monomorphic and polymorphic items
     instances: RefCell<FnvHashMap<Instance<'tcx>, ValueRef>>,
-    monomorphizing: RefCell<DefIdMap<usize>>,
     /// Cache generated vtables
     vtables: RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>, ValueRef>>,
     /// Cache of constant strings,
@@ -199,6 +196,46 @@ fn to_dep_node(key: &DefId) -> DepNode<DefId> {
     }
 }
 
+// # Global Cache
+
+pub struct ProjectionCache<'gcx> {
+    data: PhantomData<&'gcx ()>
+}
+
+impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> {
+    type Key = Ty<'gcx>;
+    type Value = Ty<'gcx>;
+    fn to_dep_node(key: &Self::Key) -> DepNode<DefId> {
+        // Ideally, we'd just put `key` into the dep-node, but we
+        // can't put full types in there. So just collect up all the
+        // def-ids of structs/enums as well as any traits that we
+        // project out of. It doesn't matter so much what we do here,
+        // except that if we are too coarse, we'll create overly
+        // coarse edges between impls and the trans. For example, if
+        // we just used the def-id of things we are projecting out of,
+        // then the key for `<Foo as SomeTrait>::T` and `<Bar as
+        // SomeTrait>::T` would both share a dep-node
+        // (`TraitSelect(SomeTrait)`), and hence the impls for both
+        // `Foo` and `Bar` would be considered inputs. So a change to
+        // `Bar` would affect things that just normalized `Foo`.
+        // Anyway, this heuristic is not ideal, but better than
+        // nothing.
+        let def_ids: Vec<DefId> =
+            key.walk()
+               .filter_map(|t| match t.sty {
+                   ty::TyStruct(adt_def, _) |
+                   ty::TyEnum(adt_def, _) =>
+                       Some(adt_def.did),
+                   ty::TyProjection(ref proj) =>
+                       Some(proj.trait_ref.def_id),
+                   _ =>
+                       None
+               })
+               .collect();
+        DepNode::TraitSelect(def_ids)
+    }
+}
+
 /// This list owns a number of LocalCrateContexts and binds them to their common
 /// SharedCrateContext. This type just exists as a convenience, something to
 /// pass around all LocalCrateContexts with and get an iterator over them.
@@ -424,8 +461,7 @@ pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>,
                symbol_hasher: Sha256,
                link_meta: LinkMeta,
                reachable: NodeSet,
-               check_overflow: bool,
-               check_drop_flag_for_sanity: bool)
+               check_overflow: bool)
                -> SharedCrateContext<'b, 'tcx> {
         let (metadata_llcx, metadata_llmod) = unsafe {
             create_context_and_module(&tcx.sess, "metadata")
@@ -490,9 +526,7 @@ pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>,
                 n_glues_created: Cell::new(0),
                 n_null_glues: Cell::new(0),
                 n_real_glues: Cell::new(0),
-                n_fallback_instantiations: Cell::new(0),
                 n_fns: Cell::new(0),
-                n_monos: Cell::new(0),
                 n_inlines: Cell::new(0),
                 n_closures: Cell::new(0),
                 n_llvm_insns: Cell::new(0),
@@ -500,10 +534,10 @@ pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>,
                 fn_stats: RefCell::new(Vec::new()),
             },
             check_overflow: check_overflow,
-            check_drop_flag_for_sanity: check_drop_flag_for_sanity,
             use_dll_storage_attrs: use_dll_storage_attrs,
             translation_items: RefCell::new(FnvHashSet()),
             trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
+            project_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
         }
     }
 
@@ -527,6 +561,10 @@ pub fn trait_cache(&self) -> &RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>
         &self.trait_cache
     }
 
+    pub fn project_cache(&self) -> &RefCell<DepTrackingMap<ProjectionCache<'tcx>>> {
+        &self.project_cache
+    }
+
     pub fn link_meta<'a>(&'a self) -> &'a LinkMeta {
         &self.link_meta
     }
@@ -571,7 +609,9 @@ pub fn translation_items(&self) -> &RefCell<FnvHashSet<TransItem<'tcx>>> {
     /// Given the def-id of some item that has no type parameters, make
     /// a suitable "empty substs" for it.
     pub fn empty_substs_for_def_id(&self, item_def_id: DefId) -> &'tcx Substs<'tcx> {
-        Substs::for_item(self.tcx(), item_def_id, |_, _| ty::ReErased, |_, _| {
+        Substs::for_item(self.tcx(), item_def_id,
+                         |_, _| self.tcx().mk_region(ty::ReErased),
+                         |_, _| {
             bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
         })
     }
@@ -629,7 +669,6 @@ fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
                 fn_pointer_shims: RefCell::new(FnvHashMap()),
                 drop_glues: RefCell::new(FnvHashMap()),
                 instances: RefCell::new(FnvHashMap()),
-                monomorphizing: RefCell::new(DefIdMap()),
                 vtables: RefCell::new(FnvHashMap()),
                 const_cstr_cache: RefCell::new(FnvHashMap()),
                 const_unsized: RefCell::new(FnvHashMap()),
@@ -833,10 +872,6 @@ pub fn instances<'a>(&'a self) -> &'a RefCell<FnvHashMap<Instance<'tcx>, ValueRe
         &self.local().instances
     }
 
-    pub fn monomorphizing<'a>(&'a self) -> &'a RefCell<DefIdMap<usize>> {
-        &self.local().monomorphizing
-    }
-
     pub fn vtables<'a>(&'a self) -> &'a RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>, ValueRef>> {
         &self.local().vtables
     }
@@ -960,15 +995,16 @@ pub fn enter_type_of(&self, ty: Ty<'tcx>) -> TypeOfDepthLock<'b, 'tcx> {
         TypeOfDepthLock(self.local())
     }
 
-    pub fn check_overflow(&self) -> bool {
-        self.shared.check_overflow
+    pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout {
+        self.tcx().infer_ctxt(None, None, traits::Reveal::All).enter(|infcx| {
+            ty.layout(&infcx).unwrap_or_else(|e| {
+                bug!("failed to get layout for `{}`: {}", ty, e);
+            })
+        })
     }
 
-    pub fn check_drop_flag_for_sanity(&self) -> bool {
-        // This controls whether we emit a conditional llvm.debugtrap
-        // guarded on whether the dropflag is one of its (two) valid
-        // values.
-        self.shared.check_drop_flag_for_sanity
+    pub fn check_overflow(&self) -> bool {
+        self.shared.check_overflow
     }
 
     pub fn use_dll_storage_attrs(&self) -> bool {
diff --git a/src/librustc_trans/controlflow.rs b/src/librustc_trans/controlflow.rs
deleted file mode 100644 (file)
index 8b3a8a2..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use llvm::ValueRef;
-use rustc::hir::def::Def;
-use middle::lang_items::{PanicFnLangItem, PanicBoundsCheckFnLangItem};
-use rustc::ty::subst::Substs;
-use base::*;
-use basic_block::BasicBlock;
-use build::*;
-use callee::{Callee, ArgVals};
-use cleanup::CleanupMethods;
-use cleanup;
-use common::*;
-use consts;
-use debuginfo;
-use debuginfo::{DebugLoc, ToDebugLoc};
-use expr;
-use machine;
-
-use rustc::hir;
-
-use syntax::ast;
-use syntax::parse::token::InternedString;
-use syntax::parse::token;
-
-pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
-                              s: &hir::Stmt)
-                              -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_stmt");
-    let fcx = cx.fcx;
-    debug!("trans_stmt({:?})", s);
-
-    if cx.unreachable.get() {
-        return cx;
-    }
-
-    if cx.sess().asm_comments() {
-        add_span_comment(cx, s.span, &format!("{:?}", s));
-    }
-
-    let mut bcx = cx;
-
-    let id = s.node.id();
-    let cleanup_debug_loc =
-        debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(), id, s.span, false);
-    fcx.push_ast_cleanup_scope(cleanup_debug_loc);
-
-    match s.node {
-        hir::StmtExpr(ref e, _) | hir::StmtSemi(ref e, _) => {
-            bcx = trans_stmt_semi(bcx, &e);
-        }
-        hir::StmtDecl(ref d, _) => {
-            match d.node {
-                hir::DeclLocal(ref local) => {
-                    bcx = init_local(bcx, &local);
-                    debuginfo::create_local_var_metadata(bcx, &local);
-                }
-                // Inner items are visited by `trans_item`/`trans_meth`.
-                hir::DeclItem(_) => {},
-            }
-        }
-    }
-
-    bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, s.node.id());
-
-    return bcx;
-}
-
-pub fn trans_stmt_semi<'blk, 'tcx>(cx: Block<'blk, 'tcx>, e: &hir::Expr)
-                                   -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_stmt_semi");
-
-    if cx.unreachable.get() {
-        return cx;
-    }
-
-    let ty = expr_ty(cx, e);
-    if cx.fcx.type_needs_drop(ty) {
-        expr::trans_to_lvalue(cx, e, "stmt").bcx
-    } else {
-        expr::trans_into(cx, e, expr::Ignore)
-    }
-}
-
-pub fn trans_block<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                               b: &hir::Block,
-                               mut dest: expr::Dest)
-                               -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_block");
-
-    if bcx.unreachable.get() {
-        return bcx;
-    }
-
-    let fcx = bcx.fcx;
-    let mut bcx = bcx;
-
-    let cleanup_debug_loc =
-        debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(), b.id, b.span, true);
-    fcx.push_ast_cleanup_scope(cleanup_debug_loc);
-
-    for s in &b.stmts {
-        bcx = trans_stmt(bcx, s);
-    }
-
-    if dest != expr::Ignore {
-        let block_ty = node_id_type(bcx, b.id);
-
-        if b.expr.is_none() || type_is_zero_size(bcx.ccx(), block_ty) {
-            dest = expr::Ignore;
-        } else if b.expr.is_some() {
-            // If the block has an expression, but that expression isn't reachable,
-            // don't save into the destination given, ignore it.
-            if let Some(ref cfg) = bcx.fcx.cfg {
-                if !cfg.node_is_reachable(b.expr.as_ref().unwrap().id) {
-                    dest = expr::Ignore;
-                }
-            }
-        }
-    }
-
-    match b.expr {
-        Some(ref e) => {
-            if !bcx.unreachable.get() {
-                bcx = expr::trans_into(bcx, &e, dest);
-            }
-        }
-        None => {
-            assert!(dest == expr::Ignore || bcx.unreachable.get());
-        }
-    }
-
-    bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, b.id);
-
-    return bcx;
-}
-
-pub fn trans_if<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                            if_id: ast::NodeId,
-                            cond: &hir::Expr,
-                            thn: &hir::Block,
-                            els: Option<&hir::Expr>,
-                            dest: expr::Dest)
-                            -> Block<'blk, 'tcx> {
-    debug!("trans_if(bcx={}, if_id={}, cond={:?}, thn={}, dest={:?})",
-           bcx.to_str(), if_id, cond, thn.id, dest);
-    let _icx = push_ctxt("trans_if");
-
-    if bcx.unreachable.get() {
-        return bcx;
-    }
-
-    let mut bcx = bcx;
-
-    let cond_val = unpack_result!(bcx, expr::trans(bcx, cond).to_llbool());
-
-    // Drop branches that are known to be impossible
-    if let Some(cv) = const_to_opt_uint(cond_val) {
-        if cv == 1 {
-            // if true { .. } [else { .. }]
-            bcx = trans_block(bcx, &thn, dest);
-            DebugLoc::None.apply(bcx.fcx);
-        } else {
-            if let Some(elexpr) = els {
-                bcx = expr::trans_into(bcx, &elexpr, dest);
-                DebugLoc::None.apply(bcx.fcx);
-            }
-        }
-
-        return bcx;
-    }
-
-    let name = format!("then-block-{}-", thn.id);
-    let then_bcx_in = bcx.fcx.new_id_block(&name[..], thn.id);
-    let then_bcx_out = trans_block(then_bcx_in, &thn, dest);
-    DebugLoc::None.apply(bcx.fcx);
-
-    let cond_source_loc = cond.debug_loc();
-
-    let next_bcx;
-    match els {
-        Some(elexpr) => {
-            let else_bcx_in = bcx.fcx.new_id_block("else-block", elexpr.id);
-            let else_bcx_out = expr::trans_into(else_bcx_in, &elexpr, dest);
-            next_bcx = bcx.fcx.join_blocks(if_id,
-                                           &[then_bcx_out, else_bcx_out]);
-            CondBr(bcx, cond_val, then_bcx_in.llbb, else_bcx_in.llbb, cond_source_loc);
-        }
-
-        None => {
-            next_bcx = bcx.fcx.new_id_block("next-block", if_id);
-            Br(then_bcx_out, next_bcx.llbb, DebugLoc::None);
-            CondBr(bcx, cond_val, then_bcx_in.llbb, next_bcx.llbb, cond_source_loc);
-        }
-    }
-
-    // Clear the source location because it is still set to whatever has been translated
-    // right before.
-    DebugLoc::None.apply(next_bcx.fcx);
-
-    next_bcx
-}
-
-pub fn trans_while<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                               loop_expr: &hir::Expr,
-                               cond: &hir::Expr,
-                               body: &hir::Block)
-                               -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_while");
-
-    if bcx.unreachable.get() {
-        return bcx;
-    }
-
-    let fcx = bcx.fcx;
-
-    //            bcx
-    //             |
-    //         cond_bcx_in  <--------+
-    //             |                 |
-    //         cond_bcx_out          |
-    //           |      |            |
-    //           |    body_bcx_in    |
-    // cleanup_blk      |            |
-    //    |           body_bcx_out --+
-    // next_bcx_in
-
-    let next_bcx_in = fcx.new_id_block("while_exit", loop_expr.id);
-    let cond_bcx_in = fcx.new_id_block("while_cond", cond.id);
-    let body_bcx_in = fcx.new_id_block("while_body", body.id);
-
-    fcx.push_loop_cleanup_scope(loop_expr.id, [next_bcx_in, cond_bcx_in]);
-
-    Br(bcx, cond_bcx_in.llbb, loop_expr.debug_loc());
-
-    // compile the block where we will handle loop cleanups
-    let cleanup_llbb = fcx.normal_exit_block(loop_expr.id, cleanup::EXIT_BREAK);
-
-    // compile the condition
-    let Result {bcx: cond_bcx_out, val: cond_val} =
-        expr::trans(cond_bcx_in, cond).to_llbool();
-
-    CondBr(cond_bcx_out, cond_val, body_bcx_in.llbb, cleanup_llbb, cond.debug_loc());
-
-    // loop body:
-    let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore);
-    Br(body_bcx_out, cond_bcx_in.llbb, DebugLoc::None);
-
-    fcx.pop_loop_cleanup_scope(loop_expr.id);
-    return next_bcx_in;
-}
-
-pub fn trans_loop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                              loop_expr: &hir::Expr,
-                              body: &hir::Block)
-                              -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_loop");
-
-    if bcx.unreachable.get() {
-        return bcx;
-    }
-
-    let fcx = bcx.fcx;
-
-    //            bcx
-    //             |
-    //         body_bcx_in
-    //             |
-    //         body_bcx_out
-    //
-    // next_bcx
-    //
-    // Links between body_bcx_in and next_bcx are created by
-    // break statements.
-
-    let next_bcx_in = bcx.fcx.new_id_block("loop_exit", loop_expr.id);
-    let body_bcx_in = bcx.fcx.new_id_block("loop_body", body.id);
-
-    fcx.push_loop_cleanup_scope(loop_expr.id, [next_bcx_in, body_bcx_in]);
-
-    Br(bcx, body_bcx_in.llbb, loop_expr.debug_loc());
-    let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore);
-    Br(body_bcx_out, body_bcx_in.llbb, DebugLoc::None);
-
-    fcx.pop_loop_cleanup_scope(loop_expr.id);
-
-    // If there are no predecessors for the next block, we just translated an endless loop and the
-    // next block is unreachable
-    if BasicBlock(next_bcx_in.llbb).pred_iter().next().is_none() {
-        Unreachable(next_bcx_in);
-    }
-
-    return next_bcx_in;
-}
-
-pub fn trans_break_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                    expr: &hir::Expr,
-                                    opt_label: Option<ast::Name>,
-                                    exit: usize)
-                                    -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_break_cont");
-
-    if bcx.unreachable.get() {
-        return bcx;
-    }
-
-    let fcx = bcx.fcx;
-
-    // Locate loop that we will break to
-    let loop_id = match opt_label {
-        None => fcx.top_loop_scope(),
-        Some(_) => {
-            match bcx.tcx().expect_def(expr.id) {
-                Def::Label(loop_id) => loop_id,
-                r => {
-                    bug!("{:?} in def-map for label", r)
-                }
-            }
-        }
-    };
-
-    // Generate appropriate cleanup code and branch
-    let cleanup_llbb = fcx.normal_exit_block(loop_id, exit);
-    Br(bcx, cleanup_llbb, expr.debug_loc());
-    Unreachable(bcx); // anything afterwards should be ignored
-    return bcx;
-}
-
-pub fn trans_break<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                               expr: &hir::Expr,
-                               label_opt: Option<ast::Name>)
-                               -> Block<'blk, 'tcx> {
-    return trans_break_cont(bcx, expr, label_opt, cleanup::EXIT_BREAK);
-}
-
-pub fn trans_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                              expr: &hir::Expr,
-                              label_opt: Option<ast::Name>)
-                              -> Block<'blk, 'tcx> {
-    return trans_break_cont(bcx, expr, label_opt, cleanup::EXIT_LOOP);
-}
-
-pub fn trans_ret<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                             return_expr: &hir::Expr,
-                             retval_expr: Option<&hir::Expr>)
-                             -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_ret");
-
-    if bcx.unreachable.get() {
-        return bcx;
-    }
-
-    let fcx = bcx.fcx;
-    let mut bcx = bcx;
-    if let Some(x) = retval_expr {
-        let dest = if fcx.llretslotptr.get().is_some() {
-            expr::SaveIn(fcx.get_ret_slot(bcx, "ret_slot"))
-        } else {
-            expr::Ignore
-        };
-        bcx = expr::trans_into(bcx, &x, dest);
-        match dest {
-            expr::SaveIn(slot) if fcx.needs_ret_allocas => {
-                Store(bcx, slot, fcx.llretslotptr.get().unwrap());
-            }
-            _ => {}
-        }
-    }
-    let cleanup_llbb = fcx.return_exit_block();
-    Br(bcx, cleanup_llbb, return_expr.debug_loc());
-    Unreachable(bcx);
-    return bcx;
-}
-
-pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                              call_info: NodeIdAndSpan,
-                              fail_str: InternedString)
-                              -> Block<'blk, 'tcx> {
-    let ccx = bcx.ccx();
-    let _icx = push_ctxt("trans_fail_value");
-
-    if bcx.unreachable.get() {
-        return bcx;
-    }
-
-    let v_str = C_str_slice(ccx, fail_str);
-    let loc = bcx.sess().codemap().lookup_char_pos(call_info.span.lo);
-    let filename = token::intern_and_get_ident(&loc.file.name);
-    let filename = C_str_slice(ccx, filename);
-    let line = C_u32(ccx, loc.line as u32);
-    let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false);
-    let align = machine::llalign_of_min(ccx, val_ty(expr_file_line_const));
-    let expr_file_line = consts::addr_of(ccx, expr_file_line_const, align, "panic_loc");
-    let args = vec!(expr_file_line);
-    let did = langcall(bcx.tcx(), Some(call_info.span), "", PanicFnLangItem);
-    Callee::def(ccx, did, Substs::empty(ccx.tcx()))
-        .call(bcx, call_info.debug_loc(), ArgVals(&args), None).bcx
-}
-
-pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                           call_info: NodeIdAndSpan,
-                                           index: ValueRef,
-                                           len: ValueRef)
-                                           -> Block<'blk, 'tcx> {
-    let ccx = bcx.ccx();
-    let _icx = push_ctxt("trans_fail_bounds_check");
-
-    if bcx.unreachable.get() {
-        return bcx;
-    }
-
-    // Extract the file/line from the span
-    let loc = bcx.sess().codemap().lookup_char_pos(call_info.span.lo);
-    let filename = token::intern_and_get_ident(&loc.file.name);
-
-    // Invoke the lang item
-    let filename = C_str_slice(ccx,  filename);
-    let line = C_u32(ccx, loc.line as u32);
-    let file_line_const = C_struct(ccx, &[filename, line], false);
-    let align = machine::llalign_of_min(ccx, val_ty(file_line_const));
-    let file_line = consts::addr_of(ccx, file_line_const, align, "panic_bounds_check_loc");
-    let args = vec!(file_line, index, len);
-    let did = langcall(bcx.tcx(), Some(call_info.span), "", PanicBoundsCheckFnLangItem);
-    Callee::def(ccx, did, Substs::empty(ccx.tcx()))
-        .call(bcx, call_info.debug_loc(), ArgVals(&args), None).bcx
-}
diff --git a/src/librustc_trans/datum.rs b/src/librustc_trans/datum.rs
deleted file mode 100644 (file)
index 875f88e..0000000
+++ /dev/null
@@ -1,828 +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.
-
-//! ## The Datum module
-//!
-//! A `Datum` encapsulates the result of evaluating a Rust expression.  It
-//! contains a `ValueRef` indicating the result, a `Ty` describing
-//! the Rust type, but also a *kind*. The kind indicates whether the datum
-//! has cleanup scheduled (lvalue) or not (rvalue) and -- in the case of
-//! rvalues -- whether or not the value is "by ref" or "by value".
-//!
-//! The datum API is designed to try and help you avoid memory errors like
-//! forgetting to arrange cleanup or duplicating a value. The type of the
-//! datum incorporates the kind, and thus reflects whether it has cleanup
-//! scheduled:
-//!
-//! - `Datum<Lvalue>` -- by ref, cleanup scheduled
-//! - `Datum<Rvalue>` -- by value or by ref, no cleanup scheduled
-//! - `Datum<Expr>` -- either `Datum<Lvalue>` or `Datum<Rvalue>`
-//!
-//! Rvalue and expr datums are noncopyable, and most of the methods on
-//! datums consume the datum itself (with some notable exceptions). This
-//! reflects the fact that datums may represent affine values which ought
-//! to be consumed exactly once, and if you were to try to (for example)
-//! store an affine value multiple times, you would be duplicating it,
-//! which would certainly be a bug.
-//!
-//! Some of the datum methods, however, are designed to work only on
-//! copyable values such as ints or pointers. Those methods may borrow the
-//! datum (`&self`) rather than consume it, but they always include
-//! assertions on the type of the value represented to check that this
-//! makes sense. An example is `shallow_copy()`, which duplicates
-//! a datum value.
-//!
-//! Translating an expression always yields a `Datum<Expr>` result, but
-//! the methods `to_[lr]value_datum()` can be used to coerce a
-//! `Datum<Expr>` into a `Datum<Lvalue>` or `Datum<Rvalue>` as
-//! needed. Coercing to an lvalue is fairly common, and generally occurs
-//! whenever it is necessary to inspect a value and pull out its
-//! subcomponents (for example, a match, or indexing expression). Coercing
-//! to an rvalue is more unusual; it occurs when moving values from place
-//! to place, such as in an assignment expression or parameter passing.
-//!
-//! ### Lvalues in detail
-//!
-//! An lvalue datum is one for which cleanup has been scheduled. Lvalue
-//! datums are always located in memory, and thus the `ValueRef` for an
-//! LLVM value is always a pointer to the actual Rust value. This means
-//! that if the Datum has a Rust type of `int`, then the LLVM type of the
-//! `ValueRef` will be `int*` (pointer to int).
-//!
-//! Because lvalues already have cleanups scheduled, the memory must be
-//! zeroed to prevent the cleanup from taking place (presuming that the
-//! Rust type needs drop in the first place, otherwise it doesn't
-//! matter). The Datum code automatically performs this zeroing when the
-//! value is stored to a new location, for example.
-//!
-//! Lvalues usually result from evaluating lvalue expressions. For
-//! example, evaluating a local variable `x` yields an lvalue, as does a
-//! reference to a field like `x.f` or an index `x[i]`.
-//!
-//! Lvalue datums can also arise by *converting* an rvalue into an lvalue.
-//! This is done with the `to_lvalue_datum` method defined on
-//! `Datum<Expr>`. Basically this method just schedules cleanup if the
-//! datum is an rvalue, possibly storing the value into a stack slot first
-//! if needed. Converting rvalues into lvalues occurs in constructs like
-//! `&foo()` or `match foo() { ref x => ... }`, where the user is
-//! implicitly requesting a temporary.
-//!
-//! ### Rvalues in detail
-//!
-//! Rvalues datums are values with no cleanup scheduled. One must be
-//! careful with rvalue datums to ensure that cleanup is properly
-//! arranged, usually by converting to an lvalue datum or by invoking the
-//! `add_clean` method.
-//!
-//! ### Scratch datums
-//!
-//! Sometimes you need some temporary scratch space.  The functions
-//! `[lr]value_scratch_datum()` can be used to get temporary stack
-//! space. As their name suggests, they yield lvalues and rvalues
-//! respectively. That is, the slot from `lvalue_scratch_datum` will have
-//! cleanup arranged, and the slot from `rvalue_scratch_datum` does not.
-
-pub use self::Expr::*;
-pub use self::RvalueMode::*;
-
-use llvm::ValueRef;
-use adt;
-use base::*;
-use build::{Load, Store};
-use common::*;
-use cleanup;
-use cleanup::{CleanupMethods, DropHintDatum, DropHintMethods};
-use expr;
-use tvec;
-use value::Value;
-use rustc::ty::Ty;
-
-use std::fmt;
-use syntax::ast;
-use syntax_pos::DUMMY_SP;
-
-/// A `Datum` encapsulates the result of evaluating an expression.  It
-/// describes where the value is stored, what Rust type the value has,
-/// whether it is addressed by reference, and so forth. Please refer
-/// the section on datums in `README.md` for more details.
-#[derive(Clone, Copy)]
-pub struct Datum<'tcx, K> {
-    /// The llvm value.  This is either a pointer to the Rust value or
-    /// the value itself, depending on `kind` below.
-    pub val: ValueRef,
-
-    /// The rust type of the value.
-    pub ty: Ty<'tcx>,
-
-    /// Indicates whether this is by-ref or by-value.
-    pub kind: K,
-}
-
-impl<'tcx, K: fmt::Debug> fmt::Debug for Datum<'tcx, K> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Datum({:?}, {:?}, {:?})",
-               Value(self.val), self.ty, self.kind)
-    }
-}
-
-pub struct DatumBlock<'blk, 'tcx: 'blk, K> {
-    pub bcx: Block<'blk, 'tcx>,
-    pub datum: Datum<'tcx, K>,
-}
-
-#[derive(Debug)]
-pub enum Expr {
-    /// a fresh value that was produced and which has no cleanup yet
-    /// because it has not yet "landed" into its permanent home
-    RvalueExpr(Rvalue),
-
-    /// `val` is a pointer into memory for which a cleanup is scheduled
-    /// (and thus has type *T). If you move out of an Lvalue, you must
-    /// zero out the memory (FIXME #5016).
-    LvalueExpr(Lvalue),
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum DropFlagInfo {
-    DontZeroJustUse(ast::NodeId),
-    ZeroAndMaintain(ast::NodeId),
-    None,
-}
-
-impl DropFlagInfo {
-    pub fn must_zero(&self) -> bool {
-        match *self {
-            DropFlagInfo::DontZeroJustUse(..) => false,
-            DropFlagInfo::ZeroAndMaintain(..) => true,
-            DropFlagInfo::None => true,
-        }
-    }
-
-    pub fn hint_datum<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>)
-                              -> Option<DropHintDatum<'tcx>> {
-        let id = match *self {
-            DropFlagInfo::None => return None,
-            DropFlagInfo::DontZeroJustUse(id) |
-            DropFlagInfo::ZeroAndMaintain(id) => id,
-        };
-
-        let hints = bcx.fcx.lldropflag_hints.borrow();
-        let retval = hints.hint_datum(id);
-        assert!(retval.is_some(), "An id (={}) means must have a hint", id);
-        retval
-    }
-}
-
-// FIXME: having Lvalue be `Copy` is a bit of a footgun, since clients
-// may not realize that subparts of an Lvalue can have a subset of
-// drop-flags associated with them, while this as written will just
-// memcpy the drop_flag_info. But, it is an easier way to get `_match`
-// off the ground to just let this be `Copy` for now.
-#[derive(Copy, Clone, Debug)]
-pub struct Lvalue {
-    pub source: &'static str,
-    pub drop_flag_info: DropFlagInfo
-}
-
-#[derive(Debug)]
-pub struct Rvalue {
-    pub mode: RvalueMode
-}
-
-/// Classifies what action we should take when a value is moved away
-/// with respect to its drop-flag.
-///
-/// Long term there will be no need for this classification: all flags
-/// (which will be stored on the stack frame) will have the same
-/// interpretation and maintenance code associated with them.
-#[derive(Copy, Clone, Debug)]
-pub enum HintKind {
-    /// When the value is moved, set the drop-flag to "dropped"
-    /// (i.e. "zero the flag", even when the specific representation
-    /// is not literally 0) and when it is reinitialized, set the
-    /// drop-flag back to "initialized".
-    ZeroAndMaintain,
-
-    /// When the value is moved, do not set the drop-flag to "dropped"
-    /// However, continue to read the drop-flag in deciding whether to
-    /// drop. (In essence, the path/fragment in question will never
-    /// need to be dropped at the points where it is moved away by
-    /// this code, but we are defending against the scenario where
-    /// some *other* code could move away (or drop) the value and thus
-    /// zero-the-flag, which is why we will still read from it.
-    DontZeroJustUse,
-}
-
-impl Lvalue { // Constructors for various Lvalues.
-    pub fn new<'blk, 'tcx>(source: &'static str) -> Lvalue {
-        debug!("Lvalue at {} no drop flag info", source);
-        Lvalue { source: source, drop_flag_info: DropFlagInfo::None }
-    }
-
-    pub fn new_dropflag_hint(source: &'static str) -> Lvalue {
-        debug!("Lvalue at {} is drop flag hint", source);
-        Lvalue { source: source, drop_flag_info: DropFlagInfo::None }
-    }
-
-    pub fn new_with_hint<'blk, 'tcx>(source: &'static str,
-                                     bcx: Block<'blk, 'tcx>,
-                                     id: ast::NodeId,
-                                     k: HintKind) -> Lvalue {
-        let (opt_id, info) = {
-            let hint_available = Lvalue::has_dropflag_hint(bcx, id) &&
-                bcx.tcx().sess.nonzeroing_move_hints();
-            let info = match k {
-                HintKind::ZeroAndMaintain if hint_available =>
-                    DropFlagInfo::ZeroAndMaintain(id),
-                HintKind::DontZeroJustUse if hint_available =>
-                    DropFlagInfo::DontZeroJustUse(id),
-                _ =>
-                    DropFlagInfo::None,
-            };
-            (Some(id), info)
-        };
-        debug!("Lvalue at {}, id: {:?} info: {:?}", source, opt_id, info);
-        Lvalue { source: source, drop_flag_info: info }
-    }
-} // end Lvalue constructor methods.
-
-impl Lvalue {
-    fn has_dropflag_hint<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                     id: ast::NodeId) -> bool {
-        let hints = bcx.fcx.lldropflag_hints.borrow();
-        hints.has_hint(id)
-    }
-    pub fn dropflag_hint<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>)
-                                 -> Option<DropHintDatum<'tcx>> {
-        self.drop_flag_info.hint_datum(bcx)
-    }
-}
-
-impl Rvalue {
-    pub fn new(m: RvalueMode) -> Rvalue {
-        Rvalue { mode: m }
-    }
-}
-
-// Make Datum linear for more type safety.
-impl Drop for Rvalue {
-    fn drop(&mut self) { }
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub enum RvalueMode {
-    /// `val` is a pointer to the actual value (and thus has type *T)
-    ByRef,
-
-    /// `val` is the actual value (*only used for immediates* like ints, ptrs)
-    ByValue,
-}
-
-pub fn immediate_rvalue<'tcx>(val: ValueRef, ty: Ty<'tcx>) -> Datum<'tcx, Rvalue> {
-    return Datum::new(val, ty, Rvalue::new(ByValue));
-}
-
-pub fn immediate_rvalue_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                        val: ValueRef,
-                                        ty: Ty<'tcx>)
-                                        -> DatumBlock<'blk, 'tcx, Rvalue> {
-    return DatumBlock::new(bcx, immediate_rvalue(val, ty))
-}
-
-/// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to
-/// it. The memory will be dropped upon exit from `scope`. The callback `populate` should
-/// initialize the memory.
-///
-/// The flag `zero` indicates how the temporary space itself should be
-/// initialized at the outset of the function; the only time that
-/// `InitAlloca::Uninit` is a valid value for `zero` is when the
-/// caller can prove that either (1.) the code injected by `populate`
-/// onto `bcx` always dominates the end of `scope`, or (2.) the data
-/// being allocated has no associated destructor.
-pub fn lvalue_scratch_datum<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
-                                           ty: Ty<'tcx>,
-                                           name: &str,
-                                           zero: InitAlloca,
-                                           scope: cleanup::ScopeId,
-                                           populate: F)
-                                           -> DatumBlock<'blk, 'tcx, Lvalue> where
-    F: FnOnce(Block<'blk, 'tcx>, ValueRef) -> Block<'blk, 'tcx>,
-{
-    // Very subtle: potentially initialize the scratch memory at point where it is alloca'ed.
-    // (See discussion at Issue 30530.)
-    let scratch = alloc_ty_init(bcx, ty, zero, name);
-    debug!("lvalue_scratch_datum scope={:?} scratch={:?} ty={:?}",
-           scope, Value(scratch), ty);
-
-    // Subtle. Populate the scratch memory *before* scheduling cleanup.
-    let bcx = populate(bcx, scratch);
-    bcx.fcx.schedule_drop_mem(scope, scratch, ty, None);
-
-    DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue::new("datum::lvalue_scratch_datum")))
-}
-
-/// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to
-/// it.  If `zero` is true, the space will be zeroed when it is allocated; this is normally not
-/// necessary, but in the case of automatic rooting in match statements it is possible to have
-/// temporaries that may not get initialized if a certain arm is not taken, so we must zero them.
-/// You must arrange any cleanups etc yourself!
-pub fn rvalue_scratch_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                        ty: Ty<'tcx>,
-                                        name: &str)
-                                        -> Datum<'tcx, Rvalue> {
-    let scratch = alloc_ty(bcx, ty, name);
-    call_lifetime_start(bcx, scratch);
-    Datum::new(scratch, ty, Rvalue::new(ByRef))
-}
-
-/// Indicates the "appropriate" mode for this value, which is either by ref or by value, depending
-/// on whether type is immediate or not.
-pub fn appropriate_rvalue_mode<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                         ty: Ty<'tcx>) -> RvalueMode {
-    if type_is_immediate(ccx, ty) {
-        ByValue
-    } else {
-        ByRef
-    }
-}
-
-fn add_rvalue_clean<'a, 'tcx>(mode: RvalueMode,
-                              fcx: &FunctionContext<'a, 'tcx>,
-                              scope: cleanup::ScopeId,
-                              val: ValueRef,
-                              ty: Ty<'tcx>) {
-    debug!("add_rvalue_clean scope={:?} val={:?} ty={:?}",
-           scope, Value(val), ty);
-    match mode {
-        ByValue => { fcx.schedule_drop_immediate(scope, val, ty); }
-        ByRef => {
-            fcx.schedule_lifetime_end(scope, val);
-            fcx.schedule_drop_mem(scope, val, ty, None);
-        }
-    }
-}
-
-pub trait KindOps {
-
-    /// Take appropriate action after the value in `datum` has been
-    /// stored to a new location.
-    fn post_store<'blk, 'tcx>(&self,
-                              bcx: Block<'blk, 'tcx>,
-                              val: ValueRef,
-                              ty: Ty<'tcx>)
-                              -> Block<'blk, 'tcx>;
-
-    /// True if this mode is a reference mode, meaning that the datum's
-    /// val field is a pointer to the actual value
-    fn is_by_ref(&self) -> bool;
-
-    /// Converts to an Expr kind
-    fn to_expr_kind(self) -> Expr;
-
-}
-
-impl KindOps for Rvalue {
-    fn post_store<'blk, 'tcx>(&self,
-                              bcx: Block<'blk, 'tcx>,
-                              _val: ValueRef,
-                              _ty: Ty<'tcx>)
-                              -> Block<'blk, 'tcx> {
-        // No cleanup is scheduled for an rvalue, so we don't have
-        // to do anything after a move to cancel or duplicate it.
-        if self.is_by_ref() {
-            call_lifetime_end(bcx, _val);
-        }
-        bcx
-    }
-
-    fn is_by_ref(&self) -> bool {
-        self.mode == ByRef
-    }
-
-    fn to_expr_kind(self) -> Expr {
-        RvalueExpr(self)
-    }
-}
-
-impl KindOps for Lvalue {
-    /// If an lvalue is moved, we must zero out the memory in which it resides so as to cancel
-    /// cleanup. If an @T lvalue is copied, we must increment the reference count.
-    fn post_store<'blk, 'tcx>(&self,
-                              bcx: Block<'blk, 'tcx>,
-                              val: ValueRef,
-                              ty: Ty<'tcx>)
-                              -> Block<'blk, 'tcx> {
-        let _icx = push_ctxt("<Lvalue as KindOps>::post_store");
-        if bcx.fcx.type_needs_drop(ty) {
-            // cancel cleanup of affine values:
-            // 1. if it has drop-hint, mark as moved; then code
-            //    aware of drop-hint won't bother calling the
-            //    drop-glue itself.
-            if let Some(hint_datum) = self.drop_flag_info.hint_datum(bcx) {
-                let moved_hint_byte = adt::DTOR_MOVED_HINT;
-                let hint_llval = hint_datum.to_value().value();
-                Store(bcx, C_u8(bcx.fcx.ccx, moved_hint_byte), hint_llval);
-            }
-            // 2. if the drop info says its necessary, drop-fill the memory.
-            if self.drop_flag_info.must_zero() {
-                let () = drop_done_fill_mem(bcx, val, ty);
-            }
-            bcx
-        } else {
-            // FIXME (#5016) would be nice to assert this, but we have
-            // to allow for e.g. DontZeroJustUse flags, for now.
-            //
-            // (The dropflag hint construction should be taking
-            // !type_needs_drop into account; earlier analysis phases
-            // may not have all the info they need to include such
-            // information properly, I think; in particular the
-            // fragments analysis works on a non-monomorphized view of
-            // the code.)
-            //
-            // assert_eq!(self.drop_flag_info, DropFlagInfo::None);
-            bcx
-        }
-    }
-
-    fn is_by_ref(&self) -> bool {
-        true
-    }
-
-    fn to_expr_kind(self) -> Expr {
-        LvalueExpr(self)
-    }
-}
-
-impl KindOps for Expr {
-    fn post_store<'blk, 'tcx>(&self,
-                              bcx: Block<'blk, 'tcx>,
-                              val: ValueRef,
-                              ty: Ty<'tcx>)
-                              -> Block<'blk, 'tcx> {
-        match *self {
-            LvalueExpr(ref l) => l.post_store(bcx, val, ty),
-            RvalueExpr(ref r) => r.post_store(bcx, val, ty),
-        }
-    }
-
-    fn is_by_ref(&self) -> bool {
-        match *self {
-            LvalueExpr(ref l) => l.is_by_ref(),
-            RvalueExpr(ref r) => r.is_by_ref()
-        }
-    }
-
-    fn to_expr_kind(self) -> Expr {
-        self
-    }
-}
-
-impl<'tcx> Datum<'tcx, Rvalue> {
-    /// Schedules a cleanup for this datum in the given scope. That means that this datum is no
-    /// longer an rvalue datum; hence, this function consumes the datum and returns the contained
-    /// ValueRef.
-    pub fn add_clean<'a>(self,
-                         fcx: &FunctionContext<'a, 'tcx>,
-                         scope: cleanup::ScopeId)
-                         -> ValueRef {
-        add_rvalue_clean(self.kind.mode, fcx, scope, self.val, self.ty);
-        self.val
-    }
-
-    /// Returns an lvalue datum (that is, a by ref datum with cleanup scheduled). If `self` is not
-    /// already an lvalue, cleanup will be scheduled in the temporary scope for `expr_id`.
-    pub fn to_lvalue_datum_in_scope<'blk>(self,
-                                          bcx: Block<'blk, 'tcx>,
-                                          name: &str,
-                                          scope: cleanup::ScopeId)
-                                          -> DatumBlock<'blk, 'tcx, Lvalue> {
-        let fcx = bcx.fcx;
-
-        match self.kind.mode {
-            ByRef => {
-                add_rvalue_clean(ByRef, fcx, scope, self.val, self.ty);
-                DatumBlock::new(bcx, Datum::new(
-                    self.val,
-                    self.ty,
-                    Lvalue::new("datum::to_lvalue_datum_in_scope")))
-            }
-
-            ByValue => {
-                lvalue_scratch_datum(
-                    bcx, self.ty, name, InitAlloca::Dropped, scope,
-                    |bcx, llval| {
-                        debug!("populate call for Datum::to_lvalue_datum_in_scope \
-                                self.ty={:?}", self.ty);
-                        // do not call_lifetime_start here; the
-                        // `InitAlloc::Dropped` will start scratch
-                        // value's lifetime at open of function body.
-                        let bcx = self.store_to(bcx, llval);
-                        bcx.fcx.schedule_lifetime_end(scope, llval);
-                        bcx
-                    })
-            }
-        }
-    }
-
-    pub fn to_ref_datum<'blk>(self, bcx: Block<'blk, 'tcx>)
-                              -> DatumBlock<'blk, 'tcx, Rvalue> {
-        let mut bcx = bcx;
-        match self.kind.mode {
-            ByRef => DatumBlock::new(bcx, self),
-            ByValue => {
-                let scratch = rvalue_scratch_datum(bcx, self.ty, "to_ref");
-                bcx = self.store_to(bcx, scratch.val);
-                DatumBlock::new(bcx, scratch)
-            }
-        }
-    }
-
-    pub fn to_appropriate_datum<'blk>(self, bcx: Block<'blk, 'tcx>)
-                                      -> DatumBlock<'blk, 'tcx, Rvalue> {
-        match self.appropriate_rvalue_mode(bcx.ccx()) {
-            ByRef => {
-                self.to_ref_datum(bcx)
-            }
-            ByValue => {
-                match self.kind.mode {
-                    ByValue => DatumBlock::new(bcx, self),
-                    ByRef => {
-                        let llval = load_ty(bcx, self.val, self.ty);
-                        call_lifetime_end(bcx, self.val);
-                        DatumBlock::new(bcx, Datum::new(llval, self.ty, Rvalue::new(ByValue)))
-                    }
-                }
-            }
-        }
-    }
-}
-
-/// Methods suitable for "expr" datums that could be either lvalues or
-/// rvalues. These include coercions into lvalues/rvalues but also a number
-/// of more general operations. (Some of those operations could be moved to
-/// the more general `impl<K> Datum<K>`, but it's convenient to have them
-/// here since we can `match self.kind` rather than having to implement
-/// generic methods in `KindOps`.)
-impl<'tcx> Datum<'tcx, Expr> {
-    fn match_kind<R, F, G>(self, if_lvalue: F, if_rvalue: G) -> R where
-        F: FnOnce(Datum<'tcx, Lvalue>) -> R,
-        G: FnOnce(Datum<'tcx, Rvalue>) -> R,
-    {
-        let Datum { val, ty, kind } = self;
-        match kind {
-            LvalueExpr(l) => if_lvalue(Datum::new(val, ty, l)),
-            RvalueExpr(r) => if_rvalue(Datum::new(val, ty, r)),
-        }
-    }
-
-    /// Asserts that this datum *is* an lvalue and returns it.
-    #[allow(dead_code)] // potentially useful
-    pub fn assert_lvalue(self) -> Datum<'tcx, Lvalue> {
-        self.match_kind(
-            |d| d,
-            |_| bug!("assert_lvalue given rvalue"))
-    }
-
-    pub fn store_to_dest<'blk>(self,
-                               bcx: Block<'blk, 'tcx>,
-                               dest: expr::Dest,
-                               expr_id: ast::NodeId)
-                               -> Block<'blk, 'tcx> {
-        match dest {
-            expr::Ignore => {
-                self.add_clean_if_rvalue(bcx, expr_id);
-                bcx
-            }
-            expr::SaveIn(addr) => {
-                self.store_to(bcx, addr)
-            }
-        }
-    }
-
-    /// Arranges cleanup for `self` if it is an rvalue. Use when you are done working with a value
-    /// that may need drop.
-    pub fn add_clean_if_rvalue<'blk>(self,
-                                     bcx: Block<'blk, 'tcx>,
-                                     expr_id: ast::NodeId) {
-        self.match_kind(
-            |_| { /* Nothing to do, cleanup already arranged */ },
-            |r| {
-                let scope = cleanup::temporary_scope(bcx.tcx(), expr_id);
-                r.add_clean(bcx.fcx, scope);
-            })
-    }
-
-    pub fn to_lvalue_datum<'blk>(self,
-                                 bcx: Block<'blk, 'tcx>,
-                                 name: &str,
-                                 expr_id: ast::NodeId)
-                                 -> DatumBlock<'blk, 'tcx, Lvalue> {
-        debug!("to_lvalue_datum self: {:?}", self);
-
-        self.match_kind(
-            |l| DatumBlock::new(bcx, l),
-            |r| {
-                let scope = cleanup::temporary_scope(bcx.tcx(), expr_id);
-                r.to_lvalue_datum_in_scope(bcx, name, scope)
-            })
-    }
-
-    /// Ensures that we have an rvalue datum (that is, a datum with no cleanup scheduled).
-    pub fn to_rvalue_datum<'blk>(self,
-                                 bcx: Block<'blk, 'tcx>,
-                                 name: &'static str)
-                                 -> DatumBlock<'blk, 'tcx, Rvalue> {
-        self.match_kind(
-            |l| {
-                let mut bcx = bcx;
-                match l.appropriate_rvalue_mode(bcx.ccx()) {
-                    ByRef => {
-                        let scratch = rvalue_scratch_datum(bcx, l.ty, name);
-                        bcx = l.store_to(bcx, scratch.val);
-                        DatumBlock::new(bcx, scratch)
-                    }
-                    ByValue => {
-                        let v = load_ty(bcx, l.val, l.ty);
-                        bcx = l.kind.post_store(bcx, l.val, l.ty);
-                        DatumBlock::new(bcx, Datum::new(v, l.ty, Rvalue::new(ByValue)))
-                    }
-                }
-            },
-            |r| DatumBlock::new(bcx, r))
-    }
-
-}
-
-/// Methods suitable only for lvalues. These include the various
-/// operations to extract components out of compound data structures,
-/// such as extracting the field from a struct or a particular element
-/// from an array.
-impl<'tcx> Datum<'tcx, Lvalue> {
-    /// Converts a datum into a by-ref value. The datum type must be one which is always passed by
-    /// reference.
-    pub fn to_llref(self) -> ValueRef {
-        self.val
-    }
-
-    // Extracts a component of a compound data structure (e.g., a field from a
-    // struct). Note that if self is an opened, unsized type then the returned
-    // datum may also be unsized _without the size information_. It is the
-    // callers responsibility to package the result in some way to make a valid
-    // datum in that case (e.g., by making a fat pointer or opened pair).
-    pub fn get_element<'blk, F>(&self, bcx: Block<'blk, 'tcx>, ty: Ty<'tcx>,
-                                gep: F)
-                                -> Datum<'tcx, Lvalue> where
-        F: FnOnce(adt::MaybeSizedValue) -> ValueRef,
-    {
-        let val = if type_is_sized(bcx.tcx(), self.ty) {
-            let val = adt::MaybeSizedValue::sized(self.val);
-            gep(val)
-        } else {
-            let val = adt::MaybeSizedValue::unsized_(
-                Load(bcx, expr::get_dataptr(bcx, self.val)),
-                Load(bcx, expr::get_meta(bcx, self.val)));
-            gep(val)
-        };
-        Datum {
-            val: val,
-            kind: Lvalue::new("Datum::get_element"),
-            ty: ty,
-        }
-    }
-
-    pub fn get_vec_base_and_len<'blk>(&self, bcx: Block<'blk, 'tcx>)
-                                      -> (ValueRef, ValueRef) {
-        //! Converts a vector into the slice pair.
-
-        tvec::get_base_and_len(bcx, self.val, self.ty)
-    }
-}
-
-/// Generic methods applicable to any sort of datum.
-impl<'tcx, K: KindOps + fmt::Debug> Datum<'tcx, K> {
-    pub fn new(val: ValueRef, ty: Ty<'tcx>, kind: K) -> Datum<'tcx, K> {
-        Datum { val: val, ty: ty, kind: kind }
-    }
-
-    pub fn to_expr_datum(self) -> Datum<'tcx, Expr> {
-        let Datum { val, ty, kind } = self;
-        Datum { val: val, ty: ty, kind: kind.to_expr_kind() }
-    }
-
-    /// Moves or copies this value into a new home, as appropriate depending on the type of the
-    /// datum. This method consumes the datum, since it would be incorrect to go on using the datum
-    /// if the value represented is affine (and hence the value is moved).
-    pub fn store_to<'blk>(self,
-                          bcx: Block<'blk, 'tcx>,
-                          dst: ValueRef)
-                          -> Block<'blk, 'tcx> {
-        self.shallow_copy_raw(bcx, dst);
-
-        self.kind.post_store(bcx, self.val, self.ty)
-    }
-
-    /// Helper function that performs a shallow copy of this value into `dst`, which should be a
-    /// pointer to a memory location suitable for `self.ty`. `dst` should contain uninitialized
-    /// memory (either newly allocated, zeroed, or dropped).
-    ///
-    /// This function is private to datums because it leaves memory in an unstable state, where the
-    /// source value has been copied but not zeroed. Public methods are `store_to` (if you no
-    /// longer need the source value) or `shallow_copy` (if you wish the source value to remain
-    /// valid).
-    fn shallow_copy_raw<'blk>(&self,
-                              bcx: Block<'blk, 'tcx>,
-                              dst: ValueRef)
-                              -> Block<'blk, 'tcx> {
-        let _icx = push_ctxt("copy_to_no_check");
-
-        if type_is_zero_size(bcx.ccx(), self.ty) {
-            return bcx;
-        }
-
-        if self.kind.is_by_ref() {
-            memcpy_ty(bcx, dst, self.val, self.ty);
-        } else {
-            store_ty(bcx, self.val, dst, self.ty);
-        }
-
-        return bcx;
-    }
-
-    /// Copies the value into a new location. This function always preserves the existing datum as
-    /// a valid value. Therefore, it does not consume `self` and, also, cannot be applied to affine
-    /// values (since they must never be duplicated).
-    pub fn shallow_copy<'blk>(&self,
-                              bcx: Block<'blk, 'tcx>,
-                              dst: ValueRef)
-                              -> Block<'blk, 'tcx> {
-        /*!
-         * Copies the value into a new location. This function always
-         * preserves the existing datum as a valid value. Therefore,
-         * it does not consume `self` and, also, cannot be applied to
-         * affine values (since they must never be duplicated).
-         */
-
-        assert!(!self.ty.moves_by_default(bcx.tcx(),
-            &bcx.tcx().empty_parameter_environment(), DUMMY_SP));
-        self.shallow_copy_raw(bcx, dst)
-    }
-
-    /// See the `appropriate_rvalue_mode()` function
-    pub fn appropriate_rvalue_mode<'a>(&self, ccx: &CrateContext<'a, 'tcx>)
-                                       -> RvalueMode {
-        appropriate_rvalue_mode(ccx, self.ty)
-    }
-
-    /// Converts `self` into a by-value `ValueRef`. Consumes this datum (i.e., absolves you of
-    /// responsibility to cleanup the value). For this to work, the value must be something
-    /// scalar-ish (like an int or a pointer) which (1) does not require drop glue and (2) is
-    /// naturally passed around by value, and not by reference.
-    pub fn to_llscalarish<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef {
-        assert!(!bcx.fcx.type_needs_drop(self.ty));
-        assert!(self.appropriate_rvalue_mode(bcx.ccx()) == ByValue);
-        if self.kind.is_by_ref() {
-            load_ty(bcx, self.val, self.ty)
-        } else {
-            self.val
-        }
-    }
-
-    pub fn to_llbool<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef {
-        assert!(self.ty.is_bool());
-        self.to_llscalarish(bcx)
-    }
-}
-
-impl<'blk, 'tcx, K> DatumBlock<'blk, 'tcx, K> {
-    pub fn new(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, K>)
-               -> DatumBlock<'blk, 'tcx, K> {
-        DatumBlock { bcx: bcx, datum: datum }
-    }
-}
-
-impl<'blk, 'tcx, K: KindOps + fmt::Debug> DatumBlock<'blk, 'tcx, K> {
-    pub fn to_expr_datumblock(self) -> DatumBlock<'blk, 'tcx, Expr> {
-        DatumBlock::new(self.bcx, self.datum.to_expr_datum())
-    }
-}
-
-impl<'blk, 'tcx> DatumBlock<'blk, 'tcx, Expr> {
-    pub fn store_to_dest(self,
-                         dest: expr::Dest,
-                         expr_id: ast::NodeId) -> Block<'blk, 'tcx> {
-        let DatumBlock { bcx, datum } = self;
-        datum.store_to_dest(bcx, dest, expr_id)
-    }
-
-    pub fn to_llbool(self) -> Result<'blk, 'tcx> {
-        let DatumBlock { datum, bcx } = self;
-        Result::new(bcx, datum.to_llbool(bcx))
-    }
-}
index fe6a48d4c559dac732df51158504bdb562f3f466..21716d55ac6fa33c67d950d467f4d49deae26574 100644 (file)
 use llvm;
 use llvm::debuginfo::{DIScope, DISubprogram};
 use common::{CrateContext, FunctionContext};
-use rustc::hir::pat_util;
 use rustc::mir::repr::{Mir, VisibilityScope};
-use rustc::util::nodemap::NodeMap;
 
 use libc::c_uint;
 use std::ptr;
 
-use syntax_pos::{Span, Pos};
-use syntax::{ast, codemap};
+use syntax_pos::Pos;
 
 use rustc_data_structures::bitvec::BitVector;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
-use rustc::hir::{self, PatKind};
 
-// This procedure builds the *scope map* for a given function, which maps any
-// given ast::NodeId in the function's AST to the correct DIScope metadata instance.
-//
-// This builder procedure walks the AST in execution order and keeps track of
-// what belongs to which scope, creating DIScope DIEs along the way, and
-// introducing *artificial* lexical scope descriptors where necessary. These
-// artificial scopes allow GDB to correctly handle name shadowing.
-pub fn create_scope_map(cx: &CrateContext,
-                        args: &[hir::Arg],
-                        fn_entry_block: &hir::Block,
-                        fn_metadata: DISubprogram,
-                        fn_ast_id: ast::NodeId)
-                        -> NodeMap<DIScope> {
-    let mut scope_map = NodeMap();
-    let mut scope_stack = vec!(ScopeStackEntry { scope_metadata: fn_metadata, name: None });
-    scope_map.insert(fn_ast_id, fn_metadata);
-
-    // Push argument identifiers onto the stack so arguments integrate nicely
-    // with variable shadowing.
-    for arg in args {
-        pat_util::pat_bindings(&arg.pat, |_, node_id, _, path1| {
-            scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata,
-                                               name: Some(path1.node) });
-            scope_map.insert(node_id, fn_metadata);
-        })
-    }
+use syntax_pos::BytePos;
 
-    // Clang creates a separate scope for function bodies, so let's do this too.
-    with_new_scope(cx,
-                   fn_entry_block.span,
-                   &mut scope_stack,
-                   &mut scope_map,
-                   |cx, scope_stack, scope_map| {
-        walk_block(cx, fn_entry_block, scope_stack, scope_map);
-    });
+#[derive(Clone, Copy, Debug)]
+pub struct MirDebugScope {
+    pub scope_metadata: DIScope,
+    // Start and end offsets of the file to which this DIScope belongs.
+    // These are used to quickly determine whether some span refers to the same file.
+    pub file_start_pos: BytePos,
+    pub file_end_pos: BytePos,
+}
 
-    return scope_map;
+impl MirDebugScope {
+    pub fn is_valid(&self) -> bool {
+        !self.scope_metadata.is_null()
+    }
 }
 
 /// Produce DIScope DIEs for each MIR Scope which has variables defined in it.
 /// If debuginfo is disabled, the returned vector is empty.
-pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec<VisibilityScope, DIScope> {
+pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec<VisibilityScope, MirDebugScope> {
     let mir = fcx.mir.clone().expect("create_mir_scopes: missing MIR for fn");
-    let mut scopes = IndexVec::from_elem(ptr::null_mut(), &mir.visibility_scopes);
+    let null_scope = MirDebugScope {
+        scope_metadata: ptr::null_mut(),
+        file_start_pos: BytePos(0),
+        file_end_pos: BytePos(0)
+    };
+    let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes);
 
     let fn_metadata = match fcx.debug_context {
         FunctionDebugContext::RegularContext(box ref data) => data.fn_metadata,
@@ -102,8 +81,8 @@ fn make_mir_scope(ccx: &CrateContext,
                   has_variables: &BitVector,
                   fn_metadata: DISubprogram,
                   scope: VisibilityScope,
-                  scopes: &mut IndexVec<VisibilityScope, DIScope>) {
-    if !scopes[scope].is_null() {
+                  scopes: &mut IndexVec<VisibilityScope, MirDebugScope>) {
+    if scopes[scope].is_valid() {
         return;
     }
 
@@ -113,7 +92,12 @@ fn make_mir_scope(ccx: &CrateContext,
         scopes[parent]
     } else {
         // The root is the function itself.
-        scopes[scope] = fn_metadata;
+        let loc = span_start(ccx, mir.span);
+        scopes[scope] = MirDebugScope {
+            scope_metadata: fn_metadata,
+            file_start_pos: loc.file.start_pos,
+            file_end_pos: loc.file.end_pos,
+        };
         return;
     };
 
@@ -124,422 +108,25 @@ fn make_mir_scope(ccx: &CrateContext,
         // However, we don't skip creating a nested scope if
         // our parent is the root, because we might want to
         // put arguments in the root and not have shadowing.
-        if parent_scope != fn_metadata {
+        if parent_scope.scope_metadata != fn_metadata {
             scopes[scope] = parent_scope;
             return;
         }
     }
 
     let loc = span_start(ccx, scope_data.span);
-    scopes[scope] = unsafe {
     let file_metadata = file_metadata(ccx, &loc.file.name, &loc.file.abs_path);
+    let scope_metadata = unsafe {
         llvm::LLVMRustDIBuilderCreateLexicalBlock(
             DIB(ccx),
-            parent_scope,
+            parent_scope.scope_metadata,
             file_metadata,
             loc.line as c_uint,
             loc.col.to_usize() as c_uint)
     };
-}
-
-// local helper functions for walking the AST.
-fn with_new_scope<F>(cx: &CrateContext,
-                     scope_span: Span,
-                     scope_stack: &mut Vec<ScopeStackEntry> ,
-                     scope_map: &mut NodeMap<DIScope>,
-                     inner_walk: F) where
-    F: FnOnce(&CrateContext, &mut Vec<ScopeStackEntry>, &mut NodeMap<DIScope>),
-{
-    // Create a new lexical scope and push it onto the stack
-    let loc = span_start(cx, scope_span);
-    let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path);
-    let parent_scope = scope_stack.last().unwrap().scope_metadata;
-
-    let scope_metadata = unsafe {
-        llvm::LLVMRustDIBuilderCreateLexicalBlock(
-            DIB(cx),
-            parent_scope,
-            file_metadata,
-            loc.line as c_uint,
-            loc.col.to_usize() as c_uint)
+    scopes[scope] = MirDebugScope {
+        scope_metadata: scope_metadata,
+        file_start_pos: loc.file.start_pos,
+        file_end_pos: loc.file.end_pos,
     };
-
-    scope_stack.push(ScopeStackEntry { scope_metadata: scope_metadata, name: None });
-
-    inner_walk(cx, scope_stack, scope_map);
-
-    // pop artificial scopes
-    while scope_stack.last().unwrap().name.is_some() {
-        scope_stack.pop();
-    }
-
-    if scope_stack.last().unwrap().scope_metadata != scope_metadata {
-        span_bug!(scope_span, "debuginfo: Inconsistency in scope management.");
-    }
-
-    scope_stack.pop();
-}
-
-struct ScopeStackEntry {
-    scope_metadata: DIScope,
-    name: Option<ast::Name>
-}
-
-fn walk_block(cx: &CrateContext,
-              block: &hir::Block,
-              scope_stack: &mut Vec<ScopeStackEntry> ,
-              scope_map: &mut NodeMap<DIScope>) {
-    scope_map.insert(block.id, scope_stack.last().unwrap().scope_metadata);
-
-    // The interesting things here are statements and the concluding expression.
-    for statement in &block.stmts {
-        scope_map.insert(statement.node.id(),
-                         scope_stack.last().unwrap().scope_metadata);
-
-        match statement.node {
-            hir::StmtDecl(ref decl, _) =>
-                walk_decl(cx, &decl, scope_stack, scope_map),
-            hir::StmtExpr(ref exp, _) |
-            hir::StmtSemi(ref exp, _) =>
-                walk_expr(cx, &exp, scope_stack, scope_map),
-        }
-    }
-
-    if let Some(ref exp) = block.expr {
-        walk_expr(cx, &exp, scope_stack, scope_map);
-    }
-}
-
-fn walk_decl(cx: &CrateContext,
-             decl: &hir::Decl,
-             scope_stack: &mut Vec<ScopeStackEntry> ,
-             scope_map: &mut NodeMap<DIScope>) {
-    match *decl {
-        codemap::Spanned { node: hir::DeclLocal(ref local), .. } => {
-            scope_map.insert(local.id, scope_stack.last().unwrap().scope_metadata);
-
-            walk_pattern(cx, &local.pat, scope_stack, scope_map);
-
-            if let Some(ref exp) = local.init {
-                walk_expr(cx, &exp, scope_stack, scope_map);
-            }
-        }
-        _ => ()
-    }
-}
-
-fn walk_pattern(cx: &CrateContext,
-                pat: &hir::Pat,
-                scope_stack: &mut Vec<ScopeStackEntry> ,
-                scope_map: &mut NodeMap<DIScope>) {
-    // Unfortunately, we cannot just use pat_util::pat_bindings() or
-    // ast_util::walk_pat() here because we have to visit *all* nodes in
-    // order to put them into the scope map. The above functions don't do that.
-    match pat.node {
-        PatKind::Binding(_, ref path1, ref sub_pat_opt) => {
-            // LLVM does not properly generate 'DW_AT_start_scope' fields
-            // for variable DIEs. For this reason we have to introduce
-            // an artificial scope at bindings whenever a variable with
-            // the same name is declared in *any* parent scope.
-            //
-            // Otherwise the following error occurs:
-            //
-            // let x = 10;
-            //
-            // do_something(); // 'gdb print x' correctly prints 10
-            //
-            // {
-            //     do_something(); // 'gdb print x' prints 0, because it
-            //                     // already reads the uninitialized 'x'
-            //                     // from the next line...
-            //     let x = 100;
-            //     do_something(); // 'gdb print x' correctly prints 100
-            // }
-
-            // Is there already a binding with that name?
-            // N.B.: this comparison must be UNhygienic... because
-            // gdb knows nothing about the context, so any two
-            // variables with the same name will cause the problem.
-            let name = path1.node;
-            let need_new_scope = scope_stack
-                .iter()
-                .any(|entry| entry.name == Some(name));
-
-            if need_new_scope {
-                // Create a new lexical scope and push it onto the stack
-                let loc = span_start(cx, pat.span);
-                let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path);
-                let parent_scope = scope_stack.last().unwrap().scope_metadata;
-
-                let scope_metadata = unsafe {
-                    llvm::LLVMRustDIBuilderCreateLexicalBlock(
-                        DIB(cx),
-                        parent_scope,
-                        file_metadata,
-                        loc.line as c_uint,
-                        loc.col.to_usize() as c_uint)
-                };
-
-                scope_stack.push(ScopeStackEntry {
-                    scope_metadata: scope_metadata,
-                    name: Some(name)
-                });
-
-            } else {
-                // Push a new entry anyway so the name can be found
-                let prev_metadata = scope_stack.last().unwrap().scope_metadata;
-                scope_stack.push(ScopeStackEntry {
-                    scope_metadata: prev_metadata,
-                    name: Some(name)
-                });
-            }
-
-            scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-
-            if let Some(ref sub_pat) = *sub_pat_opt {
-                walk_pattern(cx, &sub_pat, scope_stack, scope_map);
-            }
-        }
-
-        PatKind::Wild => {
-            scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-        }
-
-        PatKind::TupleStruct(_, ref sub_pats, _) => {
-            scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-
-            for p in sub_pats {
-                walk_pattern(cx, &p, scope_stack, scope_map);
-            }
-        }
-
-        PatKind::Path(..) => {
-            scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-        }
-
-        PatKind::Struct(_, ref field_pats, _) => {
-            scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-
-            for &codemap::Spanned {
-                node: hir::FieldPat { pat: ref sub_pat, .. },
-                ..
-            } in field_pats {
-                walk_pattern(cx, &sub_pat, scope_stack, scope_map);
-            }
-        }
-
-        PatKind::Tuple(ref sub_pats, _) => {
-            scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-
-            for sub_pat in sub_pats {
-                walk_pattern(cx, &sub_pat, scope_stack, scope_map);
-            }
-        }
-
-        PatKind::Box(ref sub_pat) | PatKind::Ref(ref sub_pat, _) => {
-            scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-            walk_pattern(cx, &sub_pat, scope_stack, scope_map);
-        }
-
-        PatKind::Lit(ref exp) => {
-            scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-            walk_expr(cx, &exp, scope_stack, scope_map);
-        }
-
-        PatKind::Range(ref exp1, ref exp2) => {
-            scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-            walk_expr(cx, &exp1, scope_stack, scope_map);
-            walk_expr(cx, &exp2, scope_stack, scope_map);
-        }
-
-        PatKind::Vec(ref front_sub_pats, ref middle_sub_pats, ref back_sub_pats) => {
-            scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
-
-            for sub_pat in front_sub_pats {
-                walk_pattern(cx, &sub_pat, scope_stack, scope_map);
-            }
-
-            if let Some(ref sub_pat) = *middle_sub_pats {
-                walk_pattern(cx, &sub_pat, scope_stack, scope_map);
-            }
-
-            for sub_pat in back_sub_pats {
-                walk_pattern(cx, &sub_pat, scope_stack, scope_map);
-            }
-        }
-    }
-}
-
-fn walk_expr(cx: &CrateContext,
-             exp: &hir::Expr,
-             scope_stack: &mut Vec<ScopeStackEntry> ,
-             scope_map: &mut NodeMap<DIScope>) {
-
-    scope_map.insert(exp.id, scope_stack.last().unwrap().scope_metadata);
-
-    match exp.node {
-        hir::ExprLit(_)   |
-        hir::ExprBreak(_) |
-        hir::ExprAgain(_) |
-        hir::ExprPath(..) => {}
-
-        hir::ExprCast(ref sub_exp, _)     |
-        hir::ExprType(ref sub_exp, _) |
-        hir::ExprAddrOf(_, ref sub_exp)  |
-        hir::ExprField(ref sub_exp, _) |
-        hir::ExprTupField(ref sub_exp, _) =>
-            walk_expr(cx, &sub_exp, scope_stack, scope_map),
-
-        hir::ExprBox(ref sub_expr) => {
-            walk_expr(cx, &sub_expr, scope_stack, scope_map);
-        }
-
-        hir::ExprRet(ref exp_opt) => match *exp_opt {
-            Some(ref sub_exp) => walk_expr(cx, &sub_exp, scope_stack, scope_map),
-            None => ()
-        },
-
-        hir::ExprUnary(_, ref sub_exp) => {
-            walk_expr(cx, &sub_exp, scope_stack, scope_map);
-        }
-
-        hir::ExprAssignOp(_, ref lhs, ref rhs) |
-        hir::ExprIndex(ref lhs, ref rhs) |
-        hir::ExprBinary(_, ref lhs, ref rhs)    => {
-            walk_expr(cx, &lhs, scope_stack, scope_map);
-            walk_expr(cx, &rhs, scope_stack, scope_map);
-        }
-
-        hir::ExprVec(ref init_expressions) |
-        hir::ExprTup(ref init_expressions) => {
-            for ie in init_expressions {
-                walk_expr(cx, &ie, scope_stack, scope_map);
-            }
-        }
-
-        hir::ExprAssign(ref sub_exp1, ref sub_exp2) |
-        hir::ExprRepeat(ref sub_exp1, ref sub_exp2) => {
-            walk_expr(cx, &sub_exp1, scope_stack, scope_map);
-            walk_expr(cx, &sub_exp2, scope_stack, scope_map);
-        }
-
-        hir::ExprIf(ref cond_exp, ref then_block, ref opt_else_exp) => {
-            walk_expr(cx, &cond_exp, scope_stack, scope_map);
-
-            with_new_scope(cx,
-                           then_block.span,
-                           scope_stack,
-                           scope_map,
-                           |cx, scope_stack, scope_map| {
-                walk_block(cx, &then_block, scope_stack, scope_map);
-            });
-
-            match *opt_else_exp {
-                Some(ref else_exp) =>
-                    walk_expr(cx, &else_exp, scope_stack, scope_map),
-                _ => ()
-            }
-        }
-
-        hir::ExprWhile(ref cond_exp, ref loop_body, _) => {
-            walk_expr(cx, &cond_exp, scope_stack, scope_map);
-
-            with_new_scope(cx,
-                           loop_body.span,
-                           scope_stack,
-                           scope_map,
-                           |cx, scope_stack, scope_map| {
-                walk_block(cx, &loop_body, scope_stack, scope_map);
-            })
-        }
-
-        hir::ExprLoop(ref block, _) |
-        hir::ExprBlock(ref block)   => {
-            with_new_scope(cx,
-                           block.span,
-                           scope_stack,
-                           scope_map,
-                           |cx, scope_stack, scope_map| {
-                walk_block(cx, &block, scope_stack, scope_map);
-            })
-        }
-
-        hir::ExprClosure(_, ref decl, ref block, _) => {
-            with_new_scope(cx,
-                           block.span,
-                           scope_stack,
-                           scope_map,
-                           |cx, scope_stack, scope_map| {
-                for &hir::Arg { pat: ref pattern, .. } in &decl.inputs {
-                    walk_pattern(cx, &pattern, scope_stack, scope_map);
-                }
-
-                walk_block(cx, &block, scope_stack, scope_map);
-            })
-        }
-
-        hir::ExprCall(ref fn_exp, ref args) => {
-            walk_expr(cx, &fn_exp, scope_stack, scope_map);
-
-            for arg_exp in args {
-                walk_expr(cx, &arg_exp, scope_stack, scope_map);
-            }
-        }
-
-        hir::ExprMethodCall(_, _, ref args) => {
-            for arg_exp in args {
-                walk_expr(cx, &arg_exp, scope_stack, scope_map);
-            }
-        }
-
-        hir::ExprMatch(ref discriminant_exp, ref arms, _) => {
-            walk_expr(cx, &discriminant_exp, scope_stack, scope_map);
-
-            // For each arm we have to first walk the pattern as these might
-            // introduce new artificial scopes. It should be sufficient to
-            // walk only one pattern per arm, as they all must contain the
-            // same binding names.
-
-            for arm_ref in arms {
-                let arm_span = arm_ref.pats[0].span;
-
-                with_new_scope(cx,
-                               arm_span,
-                               scope_stack,
-                               scope_map,
-                               |cx, scope_stack, scope_map| {
-                    for pat in &arm_ref.pats {
-                        walk_pattern(cx, &pat, scope_stack, scope_map);
-                    }
-
-                    if let Some(ref guard_exp) = arm_ref.guard {
-                        walk_expr(cx, &guard_exp, scope_stack, scope_map)
-                    }
-
-                    walk_expr(cx, &arm_ref.body, scope_stack, scope_map);
-                })
-            }
-        }
-
-        hir::ExprStruct(_, ref fields, ref base_exp) => {
-            for &hir::Field { expr: ref exp, .. } in fields {
-                walk_expr(cx, &exp, scope_stack, scope_map);
-            }
-
-            match *base_exp {
-                Some(ref exp) => walk_expr(cx, &exp, scope_stack, scope_map),
-                None => ()
-            }
-        }
-
-        hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
-            for output in outputs {
-                walk_expr(cx, output, scope_stack, scope_map);
-            }
-
-            for input in inputs {
-                walk_expr(cx, input, scope_stack, scope_map);
-            }
-        }
-    }
 }
index f505efb1ab2f9aa18e994fbc2f2dbfd4d93acecc..67d4a0e044c9c8ac7d7b6594255269615a3ba6c5 100644 (file)
 use self::EnumDiscriminantInfo::*;
 
 use super::utils::{debug_context, DIB, span_start, bytes_to_bits, size_and_align_of,
-                   get_namespace_and_span_for_item, create_DIArray,
-                   fn_should_be_ignored, is_node_local_to_unit};
+                   get_namespace_and_span_for_item, create_DIArray, is_node_local_to_unit};
 use super::namespace::mangled_name_of_item;
 use super::type_names::{compute_debuginfo_type_name, push_debuginfo_type_name};
-use super::{declare_local, VariableKind, VariableAccess, CrateDebugContext};
+use super::{CrateDebugContext};
 use context::SharedCrateContext;
 use session::Session;
 
 use llvm::{self, ValueRef};
-use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType};
+use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType, DILexicalBlock};
 
 use rustc::hir::def_id::DefId;
-use rustc::hir::pat_util;
 use rustc::ty::subst::Substs;
-use rustc::hir::map as hir_map;
-use rustc::hir::{self, PatKind};
+use rustc::hir;
 use {type_of, adt, machine, monomorphize};
-use common::{self, CrateContext, FunctionContext, Block};
-use _match::{BindingInfo, TransBindingMode};
+use common::CrateContext;
 use type_::Type;
 use rustc::ty::{self, Ty};
-use session::config::{self, FullDebugInfo};
+use session::config;
 use util::nodemap::FnvHashMap;
 use util::common::path2cstr;
 
@@ -346,11 +342,10 @@ fn from_def_id_and_substs<'a, 'tcx>(type_map: &mut TypeMap<'tcx>,
             // Add the def-index as the second part
             output.push_str(&format!("{:x}", def_id.index.as_usize()));
 
-            let tps = &substs.types;
-            if !tps.is_empty() {
+            if substs.types().next().is_some() {
                 output.push('<');
 
-                for &type_parameter in tps {
+                for type_parameter in substs.types() {
                     let param_type_id =
                         type_map.get_unique_type_id_of_type(cx, type_parameter);
                     let param_type_id =
@@ -886,26 +881,6 @@ fn file_metadata_(cx: &CrateContext, key: &str, file_name: &str, work_dir: &str)
     file_metadata
 }
 
-/// Finds the scope metadata node for the given AST node.
-pub fn scope_metadata(fcx: &FunctionContext,
-                  node_id: ast::NodeId,
-                  error_reporting_span: Span)
-               -> DIScope {
-    let scope_map = &fcx.debug_context
-                        .get_ref(error_reporting_span)
-                        .scope_map;
-    match scope_map.borrow().get(&node_id).cloned() {
-        Some(scope_metadata) => scope_metadata,
-        None => {
-            let node = fcx.ccx.tcx().map.get(node_id);
-
-            span_bug!(error_reporting_span,
-                      "debuginfo: Could not find scope info for node {:?}",
-                      node);
-        }
-    }
-}
-
 fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                  t: Ty<'tcx>) -> DIType {
 
@@ -1251,7 +1226,7 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
                                       -> Vec<MemberDescription> {
         let adt = &self.enum_type.ty_adt_def().unwrap();
         match *self.type_rep {
-            adt::General(_, ref struct_defs, _) => {
+            adt::General(_, ref struct_defs) => {
                 let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata
                     .expect(""));
                 struct_defs
@@ -1285,7 +1260,7 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
                         }
                     }).collect()
             },
-            adt::Univariant(ref struct_def, _) => {
+            adt::Univariant(ref struct_def) => {
                 assert!(adt.variants.len() <= 1);
 
                 if adt.variants.is_empty() {
@@ -1635,7 +1610,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         adt::RawNullablePointer { .. }           |
         adt::StructWrappedNullablePointer { .. } |
         adt::Univariant(..)                      => None,
-        adt::General(inttype, _, _) => Some(discriminant_type_metadata(inttype)),
+        adt::General(inttype, _) => Some(discriminant_type_metadata(inttype)),
     };
 
     let enum_llvm_type = type_of::type_of(cx, enum_type);
@@ -1864,225 +1839,16 @@ pub fn create_global_var_metadata(cx: &CrateContext,
     }
 }
 
-/// Creates debug information for the given local variable.
-///
-/// This function assumes that there's a datum for each pattern component of the
-/// local in `bcx.fcx.lllocals`.
-/// Adds the created metadata nodes directly to the crate's IR.
-pub fn create_local_var_metadata(bcx: Block, local: &hir::Local) {
-    if bcx.unreachable.get() ||
-       fn_should_be_ignored(bcx.fcx) ||
-       bcx.sess().opts.debuginfo != FullDebugInfo  {
-        return;
-    }
-
-    let locals = bcx.fcx.lllocals.borrow();
-    pat_util::pat_bindings(&local.pat, |_, node_id, span, var_name| {
-        let datum = match locals.get(&node_id) {
-            Some(datum) => datum,
-            None => {
-                span_bug!(span,
-                          "no entry in lllocals table for {}",
-                          node_id);
-            }
-        };
-
-        if unsafe { llvm::LLVMIsAAllocaInst(datum.val) } == ptr::null_mut() {
-            span_bug!(span, "debuginfo::create_local_var_metadata() - \
-                             Referenced variable location is not an alloca!");
-        }
-
-        let scope_metadata = scope_metadata(bcx.fcx, node_id, span);
-
-        declare_local(bcx,
-                      var_name.node,
-                      datum.ty,
-                      scope_metadata,
-                      VariableAccess::DirectVariable { alloca: datum.val },
-                      VariableKind::LocalVariable,
-                      span);
-    })
-}
-
-/// Creates debug information for a variable captured in a closure.
-///
-/// Adds the created metadata nodes directly to the crate's IR.
-pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                                node_id: ast::NodeId,
-                                                env_pointer: ValueRef,
-                                                env_index: usize,
-                                                captured_by_ref: bool,
-                                                span: Span) {
-    if bcx.unreachable.get() ||
-       fn_should_be_ignored(bcx.fcx) ||
-       bcx.sess().opts.debuginfo != FullDebugInfo {
-        return;
-    }
-
-    let cx = bcx.ccx();
-
-    let ast_item = cx.tcx().map.find(node_id);
-
-    let variable_name = match ast_item {
-        None => {
-            span_bug!(span, "debuginfo::create_captured_var_metadata: node not found");
-        }
-        Some(hir_map::NodeLocal(pat)) => {
-            match pat.node {
-                PatKind::Binding(_, ref path1, _) => {
-                    path1.node
-                }
-                _ => {
-                    span_bug!(span,
-                              "debuginfo::create_captured_var_metadata() - \
-                               Captured var-id refers to unexpected \
-                               hir_map variant: {:?}",
-                              ast_item);
-                }
-            }
-        }
-        _ => {
-            span_bug!(span,
-                      "debuginfo::create_captured_var_metadata() - \
-                       Captured var-id refers to unexpected \
-                       hir_map variant: {:?}",
-                      ast_item);
-        }
-    };
-
-    let variable_type = common::node_id_type(bcx, node_id);
-    let scope_metadata = bcx.fcx.debug_context.get_ref(span).fn_metadata;
-
-    // env_pointer is the alloca containing the pointer to the environment,
-    // so it's type is **EnvironmentType. In order to find out the type of
-    // the environment we have to "dereference" two times.
-    let llvm_env_data_type = common::val_ty(env_pointer).element_type()
-                                                        .element_type();
-    let byte_offset_of_var_in_env = machine::llelement_offset(cx,
-                                                              llvm_env_data_type,
-                                                              env_index);
-
-    let address_operations = unsafe {
-        [llvm::LLVMRustDIBuilderCreateOpDeref(),
-         llvm::LLVMRustDIBuilderCreateOpPlus(),
-         byte_offset_of_var_in_env as i64,
-         llvm::LLVMRustDIBuilderCreateOpDeref()]
-    };
-
-    let address_op_count = if captured_by_ref {
-        address_operations.len()
-    } else {
-        address_operations.len() - 1
-    };
-
-    let variable_access = VariableAccess::IndirectVariable {
-        alloca: env_pointer,
-        address_operations: &address_operations[..address_op_count]
-    };
-
-    declare_local(bcx,
-                  variable_name,
-                  variable_type,
-                  scope_metadata,
-                  variable_access,
-                  VariableKind::CapturedVariable,
-                  span);
-}
-
-/// Creates debug information for a local variable introduced in the head of a
-/// match-statement arm.
-///
-/// Adds the created metadata nodes directly to the crate's IR.
-pub fn create_match_binding_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                                 variable_name: ast::Name,
-                                                 binding: BindingInfo<'tcx>) {
-    if bcx.unreachable.get() ||
-       fn_should_be_ignored(bcx.fcx) ||
-       bcx.sess().opts.debuginfo != FullDebugInfo {
-        return;
-    }
-
-    let scope_metadata = scope_metadata(bcx.fcx, binding.id, binding.span);
-    let aops = unsafe {
-        [llvm::LLVMRustDIBuilderCreateOpDeref()]
-    };
-    // Regardless of the actual type (`T`) we're always passed the stack slot
-    // (alloca) for the binding. For ByRef bindings that's a `T*` but for ByMove
-    // bindings we actually have `T**`. So to get the actual variable we need to
-    // dereference once more. For ByCopy we just use the stack slot we created
-    // for the binding.
-    let var_access = match binding.trmode {
-        TransBindingMode::TrByCopy(llbinding) |
-        TransBindingMode::TrByMoveIntoCopy(llbinding) => VariableAccess::DirectVariable {
-            alloca: llbinding
-        },
-        TransBindingMode::TrByMoveRef => VariableAccess::IndirectVariable {
-            alloca: binding.llmatch,
-            address_operations: &aops
-        },
-        TransBindingMode::TrByRef => VariableAccess::DirectVariable {
-            alloca: binding.llmatch
-        }
-    };
-
-    declare_local(bcx,
-                  variable_name,
-                  binding.ty,
-                  scope_metadata,
-                  var_access,
-                  VariableKind::LocalVariable,
-                  binding.span);
-}
-
-/// Creates debug information for the given function argument.
-///
-/// This function assumes that there's a datum for each pattern component of the
-/// argument in `bcx.fcx.lllocals`.
-/// Adds the created metadata nodes directly to the crate's IR.
-pub fn create_argument_metadata(bcx: Block, arg: &hir::Arg) {
-    if bcx.unreachable.get() ||
-       fn_should_be_ignored(bcx.fcx) ||
-       bcx.sess().opts.debuginfo != FullDebugInfo {
-        return;
+// Creates an "extension" of an existing DIScope into another file.
+pub fn extend_scope_to_file(ccx: &CrateContext,
+                            scope_metadata: DIScope,
+                            file: &syntax_pos::FileMap)
+                            -> DILexicalBlock {
+    let file_metadata = file_metadata(ccx, &file.name, &file.abs_path);
+    unsafe {
+        llvm::LLVMRustDIBuilderCreateLexicalBlockFile(
+            DIB(ccx),
+            scope_metadata,
+            file_metadata)
     }
-
-    let scope_metadata = bcx
-                         .fcx
-                         .debug_context
-                         .get_ref(arg.pat.span)
-                         .fn_metadata;
-    let locals = bcx.fcx.lllocals.borrow();
-
-    pat_util::pat_bindings(&arg.pat, |_, node_id, span, var_name| {
-        let datum = match locals.get(&node_id) {
-            Some(v) => v,
-            None => {
-                span_bug!(span, "no entry in lllocals table for {}", node_id);
-            }
-        };
-
-        if unsafe { llvm::LLVMIsAAllocaInst(datum.val) } == ptr::null_mut() {
-            span_bug!(span, "debuginfo::create_argument_metadata() - \
-                             Referenced variable location is not an alloca!");
-        }
-
-        let argument_index = {
-            let counter = &bcx
-                          .fcx
-                          .debug_context
-                          .get_ref(span)
-                          .argument_counter;
-            let argument_index = counter.get();
-            counter.set(argument_index + 1);
-            argument_index
-        };
-
-        declare_local(bcx,
-                      var_name.node,
-                      datum.ty,
-                      scope_metadata,
-                      VariableAccess::DirectVariable { alloca: datum.val },
-                      VariableKind::ArgumentVariable(argument_index),
-                      span);
-    })
-}
+}
\ No newline at end of file
index 1ee000992b9c59cba899c758850ca1c5e47d1126..a3a7a79fb58be4d5ce42f4f0c601b8cc539ec203 100644 (file)
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::DefPathData;
 use rustc::ty::subst::Substs;
-use rustc::hir;
 
 use abi::Abi;
-use common::{NodeIdAndSpan, CrateContext, FunctionContext, Block, BlockAndBuilder};
-use inline;
+use common::{CrateContext, FunctionContext, Block, BlockAndBuilder};
 use monomorphize::{self, Instance};
 use rustc::ty::{self, Ty};
+use rustc::mir::repr as mir;
 use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
-use util::nodemap::{DefIdMap, NodeMap, FnvHashMap, FnvHashSet};
+use util::nodemap::{DefIdMap, FnvHashMap, FnvHashSet};
 
 use libc::c_uint;
 use std::cell::{Cell, RefCell};
 mod create_scope_map;
 mod source_loc;
 
-pub use self::create_scope_map::create_mir_scopes;
+pub use self::create_scope_map::{create_mir_scopes, MirDebugScope};
 pub use self::source_loc::start_emitting_source_locations;
-pub use self::source_loc::get_cleanup_debug_loc_for_ast_node;
-pub use self::source_loc::with_source_location_override;
-pub use self::metadata::create_match_binding_metadata;
-pub use self::metadata::create_argument_metadata;
-pub use self::metadata::create_captured_var_metadata;
 pub use self::metadata::create_global_var_metadata;
-pub use self::metadata::create_local_var_metadata;
+pub use self::metadata::extend_scope_to_file;
 
 #[allow(non_upper_case_globals)]
 const DW_TAG_auto_variable: c_uint = 0x100;
@@ -140,9 +134,7 @@ fn should_be_ignored_message() -> &'static str {
 }
 
 pub struct FunctionDebugContextData {
-    scope_map: RefCell<NodeMap<DIScope>>,
     fn_metadata: DISubprogram,
-    argument_counter: Cell<usize>,
     source_locations_enabled: Cell<bool>,
     source_location_override: Cell<bool>,
 }
@@ -229,7 +221,8 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                                instance: Instance<'tcx>,
                                                sig: &ty::FnSig<'tcx>,
                                                abi: Abi,
-                                               llfn: ValueRef) -> FunctionDebugContext {
+                                               llfn: ValueRef,
+                                               mir: &mir::Mir) -> FunctionDebugContext {
     if cx.sess().opts.debuginfo == NoDebugInfo {
         return FunctionDebugContext::DebugInfoDisabled;
     }
@@ -238,8 +231,8 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     // Do this here already, in case we do an early exit from this function.
     source_loc::set_debug_location(cx, None, UnknownLocation);
 
-    let instance = inline::maybe_inline_instance(cx, instance);
-    let (containing_scope, span) = get_containing_scope_and_span(cx, instance);
+    let containing_scope = get_containing_scope(cx, instance);
+    let span = mir.span;
 
     // This can be the case for functions inlined from another crate
     if span == syntax_pos::DUMMY_SP {
@@ -305,9 +298,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
     // Initialize fn debug context (including scope map and namespace map)
     let fn_debug_context = box FunctionDebugContextData {
-        scope_map: RefCell::new(NodeMap()),
         fn_metadata: fn_metadata,
-        argument_counter: Cell::new(1),
         source_locations_enabled: Cell::new(false),
         source_location_override: Cell::new(false),
     };
@@ -353,37 +344,35 @@ fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
     fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                          generics: &ty::Generics<'tcx>,
-                                         param_substs: &Substs<'tcx>,
+                                         substs: &Substs<'tcx>,
                                          file_metadata: DIFile,
                                          name_to_append_suffix_to: &mut String)
                                          -> DIArray
     {
-        let actual_types = &param_substs.types;
-
-        if actual_types.is_empty() {
+        if substs.types().next().is_none() {
             return create_DIArray(DIB(cx), &[]);
         }
 
         name_to_append_suffix_to.push('<');
-        for (i, &actual_type) in actual_types.iter().enumerate() {
+        for (i, actual_type) in substs.types().enumerate() {
+            if i != 0 {
+                name_to_append_suffix_to.push_str(",");
+            }
+
             let actual_type = cx.tcx().normalize_associated_type(&actual_type);
             // Add actual type name to <...> clause of function name
             let actual_type_name = compute_debuginfo_type_name(cx,
                                                                actual_type,
                                                                true);
             name_to_append_suffix_to.push_str(&actual_type_name[..]);
-
-            if i != actual_types.len() - 1 {
-                name_to_append_suffix_to.push_str(",");
-            }
         }
         name_to_append_suffix_to.push('>');
 
         // Again, only create type information if full debuginfo is enabled
         let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo {
             let names = get_type_parameter_names(cx, generics);
-            actual_types.iter().zip(names).map(|(ty, name)| {
-                let actual_type = cx.tcx().normalize_associated_type(ty);
+            substs.types().zip(names).map(|(ty, name)| {
+                let actual_type = cx.tcx().normalize_associated_type(&ty);
                 let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
                 let name = CString::new(name.as_str().as_bytes()).unwrap();
                 unsafe {
@@ -414,9 +403,9 @@ fn get_type_parameter_names<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         names
     }
 
-    fn get_containing_scope_and_span<'ccx, 'tcx>(cx: &CrateContext<'ccx, 'tcx>,
-                                                 instance: Instance<'tcx>)
-                                                 -> (DIScope, Span) {
+    fn get_containing_scope<'ccx, 'tcx>(cx: &CrateContext<'ccx, 'tcx>,
+                                        instance: Instance<'tcx>)
+                                        -> DIScope {
         // First, let's see if this is a method within an inherent impl. Because
         // if yes, we want to make the result subroutine DIE a child of the
         // subroutine's self-type.
@@ -425,10 +414,18 @@ fn get_containing_scope_and_span<'ccx, 'tcx>(cx: &CrateContext<'ccx, 'tcx>,
             if cx.tcx().trait_id_of_impl(impl_def_id).is_none() {
                 let impl_self_ty = cx.tcx().lookup_item_type(impl_def_id).ty;
                 let impl_self_ty = cx.tcx().erase_regions(&impl_self_ty);
-                let impl_self_ty = monomorphize::apply_param_substs(cx.tcx(),
+                let impl_self_ty = monomorphize::apply_param_substs(cx.shared(),
                                                                     instance.substs,
                                                                     &impl_self_ty);
-                Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP))
+
+                // Only "class" methods are generally understood by LLVM,
+                // so avoid methods on other types (e.g. `<*mut T>::null`).
+                match impl_self_ty.sty {
+                    ty::TyStruct(..) | ty::TyEnum(..) => {
+                        Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP))
+                    }
+                    _ => None
+                }
             } else {
                 // For trait method impls we still use the "parallel namespace"
                 // strategy
@@ -436,41 +433,15 @@ fn get_containing_scope_and_span<'ccx, 'tcx>(cx: &CrateContext<'ccx, 'tcx>,
             }
         });
 
-        let containing_scope = self_type.unwrap_or_else(|| {
+        self_type.unwrap_or_else(|| {
             namespace::item_namespace(cx, DefId {
                 krate: instance.def.krate,
                 index: cx.tcx()
                          .def_key(instance.def)
                          .parent
-                         .expect("get_containing_scope_and_span: missing parent?")
+                         .expect("get_containing_scope: missing parent?")
             })
-        });
-
-        // Try to get some span information, if we have an inlined item.
-        let definition_span = cx.tcx()
-                                .map
-                                .def_id_span(instance.def, syntax_pos::DUMMY_SP);
-
-        (containing_scope, definition_span)
-    }
-}
-
-/// Computes the scope map for a function given its declaration and body.
-pub fn fill_scope_map_for_function<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
-                                             fn_decl: &hir::FnDecl,
-                                             top_level_block: &hir::Block,
-                                             fn_ast_id: ast::NodeId) {
-    match fcx.debug_context {
-        FunctionDebugContext::RegularContext(box ref data) => {
-            let scope_map = create_scope_map::create_scope_map(fcx.ccx,
-                                                               &fn_decl.inputs,
-                                                               top_level_block,
-                                                               data.fn_metadata,
-                                                               fn_ast_id);
-            *data.scope_map.borrow_mut() = scope_map;
-        }
-        FunctionDebugContext::DebugInfoDisabled |
-        FunctionDebugContext::FunctionWithoutDebugInfo => {}
+        })
     }
 }
 
@@ -548,7 +519,6 @@ pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum DebugLoc {
-    At(ast::NodeId, Span),
     ScopeAt(DIScope, Span),
     None
 }
@@ -562,28 +532,3 @@ pub fn apply_to_bcx(self, bcx: &BlockAndBuilder) {
         source_loc::set_source_location(bcx.fcx(), Some(bcx), self);
     }
 }
-
-pub trait ToDebugLoc {
-    fn debug_loc(&self) -> DebugLoc;
-}
-
-impl ToDebugLoc for hir::Expr {
-    fn debug_loc(&self) -> DebugLoc {
-        DebugLoc::At(self.id, self.span)
-    }
-}
-
-impl ToDebugLoc for NodeIdAndSpan {
-    fn debug_loc(&self) -> DebugLoc {
-        DebugLoc::At(self.id, self.span)
-    }
-}
-
-impl ToDebugLoc for Option<NodeIdAndSpan> {
-    fn debug_loc(&self) -> DebugLoc {
-        match *self {
-            Some(NodeIdAndSpan { id, span }) => DebugLoc::At(id, span),
-            None => DebugLoc::None
-        }
-    }
-}
index d288b9dcef70bb379c2c89a6fecbd99da6d485f1..1aee27c144a36f9c0a9c8ed1ccc4f1f8ee3cf7a5 100644 (file)
 use self::InternalDebugLocation::*;
 
 use super::utils::{debug_context, span_start};
-use super::metadata::{scope_metadata,UNKNOWN_COLUMN_NUMBER};
+use super::metadata::{UNKNOWN_COLUMN_NUMBER};
 use super::{FunctionDebugContext, DebugLoc};
 
 use llvm;
 use llvm::debuginfo::DIScope;
 use builder::Builder;
-use common::{NodeIdAndSpan, CrateContext, FunctionContext};
+use common::{CrateContext, FunctionContext};
 
 use libc::c_uint;
 use std::ptr;
-use syntax_pos::{self, Span, Pos};
-use syntax::ast;
-
-pub fn get_cleanup_debug_loc_for_ast_node<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                                                    node_id: ast::NodeId,
-                                                    node_span: Span,
-                                                    is_block: bool)
-                                                 -> NodeIdAndSpan {
-    // A debug location needs two things:
-    // (1) A span (of which only the beginning will actually be used)
-    // (2) An AST node-id which will be used to look up the lexical scope
-    //     for the location in the functions scope-map
-    //
-    // This function will calculate the debug location for compiler-generated
-    // cleanup calls that are executed when control-flow leaves the
-    // scope identified by `node_id`.
-    //
-    // For everything but block-like things we can simply take id and span of
-    // the given expression, meaning that from a debugger's view cleanup code is
-    // executed at the same source location as the statement/expr itself.
-    //
-    // Blocks are a special case. Here we want the cleanup to be linked to the
-    // closing curly brace of the block. The *scope* the cleanup is executed in
-    // is up to debate: It could either still be *within* the block being
-    // cleaned up, meaning that locals from the block are still visible in the
-    // debugger.
-    // Or it could be in the scope that the block is contained in, so any locals
-    // from within the block are already considered out-of-scope and thus not
-    // accessible in the debugger anymore.
-    //
-    // The current implementation opts for the second option: cleanup of a block
-    // already happens in the parent scope of the block. The main reason for
-    // this decision is that scoping becomes controlflow dependent when variable
-    // shadowing is involved and it's impossible to decide statically which
-    // scope is actually left when the cleanup code is executed.
-    // In practice it shouldn't make much of a difference.
-
-    let mut cleanup_span = node_span;
-
-    if is_block {
-        // Not all blocks actually have curly braces (e.g. simple closure
-        // bodies), in which case we also just want to return the span of the
-        // whole expression.
-        let code_snippet = cx.sess().codemap().span_to_snippet(node_span);
-        if let Ok(code_snippet) = code_snippet {
-            let bytes = code_snippet.as_bytes();
-
-            if !bytes.is_empty() && &bytes[bytes.len()-1..] == b"}" {
-                cleanup_span = Span {
-                    lo: node_span.hi - syntax_pos::BytePos(1),
-                    hi: node_span.hi,
-                    expn_id: node_span.expn_id
-                };
-            }
-        }
-    }
-
-    NodeIdAndSpan {
-        id: node_id,
-        span: cleanup_span
-    }
-}
-
+use syntax_pos::Pos;
 
 /// Sets the current debug location at the beginning of the span.
 ///
@@ -109,9 +47,6 @@ pub fn set_source_location(fcx: &FunctionContext,
 
     let dbg_loc = if function_debug_context.source_locations_enabled.get() {
         let (scope, span) = match debug_loc {
-            DebugLoc::At(node_id, span) => {
-                (scope_metadata(fcx, node_id, span), span)
-            }
             DebugLoc::ScopeAt(scope, span) => (scope, span),
             DebugLoc::None => {
                 set_debug_location(fcx.ccx, builder, UnknownLocation);
@@ -129,35 +64,6 @@ pub fn set_source_location(fcx: &FunctionContext,
     set_debug_location(fcx.ccx, builder, dbg_loc);
 }
 
-/// This function makes sure that all debug locations emitted while executing
-/// `wrapped_function` are set to the given `debug_loc`.
-pub fn with_source_location_override<F, R>(fcx: &FunctionContext,
-                                           debug_loc: DebugLoc,
-                                           wrapped_function: F) -> R
-    where F: FnOnce() -> R
-{
-    match fcx.debug_context {
-        FunctionDebugContext::DebugInfoDisabled => {
-            wrapped_function()
-        }
-        FunctionDebugContext::FunctionWithoutDebugInfo => {
-            set_debug_location(fcx.ccx, None, UnknownLocation);
-            wrapped_function()
-        }
-        FunctionDebugContext::RegularContext(box ref function_debug_context) => {
-            if function_debug_context.source_location_override.get() {
-                wrapped_function()
-            } else {
-                debug_loc.apply(fcx);
-                function_debug_context.source_location_override.set(true);
-                let result = wrapped_function();
-                function_debug_context.source_location_override.set(false);
-                result
-            }
-        }
-    }
-}
-
 /// Enables emitting source locations for the given functions.
 ///
 /// Since we don't want source locations to be emitted for the function prelude,
index 2a996ca75a37e78597be98fafdf760ca2f0d291b..f757578e6954def808863c0a174668972d89c17b 100644 (file)
@@ -175,13 +175,13 @@ fn push_item_name(cx: &CrateContext,
     fn push_type_params<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                   substs: &Substs<'tcx>,
                                   output: &mut String) {
-        if substs.types.is_empty() {
+        if substs.types().next().is_none() {
             return;
         }
 
         output.push('<');
 
-        for &type_parameter in &substs.types {
+        for type_parameter in substs.types() {
             push_debuginfo_type_name(cx, type_parameter, true, output);
             output.push_str(", ");
         }
index 5734a12394113fe86a2c825652c0aa11540f1a9c..3cdac485fecc990dc32f8b3d8c0227ea94787e51 100644 (file)
@@ -10,7 +10,7 @@
 
 // Utility Functions.
 
-use super::{FunctionDebugContext, CrateDebugContext};
+use super::{CrateDebugContext};
 use super::namespace::item_namespace;
 
 use rustc::hir::def_id::DefId;
@@ -18,7 +18,7 @@
 use llvm;
 use llvm::debuginfo::{DIScope, DIBuilderRef, DIDescriptor, DIArray};
 use machine;
-use common::{CrateContext, FunctionContext};
+use common::{CrateContext};
 use type_::Type;
 
 use syntax_pos::{self, Span};
@@ -70,13 +70,6 @@ pub fn DIB(cx: &CrateContext) -> DIBuilderRef {
     cx.dbg_cx().as_ref().unwrap().builder
 }
 
-pub fn fn_should_be_ignored(fcx: &FunctionContext) -> bool {
-    match fcx.debug_context {
-        FunctionDebugContext::RegularContext(_) => false,
-        _ => true
-    }
-}
-
 pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: DefId)
                                    -> (DIScope, Span) {
     let containing_scope = item_namespace(cx, DefId {
index f7f065a3562ed2bb8223a1741af97490884abd47..18d31448b1a24129920f24b1a2944efcebcf9fe3 100644 (file)
     fn simd_add<T>(a: T, b: T) -> T;
 }
 
-unsafe { simd_add(0, 1); }
-// error: invalid monomorphization of `simd_add` intrinsic
+fn main() {
+    unsafe { simd_add(0, 1); }
+    // error: invalid monomorphization of `simd_add` intrinsic
+}
 ```
 
 The generic type has to be a SIMD type. Example:
diff --git a/src/librustc_trans/expr.rs b/src/librustc_trans/expr.rs
deleted file mode 100644 (file)
index beb589c..0000000
+++ /dev/null
@@ -1,2473 +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.
-
-//! # Translation of Expressions
-//!
-//! The expr module handles translation of expressions. The most general
-//! translation routine is `trans()`, which will translate an expression
-//! into a datum. `trans_into()` is also available, which will translate
-//! an expression and write the result directly into memory, sometimes
-//! avoiding the need for a temporary stack slot. Finally,
-//! `trans_to_lvalue()` is available if you'd like to ensure that the
-//! result has cleanup scheduled.
-//!
-//! Internally, each of these functions dispatches to various other
-//! expression functions depending on the kind of expression. We divide
-//! up expressions into:
-//!
-//! - **Datum expressions:** Those that most naturally yield values.
-//!   Examples would be `22`, `box x`, or `a + b` (when not overloaded).
-//! - **DPS expressions:** Those that most naturally write into a location
-//!   in memory. Examples would be `foo()` or `Point { x: 3, y: 4 }`.
-//! - **Statement expressions:** That that do not generate a meaningful
-//!   result. Examples would be `while { ... }` or `return 44`.
-//!
-//! Public entry points:
-//!
-//! - `trans_into(bcx, expr, dest) -> bcx`: evaluates an expression,
-//!   storing the result into `dest`. This is the preferred form, if you
-//!   can manage it.
-//!
-//! - `trans(bcx, expr) -> DatumBlock`: evaluates an expression, yielding
-//!   `Datum` with the result. You can then store the datum, inspect
-//!   the value, etc. This may introduce temporaries if the datum is a
-//!   structural type.
-//!
-//! - `trans_to_lvalue(bcx, expr, "...") -> DatumBlock`: evaluates an
-//!   expression and ensures that the result has a cleanup associated with it,
-//!   creating a temporary stack slot if necessary.
-//!
-//! - `trans_var -> Datum`: looks up a local variable, upvar or static.
-
-#![allow(non_camel_case_types)]
-
-pub use self::Dest::*;
-use self::lazy_binop_ty::*;
-
-use llvm::{self, ValueRef, TypeKind};
-use middle::const_qualif::ConstQualif;
-use rustc::hir::def::Def;
-use rustc::ty::subst::Substs;
-use {_match, abi, adt, asm, base, closure, consts, controlflow};
-use base::*;
-use build::*;
-use callee::{Callee, ArgExprs, ArgOverloadedCall, ArgOverloadedOp};
-use cleanup::{self, CleanupMethods, DropHintMethods};
-use common::*;
-use datum::*;
-use debuginfo::{self, DebugLoc, ToDebugLoc};
-use glue;
-use machine;
-use tvec;
-use type_of;
-use value::Value;
-use Disr;
-use rustc::ty::adjustment::{AdjustNeverToAny, AdjustDerefRef, AdjustReifyFnPointer};
-use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
-use rustc::ty::adjustment::CustomCoerceUnsized;
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::MethodCall;
-use rustc::ty::cast::{CastKind, CastTy};
-use util::common::indenter;
-use machine::{llsize_of, llsize_of_alloc};
-use type_::Type;
-
-use rustc::hir;
-
-use syntax::ast;
-use syntax::parse::token::InternedString;
-use syntax_pos;
-use std::fmt;
-use std::mem;
-
-// Destinations
-
-// These are passed around by the code generating functions to track the
-// destination of a computation's value.
-
-#[derive(Copy, Clone, PartialEq)]
-pub enum Dest {
-    SaveIn(ValueRef),
-    Ignore,
-}
-
-impl fmt::Debug for Dest {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            SaveIn(v) => write!(f, "SaveIn({:?})", Value(v)),
-            Ignore => f.write_str("Ignore")
-        }
-    }
-}
-
-/// This function is equivalent to `trans(bcx, expr).store_to_dest(dest)` but it may generate
-/// better optimized LLVM code.
-pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                              expr: &hir::Expr,
-                              dest: Dest)
-                              -> Block<'blk, 'tcx> {
-    let mut bcx = bcx;
-
-    expr.debug_loc().apply(bcx.fcx);
-
-    if adjustment_required(bcx, expr) {
-        // use trans, which may be less efficient but
-        // which will perform the adjustments:
-        let datum = unpack_datum!(bcx, trans(bcx, expr));
-        return datum.store_to_dest(bcx, dest, expr.id);
-    }
-
-    let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
-    if !qualif.intersects(ConstQualif::NOT_CONST | ConstQualif::NEEDS_DROP) {
-        if !qualif.intersects(ConstQualif::PREFER_IN_PLACE) {
-            if let SaveIn(lldest) = dest {
-                match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
-                                                       bcx.fcx.param_substs,
-                                                       consts::TrueConst::No) {
-                    Ok(global) => {
-                        // Cast pointer to destination, because constants
-                        // have different types.
-                        let lldest = PointerCast(bcx, lldest, val_ty(global));
-                        memcpy_ty(bcx, lldest, global, expr_ty_adjusted(bcx, expr));
-                        return bcx;
-                    },
-                    Err(consts::ConstEvalFailure::Runtime(_)) => {
-                        // in case const evaluation errors, translate normally
-                        // debug assertions catch the same errors
-                        // see RFC 1229
-                    },
-                    Err(consts::ConstEvalFailure::Compiletime(_)) => {
-                        return bcx;
-                    },
-                }
-            }
-
-            // If we see a const here, that's because it evaluates to a type with zero size. We
-            // should be able to just discard it, since const expressions are guaranteed not to
-            // have side effects. This seems to be reached through tuple struct constructors being
-            // passed zero-size constants.
-            if let hir::ExprPath(..) = expr.node {
-                match bcx.tcx().expect_def(expr.id) {
-                    Def::Const(_) | Def::AssociatedConst(_) => {
-                        assert!(type_is_zero_size(bcx.ccx(), bcx.tcx().node_id_to_type(expr.id)));
-                        return bcx;
-                    }
-                    _ => {}
-                }
-            }
-
-            // Even if we don't have a value to emit, and the expression
-            // doesn't have any side-effects, we still have to translate the
-            // body of any closures.
-            // FIXME: Find a better way of handling this case.
-        } else {
-            // The only way we're going to see a `const` at this point is if
-            // it prefers in-place instantiation, likely because it contains
-            // `[x; N]` somewhere within.
-            match expr.node {
-                hir::ExprPath(..) => {
-                    match bcx.tcx().expect_def(expr.id) {
-                        Def::Const(did) | Def::AssociatedConst(did) => {
-                            let empty_substs = Substs::empty(bcx.tcx());
-                            let const_expr = consts::get_const_expr(bcx.ccx(), did, expr,
-                                                                    empty_substs);
-                            // Temporarily get cleanup scopes out of the way,
-                            // as they require sub-expressions to be contained
-                            // inside the current AST scope.
-                            // These should record no cleanups anyways, `const`
-                            // can't have destructors.
-                            let scopes = mem::replace(&mut *bcx.fcx.scopes.borrow_mut(),
-                                                      vec![]);
-                            // Lock emitted debug locations to the location of
-                            // the constant reference expression.
-                            debuginfo::with_source_location_override(bcx.fcx,
-                                                                     expr.debug_loc(),
-                                                                     || {
-                                bcx = trans_into(bcx, const_expr, dest)
-                            });
-                            let scopes = mem::replace(&mut *bcx.fcx.scopes.borrow_mut(),
-                                                      scopes);
-                            assert!(scopes.is_empty());
-                            return bcx;
-                        }
-                        _ => {}
-                    }
-                }
-                _ => {}
-            }
-        }
-    }
-
-    debug!("trans_into() expr={:?}", expr);
-
-    let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(),
-                                                                          expr.id,
-                                                                          expr.span,
-                                                                          false);
-    bcx.fcx.push_ast_cleanup_scope(cleanup_debug_loc);
-
-    let kind = expr_kind(bcx.tcx(), expr);
-    bcx = match kind {
-        ExprKind::Lvalue | ExprKind::RvalueDatum => {
-            trans_unadjusted(bcx, expr).store_to_dest(dest, expr.id)
-        }
-        ExprKind::RvalueDps => {
-            trans_rvalue_dps_unadjusted(bcx, expr, dest)
-        }
-        ExprKind::RvalueStmt => {
-            trans_rvalue_stmt_unadjusted(bcx, expr)
-        }
-    };
-
-    bcx.fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id)
-}
-
-/// Translates an expression, returning a datum (and new block) encapsulating the result. When
-/// possible, it is preferred to use `trans_into`, as that may avoid creating a temporary on the
-/// stack.
-pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                         expr: &hir::Expr)
-                         -> DatumBlock<'blk, 'tcx, Expr> {
-    debug!("trans(expr={:?})", expr);
-
-    let mut bcx = bcx;
-    let fcx = bcx.fcx;
-    let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
-    let adjusted_global = !qualif.intersects(ConstQualif::NON_STATIC_BORROWS);
-    let global = if !qualif.intersects(ConstQualif::NOT_CONST | ConstQualif::NEEDS_DROP) {
-        match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
-                                                            bcx.fcx.param_substs,
-                                                            consts::TrueConst::No) {
-            Ok(global) => {
-                if qualif.intersects(ConstQualif::HAS_STATIC_BORROWS) {
-                    // Is borrowed as 'static, must return lvalue.
-
-                    // Cast pointer to global, because constants have different types.
-                    let const_ty = expr_ty_adjusted(bcx, expr);
-                    let llty = type_of::type_of(bcx.ccx(), const_ty);
-                    let global = PointerCast(bcx, global, llty.ptr_to());
-                    let datum = Datum::new(global, const_ty, Lvalue::new("expr::trans"));
-                    return DatumBlock::new(bcx, datum.to_expr_datum());
-                }
-
-                // Otherwise, keep around and perform adjustments, if needed.
-                let const_ty = if adjusted_global {
-                    expr_ty_adjusted(bcx, expr)
-                } else {
-                    expr_ty(bcx, expr)
-                };
-
-                // This could use a better heuristic.
-                Some(if type_is_immediate(bcx.ccx(), const_ty) {
-                    // Cast pointer to global, because constants have different types.
-                    let llty = type_of::type_of(bcx.ccx(), const_ty);
-                    let global = PointerCast(bcx, global, llty.ptr_to());
-                    // Maybe just get the value directly, instead of loading it?
-                    immediate_rvalue(load_ty(bcx, global, const_ty), const_ty)
-                } else {
-                    let scratch = alloc_ty(bcx, const_ty, "const");
-                    call_lifetime_start(bcx, scratch);
-                    let lldest = if !const_ty.is_structural() {
-                        // Cast pointer to slot, because constants have different types.
-                        PointerCast(bcx, scratch, val_ty(global))
-                    } else {
-                        // In this case, memcpy_ty calls llvm.memcpy after casting both
-                        // source and destination to i8*, so we don't need any casts.
-                        scratch
-                    };
-                    memcpy_ty(bcx, lldest, global, const_ty);
-                    Datum::new(scratch, const_ty, Rvalue::new(ByRef))
-                })
-            },
-            Err(consts::ConstEvalFailure::Runtime(_)) => {
-                // in case const evaluation errors, translate normally
-                // debug assertions catch the same errors
-                // see RFC 1229
-                None
-            },
-            Err(consts::ConstEvalFailure::Compiletime(_)) => {
-                // generate a dummy llvm value
-                let const_ty = expr_ty(bcx, expr);
-                let llty = type_of::type_of(bcx.ccx(), const_ty);
-                let dummy = C_undef(llty.ptr_to());
-                Some(Datum::new(dummy, const_ty, Rvalue::new(ByRef)))
-            },
-        }
-    } else {
-        None
-    };
-
-    let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(),
-                                                                          expr.id,
-                                                                          expr.span,
-                                                                          false);
-    fcx.push_ast_cleanup_scope(cleanup_debug_loc);
-    let datum = match global {
-        Some(rvalue) => rvalue.to_expr_datum(),
-        None => unpack_datum!(bcx, trans_unadjusted(bcx, expr))
-    };
-    let datum = if adjusted_global {
-        datum // trans::consts already performed adjustments.
-    } else {
-        unpack_datum!(bcx, apply_adjustments(bcx, expr, datum))
-    };
-    bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id);
-    return DatumBlock::new(bcx, datum);
-}
-
-pub fn get_meta(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
-    StructGEP(bcx, fat_ptr, abi::FAT_PTR_EXTRA)
-}
-
-pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
-    StructGEP(bcx, fat_ptr, abi::FAT_PTR_ADDR)
-}
-
-pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) {
-    Store(bcx, Load(bcx, get_dataptr(bcx, src_ptr)), get_dataptr(bcx, dst_ptr));
-    Store(bcx, Load(bcx, get_meta(bcx, src_ptr)), get_meta(bcx, dst_ptr));
-}
-
-fn adjustment_required<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                   expr: &hir::Expr) -> bool {
-    let adjustment = match bcx.tcx().tables.borrow().adjustments.get(&expr.id).cloned() {
-        None => { return false; }
-        Some(adj) => adj
-    };
-
-    // Don't skip a conversion from Box<T> to &T, etc.
-    if bcx.tcx().is_overloaded_autoderef(expr.id, 0) {
-        return true;
-    }
-
-    match adjustment {
-        AdjustNeverToAny(..) => true,
-        AdjustReifyFnPointer => true,
-        AdjustUnsafeFnPointer | AdjustMutToConstPointer => {
-            // purely a type-level thing
-            false
-        }
-        AdjustDerefRef(ref adj) => {
-            // We are a bit paranoid about adjustments and thus might have a re-
-            // borrow here which merely derefs and then refs again (it might have
-            // a different region or mutability, but we don't care here).
-            !(adj.autoderefs == 1 && adj.autoref.is_some() && adj.unsize.is_none())
-        }
-    }
-}
-
-/// Helper for trans that apply adjustments from `expr` to `datum`, which should be the unadjusted
-/// translation of `expr`.
-fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                 expr: &hir::Expr,
-                                 datum: Datum<'tcx, Expr>)
-                                 -> DatumBlock<'blk, 'tcx, Expr>
-{
-    let mut bcx = bcx;
-    let mut datum = datum;
-    let adjustment = match bcx.tcx().tables.borrow().adjustments.get(&expr.id).cloned() {
-        None => {
-            return DatumBlock::new(bcx, datum);
-        }
-        Some(adj) => { adj }
-    };
-    debug!("unadjusted datum for expr {:?}: {:?} adjustment={:?}",
-           expr, datum, adjustment);
-    match adjustment {
-        AdjustNeverToAny(ref target) => {
-            let mono_target = bcx.monomorphize(target);
-            let llty = type_of::type_of(bcx.ccx(), mono_target);
-            let dummy = C_undef(llty.ptr_to());
-            datum = Datum::new(dummy, mono_target, Lvalue::new("never")).to_expr_datum();
-        }
-        AdjustReifyFnPointer => {
-            match datum.ty.sty {
-                ty::TyFnDef(def_id, substs, _) => {
-                    datum = Callee::def(bcx.ccx(), def_id, substs)
-                        .reify(bcx.ccx()).to_expr_datum();
-                }
-                _ => {
-                    bug!("{} cannot be reified to a fn ptr", datum.ty)
-                }
-            }
-        }
-        AdjustUnsafeFnPointer | AdjustMutToConstPointer => {
-            // purely a type-level thing
-        }
-        AdjustDerefRef(ref adj) => {
-            let skip_reborrows = if adj.autoderefs == 1 && adj.autoref.is_some() {
-                // We are a bit paranoid about adjustments and thus might have a re-
-                // borrow here which merely derefs and then refs again (it might have
-                // a different region or mutability, but we don't care here).
-                match datum.ty.sty {
-                    // Don't skip a conversion from Box<T> to &T, etc.
-                    ty::TyRef(..) => {
-                        if bcx.tcx().is_overloaded_autoderef(expr.id, 0) {
-                            // Don't skip an overloaded deref.
-                            0
-                        } else {
-                            1
-                        }
-                    }
-                    _ => 0
-                }
-            } else {
-                0
-            };
-
-            if adj.autoderefs > skip_reborrows {
-                // Schedule cleanup.
-                let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "auto_deref", expr.id));
-                datum = unpack_datum!(bcx, deref_multiple(bcx, expr,
-                                                          lval.to_expr_datum(),
-                                                          adj.autoderefs - skip_reborrows));
-            }
-
-            // (You might think there is a more elegant way to do this than a
-            // skip_reborrows bool, but then you remember that the borrow checker exists).
-            if skip_reborrows == 0 && adj.autoref.is_some() {
-                datum = unpack_datum!(bcx, auto_ref(bcx, datum, expr));
-            }
-
-            if let Some(target) = adj.unsize {
-                // We do not arrange cleanup ourselves; if we already are an
-                // L-value, then cleanup will have already been scheduled (and
-                // the `datum.to_rvalue_datum` call below will emit code to zero
-                // the drop flag when moving out of the L-value). If we are an
-                // R-value, then we do not need to schedule cleanup.
-                let source_datum = unpack_datum!(bcx,
-                    datum.to_rvalue_datum(bcx, "__coerce_source"));
-
-                let target = bcx.monomorphize(&target);
-
-                let scratch = alloc_ty(bcx, target, "__coerce_target");
-                call_lifetime_start(bcx, scratch);
-                let target_datum = Datum::new(scratch, target,
-                                              Rvalue::new(ByRef));
-                bcx = coerce_unsized(bcx, expr.span, source_datum, target_datum);
-                datum = Datum::new(scratch, target,
-                                   RvalueExpr(Rvalue::new(ByRef)));
-            }
-        }
-    }
-    debug!("after adjustments, datum={:?}", datum);
-    DatumBlock::new(bcx, datum)
-}
-
-fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                              span: syntax_pos::Span,
-                              source: Datum<'tcx, Rvalue>,
-                              target: Datum<'tcx, Rvalue>)
-                              -> Block<'blk, 'tcx> {
-    let mut bcx = bcx;
-    debug!("coerce_unsized({:?} -> {:?})", source, target);
-
-    match (&source.ty.sty, &target.ty.sty) {
-        (&ty::TyBox(a), &ty::TyBox(b)) |
-        (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }),
-         &ty::TyRef(_, ty::TypeAndMut { ty: b, .. })) |
-        (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }),
-         &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) |
-        (&ty::TyRawPtr(ty::TypeAndMut { ty: a, .. }),
-         &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => {
-            let (inner_source, inner_target) = (a, b);
-
-            let (base, old_info) = if !type_is_sized(bcx.tcx(), inner_source) {
-                // Normally, the source is a thin pointer and we are
-                // adding extra info to make a fat pointer. The exception
-                // is when we are upcasting an existing object fat pointer
-                // to use a different vtable. In that case, we want to
-                // load out the original data pointer so we can repackage
-                // it.
-                (Load(bcx, get_dataptr(bcx, source.val)),
-                Some(Load(bcx, get_meta(bcx, source.val))))
-            } else {
-                let val = if source.kind.is_by_ref() {
-                    load_ty(bcx, source.val, source.ty)
-                } else {
-                    source.val
-                };
-                (val, None)
-            };
-
-            let info = unsized_info(bcx.ccx(), inner_source, inner_target, old_info);
-
-            // Compute the base pointer. This doesn't change the pointer value,
-            // but merely its type.
-            let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), inner_target).ptr_to();
-            let base = PointerCast(bcx, base, ptr_ty);
-
-            Store(bcx, base, get_dataptr(bcx, target.val));
-            Store(bcx, info, get_meta(bcx, target.val));
-        }
-
-        // This can be extended to enums and tuples in the future.
-        // (&ty::TyEnum(def_id_a, _), &ty::TyEnum(def_id_b, _)) |
-        (&ty::TyStruct(def_id_a, _), &ty::TyStruct(def_id_b, _)) => {
-            assert_eq!(def_id_a, def_id_b);
-
-            // The target is already by-ref because it's to be written to.
-            let source = unpack_datum!(bcx, source.to_ref_datum(bcx));
-            assert!(target.kind.is_by_ref());
-
-            let kind = custom_coerce_unsize_info(bcx.ccx().shared(),
-                                                 source.ty,
-                                                 target.ty);
-
-            let repr_source = adt::represent_type(bcx.ccx(), source.ty);
-            let src_fields = match &*repr_source {
-                &adt::Repr::Univariant(ref s, _) => &s.fields,
-                _ => span_bug!(span,
-                               "Non univariant struct? (repr_source: {:?})",
-                               repr_source),
-            };
-            let repr_target = adt::represent_type(bcx.ccx(), target.ty);
-            let target_fields = match &*repr_target {
-                &adt::Repr::Univariant(ref s, _) => &s.fields,
-                _ => span_bug!(span,
-                               "Non univariant struct? (repr_target: {:?})",
-                               repr_target),
-            };
-
-            let coerce_index = match kind {
-                CustomCoerceUnsized::Struct(i) => i
-            };
-            assert!(coerce_index < src_fields.len() && src_fields.len() == target_fields.len());
-
-            let source_val = adt::MaybeSizedValue::sized(source.val);
-            let target_val = adt::MaybeSizedValue::sized(target.val);
-
-            let iter = src_fields.iter().zip(target_fields).enumerate();
-            for (i, (src_ty, target_ty)) in iter {
-                let ll_source = adt::trans_field_ptr(bcx, &repr_source, source_val, Disr(0), i);
-                let ll_target = adt::trans_field_ptr(bcx, &repr_target, target_val, Disr(0), i);
-
-                // If this is the field we need to coerce, recurse on it.
-                if i == coerce_index {
-                    coerce_unsized(bcx, span,
-                                   Datum::new(ll_source, src_ty,
-                                              Rvalue::new(ByRef)),
-                                   Datum::new(ll_target, target_ty,
-                                              Rvalue::new(ByRef)));
-                } else {
-                    // Otherwise, simply copy the data from the source.
-                    assert!(src_ty.is_phantom_data() || src_ty == target_ty);
-                    memcpy_ty(bcx, ll_target, ll_source, src_ty);
-                }
-            }
-        }
-        _ => bug!("coerce_unsized: invalid coercion {:?} -> {:?}",
-                  source.ty,
-                  target.ty)
-    }
-    bcx
-}
-
-/// Translates an expression in "lvalue" mode -- meaning that it returns a reference to the memory
-/// that the expr represents.
-///
-/// If this expression is an rvalue, this implies introducing a temporary.  In other words,
-/// something like `x().f` is translated into roughly the equivalent of
-///
-///   { tmp = x(); tmp.f }
-pub fn trans_to_lvalue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                   expr: &hir::Expr,
-                                   name: &str)
-                                   -> DatumBlock<'blk, 'tcx, Lvalue> {
-    let mut bcx = bcx;
-    let datum = unpack_datum!(bcx, trans(bcx, expr));
-    return datum.to_lvalue_datum(bcx, name, expr.id);
-}
-
-/// A version of `trans` that ignores adjustments. You almost certainly do not want to call this
-/// directly.
-fn trans_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                expr: &hir::Expr)
-                                -> DatumBlock<'blk, 'tcx, Expr> {
-    let mut bcx = bcx;
-
-    debug!("trans_unadjusted(expr={:?})", expr);
-    let _indenter = indenter();
-
-    expr.debug_loc().apply(bcx.fcx);
-
-    return match expr_kind(bcx.tcx(), expr) {
-        ExprKind::Lvalue | ExprKind::RvalueDatum => {
-            let datum = unpack_datum!(bcx, {
-                trans_datum_unadjusted(bcx, expr)
-            });
-
-            DatumBlock {bcx: bcx, datum: datum}
-        }
-
-        ExprKind::RvalueStmt => {
-            bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
-            nil(bcx, expr_ty(bcx, expr))
-        }
-
-        ExprKind::RvalueDps => {
-            let ty = expr_ty(bcx, expr);
-            if type_is_zero_size(bcx.ccx(), ty) {
-                bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
-                nil(bcx, ty)
-            } else {
-                let scratch = rvalue_scratch_datum(bcx, ty, "");
-                bcx = trans_rvalue_dps_unadjusted(
-                    bcx, expr, SaveIn(scratch.val));
-
-                // Note: this is not obviously a good idea.  It causes
-                // immediate values to be loaded immediately after a
-                // return from a call or other similar expression,
-                // which in turn leads to alloca's having shorter
-                // lifetimes and hence larger stack frames.  However,
-                // in turn it can lead to more register pressure.
-                // Still, in practice it seems to increase
-                // performance, since we have fewer problems with
-                // morestack churn.
-                let scratch = unpack_datum!(
-                    bcx, scratch.to_appropriate_datum(bcx));
-
-                DatumBlock::new(bcx, scratch.to_expr_datum())
-            }
-        }
-    };
-
-    fn nil<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty: Ty<'tcx>)
-                       -> DatumBlock<'blk, 'tcx, Expr> {
-        let llval = C_undef(type_of::type_of(bcx.ccx(), ty));
-        let datum = immediate_rvalue(llval, ty);
-        DatumBlock::new(bcx, datum.to_expr_datum())
-    }
-}
-
-fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                      expr: &hir::Expr)
-                                      -> DatumBlock<'blk, 'tcx, Expr> {
-    let mut bcx = bcx;
-    let fcx = bcx.fcx;
-    let _icx = push_ctxt("trans_datum_unadjusted");
-
-    match expr.node {
-        hir::ExprType(ref e, _) => {
-            trans(bcx, &e)
-        }
-        hir::ExprPath(..) => {
-            let var = trans_var(bcx, bcx.tcx().expect_def(expr.id));
-            DatumBlock::new(bcx, var.to_expr_datum())
-        }
-        hir::ExprField(ref base, name) => {
-            trans_rec_field(bcx, &base, name.node)
-        }
-        hir::ExprTupField(ref base, idx) => {
-            trans_rec_tup_field(bcx, &base, idx.node)
-        }
-        hir::ExprIndex(ref base, ref idx) => {
-            trans_index(bcx, expr, &base, &idx, MethodCall::expr(expr.id))
-        }
-        hir::ExprBox(ref contents) => {
-            // Special case for `Box<T>`
-            let box_ty = expr_ty(bcx, expr);
-            let contents_ty = expr_ty(bcx, &contents);
-            match box_ty.sty {
-                ty::TyBox(..) => {
-                    trans_uniq_expr(bcx, expr, box_ty, &contents, contents_ty)
-                }
-                _ => span_bug!(expr.span,
-                               "expected unique box")
-            }
-
-        }
-        hir::ExprLit(ref lit) => trans_immediate_lit(bcx, expr, &lit),
-        hir::ExprBinary(op, ref lhs, ref rhs) => {
-            trans_binary(bcx, expr, op, &lhs, &rhs)
-        }
-        hir::ExprUnary(op, ref x) => {
-            trans_unary(bcx, expr, op, &x)
-        }
-        hir::ExprAddrOf(_, ref x) => {
-            match x.node {
-                hir::ExprRepeat(..) | hir::ExprVec(..) => {
-                    // Special case for slices.
-                    let cleanup_debug_loc =
-                        debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(),
-                                                                      x.id,
-                                                                      x.span,
-                                                                      false);
-                    fcx.push_ast_cleanup_scope(cleanup_debug_loc);
-                    let datum = unpack_datum!(
-                        bcx, tvec::trans_slice_vec(bcx, expr, &x));
-                    bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, x.id);
-                    DatumBlock::new(bcx, datum)
-                }
-                _ => {
-                    trans_addr_of(bcx, expr, &x)
-                }
-            }
-        }
-        hir::ExprCast(ref val, _) => {
-            // Datum output mode means this is a scalar cast:
-            trans_imm_cast(bcx, &val, expr.id)
-        }
-        _ => {
-            span_bug!(
-                expr.span,
-                "trans_rvalue_datum_unadjusted reached \
-                 fall-through case: {:?}",
-                expr.node);
-        }
-    }
-}
-
-fn trans_field<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
-                              base: &hir::Expr,
-                              get_idx: F)
-                              -> DatumBlock<'blk, 'tcx, Expr> where
-    F: FnOnce(TyCtxt<'blk, 'tcx, 'tcx>, &VariantInfo<'tcx>) -> usize,
-{
-    let mut bcx = bcx;
-    let _icx = push_ctxt("trans_rec_field");
-
-    let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field"));
-    let bare_ty = base_datum.ty;
-    let repr = adt::represent_type(bcx.ccx(), bare_ty);
-    let vinfo = VariantInfo::from_ty(bcx.tcx(), bare_ty, None);
-
-    let ix = get_idx(bcx.tcx(), &vinfo);
-    let d = base_datum.get_element(
-        bcx,
-        vinfo.fields[ix].1,
-        |srcval| {
-            adt::trans_field_ptr(bcx, &repr, srcval, vinfo.discr, ix)
-        });
-
-    if type_is_sized(bcx.tcx(), d.ty) {
-        DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
-    } else {
-        let scratch = rvalue_scratch_datum(bcx, d.ty, "");
-        Store(bcx, d.val, get_dataptr(bcx, scratch.val));
-        let info = Load(bcx, get_meta(bcx, base_datum.val));
-        Store(bcx, info, get_meta(bcx, scratch.val));
-
-        // Always generate an lvalue datum, because this pointer doesn't own
-        // the data and cleanup is scheduled elsewhere.
-        DatumBlock::new(bcx, Datum::new(scratch.val, scratch.ty, LvalueExpr(d.kind)))
-    }
-}
-
-/// Translates `base.field`.
-fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                               base: &hir::Expr,
-                               field: ast::Name)
-                               -> DatumBlock<'blk, 'tcx, Expr> {
-    trans_field(bcx, base, |_, vinfo| vinfo.field_index(field))
-}
-
-/// Translates `base.<idx>`.
-fn trans_rec_tup_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                   base: &hir::Expr,
-                                   idx: usize)
-                                   -> DatumBlock<'blk, 'tcx, Expr> {
-    trans_field(bcx, base, |_, _| idx)
-}
-
-fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                           index_expr: &hir::Expr,
-                           base: &hir::Expr,
-                           idx: &hir::Expr,
-                           method_call: MethodCall)
-                           -> DatumBlock<'blk, 'tcx, Expr> {
-    //! Translates `base[idx]`.
-
-    let _icx = push_ctxt("trans_index");
-    let ccx = bcx.ccx();
-    let mut bcx = bcx;
-
-    let index_expr_debug_loc = index_expr.debug_loc();
-
-    // Check for overloaded index.
-    let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned();
-    let elt_datum = match method {
-        Some(method) => {
-            let method_ty = monomorphize_type(bcx, method.ty);
-
-            let base_datum = unpack_datum!(bcx, trans(bcx, base));
-
-            // Translate index expression.
-            let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
-
-            let ref_ty = // invoked methods have LB regions instantiated:
-                bcx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap();
-            let elt_ty = match ref_ty.builtin_deref(true, ty::NoPreference) {
-                None => {
-                    span_bug!(index_expr.span,
-                              "index method didn't return a \
-                              dereferenceable type?!")
-                }
-                Some(elt_tm) => elt_tm.ty,
-            };
-
-            // Overloaded. Invoke the index() method, which basically
-            // yields a `&T` pointer.  We can then proceed down the
-            // normal path (below) to dereference that `&T`.
-            let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_index_elt");
-
-            bcx = Callee::method(bcx, method)
-                .call(bcx, index_expr_debug_loc,
-                      ArgOverloadedOp(base_datum, Some(ix_datum)),
-                      Some(SaveIn(scratch.val))).bcx;
-
-            let datum = scratch.to_expr_datum();
-            let lval = Lvalue::new("expr::trans_index overload");
-            if type_is_sized(bcx.tcx(), elt_ty) {
-                Datum::new(datum.to_llscalarish(bcx), elt_ty, LvalueExpr(lval))
-            } else {
-                Datum::new(datum.val, elt_ty, LvalueExpr(lval))
-            }
-        }
-        None => {
-            let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx,
-                                                                base,
-                                                                "index"));
-
-            // Translate index expression and cast to a suitable LLVM integer.
-            // Rust is less strict than LLVM in this regard.
-            let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
-            let ix_val = ix_datum.to_llscalarish(bcx);
-            let ix_size = machine::llbitsize_of_real(bcx.ccx(),
-                                                     val_ty(ix_val));
-            let int_size = machine::llbitsize_of_real(bcx.ccx(),
-                                                      ccx.int_type());
-            let ix_val = {
-                if ix_size < int_size {
-                    if expr_ty(bcx, idx).is_signed() {
-                        SExt(bcx, ix_val, ccx.int_type())
-                    } else { ZExt(bcx, ix_val, ccx.int_type()) }
-                } else if ix_size > int_size {
-                    Trunc(bcx, ix_val, ccx.int_type())
-                } else {
-                    ix_val
-                }
-            };
-
-            let unit_ty = base_datum.ty.sequence_element_type(bcx.tcx());
-
-            let (base, len) = base_datum.get_vec_base_and_len(bcx);
-
-            debug!("trans_index: base {:?}", Value(base));
-            debug!("trans_index: len {:?}", Value(len));
-
-            let bounds_check = ICmp(bcx,
-                                    llvm::IntUGE,
-                                    ix_val,
-                                    len,
-                                    index_expr_debug_loc);
-            let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
-            let expected = Call(bcx,
-                                expect,
-                                &[bounds_check, C_bool(ccx, false)],
-                                index_expr_debug_loc);
-            bcx = with_cond(bcx, expected, |bcx| {
-                controlflow::trans_fail_bounds_check(bcx,
-                                                     expr_info(index_expr),
-                                                     ix_val,
-                                                     len)
-            });
-            let elt = InBoundsGEP(bcx, base, &[ix_val]);
-            let elt = PointerCast(bcx, elt, type_of::type_of(ccx, unit_ty).ptr_to());
-            let lval = Lvalue::new("expr::trans_index fallback");
-            Datum::new(elt, unit_ty, LvalueExpr(lval))
-        }
-    };
-
-    DatumBlock::new(bcx, elt_datum)
-}
-
-/// Translates a reference to a variable.
-pub fn trans_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, def: Def)
-                             -> Datum<'tcx, Lvalue> {
-
-    match def {
-        Def::Static(did, _) => consts::get_static(bcx.ccx(), did),
-        Def::Upvar(_, nid, _, _) => {
-            // Can't move upvars, so this is never a ZeroMemLastUse.
-            let local_ty = node_id_type(bcx, nid);
-            let lval = Lvalue::new_with_hint("expr::trans_var (upvar)",
-                                             bcx, nid, HintKind::ZeroAndMaintain);
-            match bcx.fcx.llupvars.borrow().get(&nid) {
-                Some(&val) => Datum::new(val, local_ty, lval),
-                None => {
-                    bug!("trans_var: no llval for upvar {} found", nid);
-                }
-            }
-        }
-        Def::Local(_, nid) => {
-            let datum = match bcx.fcx.lllocals.borrow().get(&nid) {
-                Some(&v) => v,
-                None => {
-                    bug!("trans_var: no datum for local/arg {} found", nid);
-                }
-            };
-            debug!("take_local(nid={}, v={:?}, ty={})",
-                   nid, Value(datum.val), datum.ty);
-            datum
-        }
-        _ => bug!("{:?} should not reach expr::trans_var", def)
-    }
-}
-
-fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                            expr: &hir::Expr)
-                                            -> Block<'blk, 'tcx> {
-    let mut bcx = bcx;
-    let _icx = push_ctxt("trans_rvalue_stmt");
-
-    if bcx.unreachable.get() {
-        return bcx;
-    }
-
-    expr.debug_loc().apply(bcx.fcx);
-
-    match expr.node {
-        hir::ExprBreak(label_opt) => {
-            controlflow::trans_break(bcx, expr, label_opt.map(|l| l.node))
-        }
-        hir::ExprType(ref e, _) => {
-            trans_into(bcx, &e, Ignore)
-        }
-        hir::ExprAgain(label_opt) => {
-            controlflow::trans_cont(bcx, expr, label_opt.map(|l| l.node))
-        }
-        hir::ExprRet(ref ex) => {
-            // Check to see if the return expression itself is reachable.
-            // This can occur when the inner expression contains a return
-            let reachable = if let Some(ref cfg) = bcx.fcx.cfg {
-                cfg.node_is_reachable(expr.id)
-            } else {
-                true
-            };
-
-            if reachable {
-                controlflow::trans_ret(bcx, expr, ex.as_ref().map(|e| &**e))
-            } else {
-                // If it's not reachable, just translate the inner expression
-                // directly. This avoids having to manage a return slot when
-                // it won't actually be used anyway.
-                if let &Some(ref x) = ex {
-                    bcx = trans_into(bcx, &x, Ignore);
-                }
-                // Mark the end of the block as unreachable. Once we get to
-                // a return expression, there's no more we should be doing
-                // after this.
-                Unreachable(bcx);
-                bcx
-            }
-        }
-        hir::ExprWhile(ref cond, ref body, _) => {
-            controlflow::trans_while(bcx, expr, &cond, &body)
-        }
-        hir::ExprLoop(ref body, _) => {
-            controlflow::trans_loop(bcx, expr, &body)
-        }
-        hir::ExprAssign(ref dst, ref src) => {
-            let src_datum = unpack_datum!(bcx, trans(bcx, &src));
-            let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &dst, "assign"));
-
-            if bcx.fcx.type_needs_drop(dst_datum.ty) {
-                // If there are destructors involved, make sure we
-                // are copying from an rvalue, since that cannot possible
-                // alias an lvalue. We are concerned about code like:
-                //
-                //   a = a
-                //
-                // but also
-                //
-                //   a = a.b
-                //
-                // where e.g. a : Option<Foo> and a.b :
-                // Option<Foo>. In that case, freeing `a` before the
-                // assignment may also free `a.b`!
-                //
-                // We could avoid this intermediary with some analysis
-                // to determine whether `dst` may possibly own `src`.
-                expr.debug_loc().apply(bcx.fcx);
-                let src_datum = unpack_datum!(
-                    bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign"));
-                let opt_hint_datum = dst_datum.kind.drop_flag_info.hint_datum(bcx);
-                let opt_hint_val = opt_hint_datum.map(|d|d.to_value());
-
-                // 1. Drop the data at the destination, passing the
-                //    drop-hint in case the lvalue has already been
-                //    dropped or moved.
-                bcx = glue::drop_ty_core(bcx,
-                                         dst_datum.val,
-                                         dst_datum.ty,
-                                         expr.debug_loc(),
-                                         false,
-                                         opt_hint_val);
-
-                // 2. We are overwriting the destination; ensure that
-                //    its drop-hint (if any) says "initialized."
-                if let Some(hint_val) = opt_hint_val {
-                    let hint_llval = hint_val.value();
-                    let drop_needed = C_u8(bcx.fcx.ccx, adt::DTOR_NEEDED_HINT);
-                    Store(bcx, drop_needed, hint_llval);
-                }
-                src_datum.store_to(bcx, dst_datum.val)
-            } else {
-                src_datum.store_to(bcx, dst_datum.val)
-            }
-        }
-        hir::ExprAssignOp(op, ref dst, ref src) => {
-            let method = bcx.tcx().tables
-                                  .borrow()
-                                  .method_map
-                                  .get(&MethodCall::expr(expr.id)).cloned();
-
-            if let Some(method) = method {
-                let dst = unpack_datum!(bcx, trans(bcx, &dst));
-                let src_datum = unpack_datum!(bcx, trans(bcx, &src));
-
-                Callee::method(bcx, method)
-                    .call(bcx, expr.debug_loc(),
-                          ArgOverloadedOp(dst, Some(src_datum)), None).bcx
-            } else {
-                trans_assign_op(bcx, expr, op, &dst, &src)
-            }
-        }
-        hir::ExprInlineAsm(ref a, ref outputs, ref inputs) => {
-            let outputs = outputs.iter().map(|output| {
-                let out_datum = unpack_datum!(bcx, trans(bcx, output));
-                unpack_datum!(bcx, out_datum.to_lvalue_datum(bcx, "out", expr.id))
-            }).collect();
-            let inputs = inputs.iter().map(|input| {
-                let input = unpack_datum!(bcx, trans(bcx, input));
-                let input = unpack_datum!(bcx, input.to_rvalue_datum(bcx, "in"));
-                input.to_llscalarish(bcx)
-            }).collect();
-            asm::trans_inline_asm(bcx, a, outputs, inputs);
-            bcx
-        }
-        _ => {
-            span_bug!(
-                expr.span,
-                "trans_rvalue_stmt_unadjusted reached \
-                 fall-through case: {:?}",
-                expr.node);
-        }
-    }
-}
-
-fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                           expr: &hir::Expr,
-                                           dest: Dest)
-                                           -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
-    let mut bcx = bcx;
-
-    expr.debug_loc().apply(bcx.fcx);
-
-    // Entry into the method table if this is an overloaded call/op.
-    let method_call = MethodCall::expr(expr.id);
-
-    match expr.node {
-        hir::ExprType(ref e, _) => {
-            trans_into(bcx, &e, dest)
-        }
-        hir::ExprPath(..) => {
-            trans_def_dps_unadjusted(bcx, expr, bcx.tcx().expect_def(expr.id), dest)
-        }
-        hir::ExprIf(ref cond, ref thn, ref els) => {
-            controlflow::trans_if(bcx, expr.id, &cond, &thn, els.as_ref().map(|e| &**e), dest)
-        }
-        hir::ExprMatch(ref discr, ref arms, _) => {
-            _match::trans_match(bcx, expr, &discr, &arms[..], dest)
-        }
-        hir::ExprBlock(ref blk) => {
-            controlflow::trans_block(bcx, &blk, dest)
-        }
-        hir::ExprStruct(_, ref fields, ref base) => {
-            trans_struct(bcx,
-                         &fields[..],
-                         base.as_ref().map(|e| &**e),
-                         expr.span,
-                         expr.id,
-                         node_id_type(bcx, expr.id),
-                         dest)
-        }
-        hir::ExprTup(ref args) => {
-            let numbered_fields: Vec<(usize, &hir::Expr)> =
-                args.iter().enumerate().map(|(i, arg)| (i, &**arg)).collect();
-            trans_adt(bcx,
-                      expr_ty(bcx, expr),
-                      Disr(0),
-                      &numbered_fields[..],
-                      None,
-                      dest,
-                      expr.debug_loc())
-        }
-        hir::ExprLit(ref lit) => {
-            match lit.node {
-                ast::LitKind::Str(ref s, _) => {
-                    tvec::trans_lit_str(bcx, expr, (*s).clone(), dest)
-                }
-                _ => {
-                    span_bug!(expr.span,
-                              "trans_rvalue_dps_unadjusted shouldn't be \
-                              translating this type of literal")
-                }
-            }
-        }
-        hir::ExprVec(..) | hir::ExprRepeat(..) => {
-            tvec::trans_fixed_vstore(bcx, expr, dest)
-        }
-        hir::ExprClosure(_, ref decl, ref body, _) => {
-            let dest = match dest {
-                SaveIn(lldest) => closure::Dest::SaveIn(bcx, lldest),
-                Ignore => closure::Dest::Ignore(bcx.ccx())
-            };
-
-            // NB. To get the id of the closure, we don't use
-            // `local_def_id(id)`, but rather we extract the closure
-            // def-id from the expr's type. This is because this may
-            // be an inlined expression from another crate, and we
-            // want to get the ORIGINAL closure def-id, since that is
-            // the key we need to find the closure-kind and
-            // closure-type etc.
-            let (def_id, substs) = match expr_ty(bcx, expr).sty {
-                ty::TyClosure(def_id, substs) => (def_id, substs),
-                ref t =>
-                    span_bug!(
-                        expr.span,
-                        "closure expr without closure type: {:?}", t),
-            };
-
-            closure::trans_closure_expr(dest,
-                                        decl,
-                                        body,
-                                        expr.id,
-                                        def_id,
-                                        substs).unwrap_or(bcx)
-        }
-        hir::ExprCall(ref f, ref args) => {
-            let method = bcx.tcx().tables.borrow().method_map.get(&method_call).cloned();
-            let (callee, args) = if let Some(method) = method {
-                let mut all_args = vec![&**f];
-                all_args.extend(args.iter().map(|e| &**e));
-
-                (Callee::method(bcx, method), ArgOverloadedCall(all_args))
-            } else {
-                let f = unpack_datum!(bcx, trans(bcx, f));
-                (match f.ty.sty {
-                    ty::TyFnDef(def_id, substs, _) => {
-                        Callee::def(bcx.ccx(), def_id, substs)
-                    }
-                    ty::TyFnPtr(_) => {
-                        let f = unpack_datum!(bcx,
-                            f.to_rvalue_datum(bcx, "callee"));
-                        Callee::ptr(f)
-                    }
-                    _ => {
-                        span_bug!(expr.span,
-                            "type of callee is not a fn: {}", f.ty);
-                    }
-                }, ArgExprs(&args))
-            };
-            callee.call(bcx, expr.debug_loc(), args, Some(dest)).bcx
-        }
-        hir::ExprMethodCall(_, _, ref args) => {
-            Callee::method_call(bcx, method_call)
-                .call(bcx, expr.debug_loc(), ArgExprs(&args), Some(dest)).bcx
-        }
-        hir::ExprBinary(op, ref lhs, ref rhs_expr) => {
-            // if not overloaded, would be RvalueDatumExpr
-            let lhs = unpack_datum!(bcx, trans(bcx, &lhs));
-            let mut rhs = unpack_datum!(bcx, trans(bcx, &rhs_expr));
-            if !op.node.is_by_value() {
-                rhs = unpack_datum!(bcx, auto_ref(bcx, rhs, rhs_expr));
-            }
-
-            Callee::method_call(bcx, method_call)
-                .call(bcx, expr.debug_loc(),
-                      ArgOverloadedOp(lhs, Some(rhs)), Some(dest)).bcx
-        }
-        hir::ExprUnary(_, ref subexpr) => {
-            // if not overloaded, would be RvalueDatumExpr
-            let arg = unpack_datum!(bcx, trans(bcx, &subexpr));
-
-            Callee::method_call(bcx, method_call)
-                .call(bcx, expr.debug_loc(),
-                      ArgOverloadedOp(arg, None), Some(dest)).bcx
-        }
-        hir::ExprCast(..) => {
-            // Trait casts used to come this way, now they should be coercions.
-            span_bug!(expr.span, "DPS expr_cast (residual trait cast?)")
-        }
-        hir::ExprAssignOp(op, _, _) => {
-            span_bug!(
-                expr.span,
-                "augmented assignment `{}=` should always be a rvalue_stmt",
-                op.node.as_str())
-        }
-        _ => {
-            span_bug!(
-                expr.span,
-                "trans_rvalue_dps_unadjusted reached fall-through \
-                 case: {:?}",
-                expr.node);
-        }
-    }
-}
-
-fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                        ref_expr: &hir::Expr,
-                                        def: Def,
-                                        dest: Dest)
-                                        -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_def_dps_unadjusted");
-
-    let lldest = match dest {
-        SaveIn(lldest) => lldest,
-        Ignore => { return bcx; }
-    };
-
-    let ty = expr_ty(bcx, ref_expr);
-    if let ty::TyFnDef(..) = ty.sty {
-        // Zero-sized function or ctor.
-        return bcx;
-    }
-
-    match def {
-        Def::Variant(tid, vid) => {
-            let variant = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid);
-            // Nullary variant.
-            let ty = expr_ty(bcx, ref_expr);
-            let repr = adt::represent_type(bcx.ccx(), ty);
-            adt::trans_set_discr(bcx, &repr, lldest, Disr::from(variant.disr_val));
-            bcx
-        }
-        Def::Struct(..) => {
-            match ty.sty {
-                ty::TyStruct(def, _) if def.has_dtor() => {
-                    let repr = adt::represent_type(bcx.ccx(), ty);
-                    adt::trans_set_discr(bcx, &repr, lldest, Disr(0));
-                }
-                _ => {}
-            }
-            bcx
-        }
-        _ => {
-            span_bug!(ref_expr.span,
-                      "Non-DPS def {:?} referened by {}",
-                      def, bcx.node_id_to_string(ref_expr.id));
-        }
-    }
-}
-
-fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                            fields: &[hir::Field],
-                            base: Option<&hir::Expr>,
-                            expr_span: syntax_pos::Span,
-                            expr_id: ast::NodeId,
-                            ty: Ty<'tcx>,
-                            dest: Dest) -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_rec");
-
-    let tcx = bcx.tcx();
-    let vinfo = VariantInfo::of_node(tcx, ty, expr_id);
-
-    let mut need_base = vec![true; vinfo.fields.len()];
-
-    let numbered_fields = fields.iter().map(|field| {
-        let pos = vinfo.field_index(field.name.node);
-        need_base[pos] = false;
-        (pos, &*field.expr)
-    }).collect::<Vec<_>>();
-
-    let optbase = match base {
-        Some(base_expr) => {
-            let mut leftovers = Vec::new();
-            for (i, b) in need_base.iter().enumerate() {
-                if *b {
-                    leftovers.push((i, vinfo.fields[i].1));
-                }
-            }
-            Some(StructBaseInfo {expr: base_expr,
-                                 fields: leftovers })
-        }
-        None => {
-            if need_base.iter().any(|b| *b) {
-                span_bug!(expr_span, "missing fields and no base expr")
-            }
-            None
-        }
-    };
-
-    trans_adt(bcx,
-              ty,
-              vinfo.discr,
-              &numbered_fields,
-              optbase,
-              dest,
-              DebugLoc::At(expr_id, expr_span))
-}
-
-/// Information that `trans_adt` needs in order to fill in the fields
-/// of a struct copied from a base struct (e.g., from an expression
-/// like `Foo { a: b, ..base }`.
-///
-/// Note that `fields` may be empty; the base expression must always be
-/// evaluated for side-effects.
-pub struct StructBaseInfo<'a, 'tcx> {
-    /// The base expression; will be evaluated after all explicit fields.
-    expr: &'a hir::Expr,
-    /// The indices of fields to copy paired with their types.
-    fields: Vec<(usize, Ty<'tcx>)>
-}
-
-/// Constructs an ADT instance:
-///
-/// - `fields` should be a list of field indices paired with the
-/// expression to store into that field.  The initializers will be
-/// evaluated in the order specified by `fields`.
-///
-/// - `optbase` contains information on the base struct (if any) from
-/// which remaining fields are copied; see comments on `StructBaseInfo`.
-pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
-                                 ty: Ty<'tcx>,
-                                 discr: Disr,
-                                 fields: &[(usize, &hir::Expr)],
-                                 optbase: Option<StructBaseInfo<'a, 'tcx>>,
-                                 dest: Dest,
-                                 debug_location: DebugLoc)
-                                 -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_adt");
-    let fcx = bcx.fcx;
-    let repr = adt::represent_type(bcx.ccx(), ty);
-
-    debug_location.apply(bcx.fcx);
-
-    // If we don't care about the result, just make a
-    // temporary stack slot
-    let addr = match dest {
-        SaveIn(pos) => pos,
-        Ignore => {
-            let llresult = alloc_ty(bcx, ty, "temp");
-            call_lifetime_start(bcx, llresult);
-            llresult
-        }
-    };
-
-    debug!("trans_adt");
-
-    // This scope holds intermediates that must be cleaned should
-    // panic occur before the ADT as a whole is ready.
-    let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
-
-    if ty.is_simd() {
-        // Issue 23112: The original logic appeared vulnerable to same
-        // order-of-eval bug. But, SIMD values are tuple-structs;
-        // i.e. functional record update (FRU) syntax is unavailable.
-        //
-        // To be safe, double-check that we did not get here via FRU.
-        assert!(optbase.is_none());
-
-        // This is the constructor of a SIMD type, such types are
-        // always primitive machine types and so do not have a
-        // destructor or require any clean-up.
-        let llty = type_of::type_of(bcx.ccx(), ty);
-
-        // keep a vector as a register, and running through the field
-        // `insertelement`ing them directly into that register
-        // (i.e. avoid GEPi and `store`s to an alloca) .
-        let mut vec_val = C_undef(llty);
-
-        for &(i, ref e) in fields {
-            let block_datum = trans(bcx, &e);
-            bcx = block_datum.bcx;
-            let position = C_uint(bcx.ccx(), i);
-            let value = block_datum.datum.to_llscalarish(bcx);
-            vec_val = InsertElement(bcx, vec_val, value, position);
-        }
-        Store(bcx, vec_val, addr);
-    } else if let Some(base) = optbase {
-        // Issue 23112: If there is a base, then order-of-eval
-        // requires field expressions eval'ed before base expression.
-
-        // First, trans field expressions to temporary scratch values.
-        let scratch_vals: Vec<_> = fields.iter().map(|&(i, ref e)| {
-            let datum = unpack_datum!(bcx, trans(bcx, &e));
-            (i, datum)
-        }).collect();
-
-        debug_location.apply(bcx.fcx);
-
-        // Second, trans the base to the dest.
-        assert_eq!(discr, Disr(0));
-
-        let addr = adt::MaybeSizedValue::sized(addr);
-        match expr_kind(bcx.tcx(), &base.expr) {
-            ExprKind::RvalueDps | ExprKind::RvalueDatum if !bcx.fcx.type_needs_drop(ty) => {
-                bcx = trans_into(bcx, &base.expr, SaveIn(addr.value));
-            },
-            ExprKind::RvalueStmt => {
-                bug!("unexpected expr kind for struct base expr")
-            }
-            _ => {
-                let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &base.expr, "base"));
-                for &(i, t) in &base.fields {
-                    let datum = base_datum.get_element(
-                            bcx, t, |srcval| adt::trans_field_ptr(bcx, &repr, srcval, discr, i));
-                    assert!(type_is_sized(bcx.tcx(), datum.ty));
-                    let dest = adt::trans_field_ptr(bcx, &repr, addr, discr, i);
-                    bcx = datum.store_to(bcx, dest);
-                }
-            }
-        }
-
-        // Finally, move scratch field values into actual field locations
-        for (i, datum) in scratch_vals {
-            let dest = adt::trans_field_ptr(bcx, &repr, addr, discr, i);
-            bcx = datum.store_to(bcx, dest);
-        }
-    } else {
-        // No base means we can write all fields directly in place.
-        let addr = adt::MaybeSizedValue::sized(addr);
-        for &(i, ref e) in fields {
-            let dest = adt::trans_field_ptr(bcx, &repr, addr, discr, i);
-            let e_ty = expr_ty_adjusted(bcx, &e);
-            bcx = trans_into(bcx, &e, SaveIn(dest));
-            let scope = cleanup::CustomScope(custom_cleanup_scope);
-            fcx.schedule_lifetime_end(scope, dest);
-            // FIXME: nonzeroing move should generalize to fields
-            fcx.schedule_drop_mem(scope, dest, e_ty, None);
-        }
-    }
-
-    adt::trans_set_discr(bcx, &repr, addr, discr);
-
-    fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
-
-    // If we don't care about the result drop the temporary we made
-    match dest {
-        SaveIn(_) => bcx,
-        Ignore => {
-            bcx = glue::drop_ty(bcx, addr, ty, debug_location);
-            base::call_lifetime_end(bcx, addr);
-            bcx
-        }
-    }
-}
-
-
-fn trans_immediate_lit<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                   expr: &hir::Expr,
-                                   lit: &ast::Lit)
-                                   -> DatumBlock<'blk, 'tcx, Expr> {
-    // must not be a string constant, that is a RvalueDpsExpr
-    let _icx = push_ctxt("trans_immediate_lit");
-    let ty = expr_ty(bcx, expr);
-    let v = consts::const_lit(bcx.ccx(), expr, lit);
-    immediate_rvalue_bcx(bcx, v, ty).to_expr_datumblock()
-}
-
-fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                           expr: &hir::Expr,
-                           op: hir::UnOp,
-                           sub_expr: &hir::Expr)
-                           -> DatumBlock<'blk, 'tcx, Expr> {
-    let ccx = bcx.ccx();
-    let mut bcx = bcx;
-    let _icx = push_ctxt("trans_unary_datum");
-
-    let method_call = MethodCall::expr(expr.id);
-
-    // The only overloaded operator that is translated to a datum
-    // is an overloaded deref, since it is always yields a `&T`.
-    // Otherwise, we should be in the RvalueDpsExpr path.
-    assert!(op == hir::UnDeref || !ccx.tcx().is_method_call(expr.id));
-
-    let un_ty = expr_ty(bcx, expr);
-
-    let debug_loc = expr.debug_loc();
-
-    match op {
-        hir::UnNot => {
-            let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
-            let llresult = Not(bcx, datum.to_llscalarish(bcx), debug_loc);
-            immediate_rvalue_bcx(bcx, llresult, un_ty).to_expr_datumblock()
-        }
-        hir::UnNeg => {
-            let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
-            let val = datum.to_llscalarish(bcx);
-            let (bcx, llneg) = {
-                if un_ty.is_fp() {
-                    let result = FNeg(bcx, val, debug_loc);
-                    (bcx, result)
-                } else {
-                    let is_signed = un_ty.is_signed();
-                    let result = Neg(bcx, val, debug_loc);
-                    let bcx = if bcx.ccx().check_overflow() && is_signed {
-                        let (llty, min) = base::llty_and_min_for_signed_ty(bcx, un_ty);
-                        let is_min = ICmp(bcx, llvm::IntEQ, val,
-                                          C_integral(llty, min, true), debug_loc);
-                        with_cond(bcx, is_min, |bcx| {
-                            let msg = InternedString::new(
-                                "attempt to negate with overflow");
-                            controlflow::trans_fail(bcx, expr_info(expr), msg)
-                        })
-                    } else {
-                        bcx
-                    };
-                    (bcx, result)
-                }
-            };
-            immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
-        }
-        hir::UnDeref => {
-            let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
-            deref_once(bcx, expr, datum, method_call)
-        }
-    }
-}
-
-fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                               box_expr: &hir::Expr,
-                               box_ty: Ty<'tcx>,
-                               contents: &hir::Expr,
-                               contents_ty: Ty<'tcx>)
-                               -> DatumBlock<'blk, 'tcx, Expr> {
-    let _icx = push_ctxt("trans_uniq_expr");
-    let fcx = bcx.fcx;
-    assert!(type_is_sized(bcx.tcx(), contents_ty));
-    let llty = type_of::type_of(bcx.ccx(), contents_ty);
-    let size = llsize_of(bcx.ccx(), llty);
-    let align = C_uint(bcx.ccx(), type_of::align_of(bcx.ccx(), contents_ty));
-    let llty_ptr = llty.ptr_to();
-    let Result { bcx, val } = malloc_raw_dyn(bcx,
-                                             llty_ptr,
-                                             box_ty,
-                                             size,
-                                             align,
-                                             box_expr.debug_loc());
-    // Unique boxes do not allocate for zero-size types. The standard library
-    // may assume that `free` is never called on the pointer returned for
-    // `Box<ZeroSizeType>`.
-    let bcx = if llsize_of_alloc(bcx.ccx(), llty) == 0 {
-        trans_into(bcx, contents, SaveIn(val))
-    } else {
-        let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
-        fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
-                                val, cleanup::HeapExchange, contents_ty);
-        let bcx = trans_into(bcx, contents, SaveIn(val));
-        fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
-        bcx
-    };
-    immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
-}
-
-fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                             expr: &hir::Expr,
-                             subexpr: &hir::Expr)
-                             -> DatumBlock<'blk, 'tcx, Expr> {
-    let _icx = push_ctxt("trans_addr_of");
-    let mut bcx = bcx;
-    let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
-    let ty = expr_ty(bcx, expr);
-    if !type_is_sized(bcx.tcx(), sub_datum.ty) {
-        // Always generate an lvalue datum, because this pointer doesn't own
-        // the data and cleanup is scheduled elsewhere.
-        DatumBlock::new(bcx, Datum::new(sub_datum.val, ty, LvalueExpr(sub_datum.kind)))
-    } else {
-        // Sized value, ref to a thin pointer
-        immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock()
-    }
-}
-
-fn trans_scalar_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                  binop_expr: &hir::Expr,
-                                  binop_ty: Ty<'tcx>,
-                                  op: hir::BinOp,
-                                  lhs: Datum<'tcx, Rvalue>,
-                                  rhs: Datum<'tcx, Rvalue>)
-                                  -> DatumBlock<'blk, 'tcx, Expr>
-{
-    let _icx = push_ctxt("trans_scalar_binop");
-
-    let lhs_t = lhs.ty;
-    assert!(!lhs_t.is_simd());
-    let is_float = lhs_t.is_fp();
-    let is_signed = lhs_t.is_signed();
-    let info = expr_info(binop_expr);
-
-    let binop_debug_loc = binop_expr.debug_loc();
-
-    let mut bcx = bcx;
-    let lhs = lhs.to_llscalarish(bcx);
-    let rhs = rhs.to_llscalarish(bcx);
-    let val = match op.node {
-      hir::BiAdd => {
-        if is_float {
-            FAdd(bcx, lhs, rhs, binop_debug_loc)
-        } else {
-            let (newbcx, res) = with_overflow_check(
-                bcx, OverflowOp::Add, info, lhs_t, lhs, rhs, binop_debug_loc);
-            bcx = newbcx;
-            res
-        }
-      }
-      hir::BiSub => {
-        if is_float {
-            FSub(bcx, lhs, rhs, binop_debug_loc)
-        } else {
-            let (newbcx, res) = with_overflow_check(
-                bcx, OverflowOp::Sub, info, lhs_t, lhs, rhs, binop_debug_loc);
-            bcx = newbcx;
-            res
-        }
-      }
-      hir::BiMul => {
-        if is_float {
-            FMul(bcx, lhs, rhs, binop_debug_loc)
-        } else {
-            let (newbcx, res) = with_overflow_check(
-                bcx, OverflowOp::Mul, info, lhs_t, lhs, rhs, binop_debug_loc);
-            bcx = newbcx;
-            res
-        }
-      }
-      hir::BiDiv => {
-        if is_float {
-            FDiv(bcx, lhs, rhs, binop_debug_loc)
-        } else {
-            // Only zero-check integers; fp /0 is NaN
-            bcx = base::fail_if_zero_or_overflows(bcx,
-                                                  expr_info(binop_expr),
-                                                  op,
-                                                  lhs,
-                                                  rhs,
-                                                  lhs_t);
-            if is_signed {
-                SDiv(bcx, lhs, rhs, binop_debug_loc)
-            } else {
-                UDiv(bcx, lhs, rhs, binop_debug_loc)
-            }
-        }
-      }
-      hir::BiRem => {
-        if is_float {
-            FRem(bcx, lhs, rhs, binop_debug_loc)
-        } else {
-            // Only zero-check integers; fp %0 is NaN
-            bcx = base::fail_if_zero_or_overflows(bcx,
-                                                  expr_info(binop_expr),
-                                                  op, lhs, rhs, lhs_t);
-            if is_signed {
-                SRem(bcx, lhs, rhs, binop_debug_loc)
-            } else {
-                URem(bcx, lhs, rhs, binop_debug_loc)
-            }
-        }
-      }
-      hir::BiBitOr => Or(bcx, lhs, rhs, binop_debug_loc),
-      hir::BiBitAnd => And(bcx, lhs, rhs, binop_debug_loc),
-      hir::BiBitXor => Xor(bcx, lhs, rhs, binop_debug_loc),
-      hir::BiShl => {
-          let (newbcx, res) = with_overflow_check(
-              bcx, OverflowOp::Shl, info, lhs_t, lhs, rhs, binop_debug_loc);
-          bcx = newbcx;
-          res
-      }
-      hir::BiShr => {
-          let (newbcx, res) = with_overflow_check(
-              bcx, OverflowOp::Shr, info, lhs_t, lhs, rhs, binop_debug_loc);
-          bcx = newbcx;
-          res
-      }
-      hir::BiEq | hir::BiNe | hir::BiLt | hir::BiGe | hir::BiLe | hir::BiGt => {
-          base::compare_scalar_types(bcx, lhs, rhs, lhs_t, op.node, binop_debug_loc)
-      }
-      _ => {
-        span_bug!(binop_expr.span, "unexpected binop");
-      }
-    };
-
-    immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
-}
-
-// refinement types would obviate the need for this
-#[derive(Clone, Copy)]
-enum lazy_binop_ty {
-    lazy_and,
-    lazy_or,
-}
-
-
-fn trans_lazy_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                binop_expr: &hir::Expr,
-                                op: lazy_binop_ty,
-                                a: &hir::Expr,
-                                b: &hir::Expr)
-                                -> DatumBlock<'blk, 'tcx, Expr> {
-    let _icx = push_ctxt("trans_lazy_binop");
-    let binop_ty = expr_ty(bcx, binop_expr);
-    let fcx = bcx.fcx;
-
-    let DatumBlock {bcx: past_lhs, datum: lhs} = trans(bcx, a);
-    let lhs = lhs.to_llscalarish(past_lhs);
-
-    if past_lhs.unreachable.get() {
-        return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock();
-    }
-
-    // If the rhs can never be reached, don't generate code for it.
-    if let Some(cond_val) = const_to_opt_uint(lhs) {
-        match (cond_val, op) {
-            (0, lazy_and) |
-            (1, lazy_or)  => {
-                return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock();
-            }
-            _ => { /* continue */ }
-        }
-    }
-
-    let join = fcx.new_id_block("join", binop_expr.id);
-    let before_rhs = fcx.new_id_block("before_rhs", b.id);
-
-    match op {
-      lazy_and => CondBr(past_lhs, lhs, before_rhs.llbb, join.llbb, DebugLoc::None),
-      lazy_or => CondBr(past_lhs, lhs, join.llbb, before_rhs.llbb, DebugLoc::None)
-    }
-
-    let DatumBlock {bcx: past_rhs, datum: rhs} = trans(before_rhs, b);
-    let rhs = rhs.to_llscalarish(past_rhs);
-
-    if past_rhs.unreachable.get() {
-        return immediate_rvalue_bcx(join, lhs, binop_ty).to_expr_datumblock();
-    }
-
-    Br(past_rhs, join.llbb, DebugLoc::None);
-    let phi = Phi(join, Type::i1(bcx.ccx()), &[lhs, rhs],
-                  &[past_lhs.llbb, past_rhs.llbb]);
-
-    return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock();
-}
-
-fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                            expr: &hir::Expr,
-                            op: hir::BinOp,
-                            lhs: &hir::Expr,
-                            rhs: &hir::Expr)
-                            -> DatumBlock<'blk, 'tcx, Expr> {
-    let _icx = push_ctxt("trans_binary");
-    let ccx = bcx.ccx();
-
-    // if overloaded, would be RvalueDpsExpr
-    assert!(!ccx.tcx().is_method_call(expr.id));
-
-    match op.node {
-        hir::BiAnd => {
-            trans_lazy_binop(bcx, expr, lazy_and, lhs, rhs)
-        }
-        hir::BiOr => {
-            trans_lazy_binop(bcx, expr, lazy_or, lhs, rhs)
-        }
-        _ => {
-            let mut bcx = bcx;
-            let binop_ty = expr_ty(bcx, expr);
-
-            let lhs = unpack_datum!(bcx, trans(bcx, lhs));
-            let lhs = unpack_datum!(bcx, lhs.to_rvalue_datum(bcx, "binop_lhs"));
-            debug!("trans_binary (expr {}): lhs={:?}", expr.id, lhs);
-            let rhs = unpack_datum!(bcx, trans(bcx, rhs));
-            let rhs = unpack_datum!(bcx, rhs.to_rvalue_datum(bcx, "binop_rhs"));
-            debug!("trans_binary (expr {}): rhs={:?}", expr.id, rhs);
-
-            if type_is_fat_ptr(ccx.tcx(), lhs.ty) {
-                assert!(type_is_fat_ptr(ccx.tcx(), rhs.ty),
-                        "built-in binary operators on fat pointers are homogeneous");
-                assert_eq!(binop_ty, bcx.tcx().types.bool);
-                let val = base::compare_scalar_types(
-                    bcx,
-                    lhs.val,
-                    rhs.val,
-                    lhs.ty,
-                    op.node,
-                    expr.debug_loc());
-                immediate_rvalue_bcx(bcx, val, binop_ty).to_expr_datumblock()
-            } else {
-                assert!(!type_is_fat_ptr(ccx.tcx(), rhs.ty),
-                        "built-in binary operators on fat pointers are homogeneous");
-                trans_scalar_binop(bcx, expr, binop_ty, op, lhs, rhs)
-            }
-        }
-    }
-}
-
-pub fn cast_is_noop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                              expr: &hir::Expr,
-                              t_in: Ty<'tcx>,
-                              t_out: Ty<'tcx>)
-                              -> bool {
-    if let Some(&CastKind::CoercionCast) = tcx.cast_kinds.borrow().get(&expr.id) {
-        return true;
-    }
-
-    match (t_in.builtin_deref(true, ty::NoPreference),
-           t_out.builtin_deref(true, ty::NoPreference)) {
-        (Some(ty::TypeAndMut{ ty: t_in, .. }), Some(ty::TypeAndMut{ ty: t_out, .. })) => {
-            t_in == t_out
-        }
-        _ => {
-            // This condition isn't redundant with the check for CoercionCast:
-            // different types can be substituted into the same type, and
-            // == equality can be overconservative if there are regions.
-            t_in == t_out
-        }
-    }
-}
-
-fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                              expr: &hir::Expr,
-                              id: ast::NodeId)
-                              -> DatumBlock<'blk, 'tcx, Expr>
-{
-    use rustc::ty::cast::CastTy::*;
-    use rustc::ty::cast::IntTy::*;
-
-    fn int_cast(bcx: Block,
-                lldsttype: Type,
-                llsrctype: Type,
-                llsrc: ValueRef,
-                signed: bool)
-                -> ValueRef
-    {
-        let _icx = push_ctxt("int_cast");
-        let srcsz = llsrctype.int_width();
-        let dstsz = lldsttype.int_width();
-        return if dstsz == srcsz {
-            BitCast(bcx, llsrc, lldsttype)
-        } else if srcsz > dstsz {
-            TruncOrBitCast(bcx, llsrc, lldsttype)
-        } else if signed {
-            SExtOrBitCast(bcx, llsrc, lldsttype)
-        } else {
-            ZExtOrBitCast(bcx, llsrc, lldsttype)
-        }
-    }
-
-    fn float_cast(bcx: Block,
-                  lldsttype: Type,
-                  llsrctype: Type,
-                  llsrc: ValueRef)
-                  -> ValueRef
-    {
-        let _icx = push_ctxt("float_cast");
-        let srcsz = llsrctype.float_width();
-        let dstsz = lldsttype.float_width();
-        return if dstsz > srcsz {
-            FPExt(bcx, llsrc, lldsttype)
-        } else if srcsz > dstsz {
-            FPTrunc(bcx, llsrc, lldsttype)
-        } else { llsrc };
-    }
-
-    let _icx = push_ctxt("trans_cast");
-    let mut bcx = bcx;
-    let ccx = bcx.ccx();
-
-    let t_in = expr_ty_adjusted(bcx, expr);
-    let t_out = node_id_type(bcx, id);
-
-    debug!("trans_cast({:?} as {:?})", t_in, t_out);
-    let mut ll_t_in = type_of::immediate_type_of(ccx, t_in);
-    let ll_t_out = type_of::immediate_type_of(ccx, t_out);
-    // Convert the value to be cast into a ValueRef, either by-ref or
-    // by-value as appropriate given its type:
-    let mut datum = unpack_datum!(bcx, trans(bcx, expr));
-
-    let datum_ty = monomorphize_type(bcx, datum.ty);
-
-    if cast_is_noop(bcx.tcx(), expr, datum_ty, t_out) {
-        datum.ty = t_out;
-        return DatumBlock::new(bcx, datum);
-    }
-
-    if type_is_fat_ptr(bcx.tcx(), t_in) {
-        assert!(datum.kind.is_by_ref());
-        if type_is_fat_ptr(bcx.tcx(), t_out) {
-            return DatumBlock::new(bcx, Datum::new(
-                PointerCast(bcx, datum.val, ll_t_out.ptr_to()),
-                t_out,
-                Rvalue::new(ByRef)
-            )).to_expr_datumblock();
-        } else {
-            // Return the address
-            return immediate_rvalue_bcx(bcx,
-                                        PointerCast(bcx,
-                                                    Load(bcx, get_dataptr(bcx, datum.val)),
-                                                    ll_t_out),
-                                        t_out).to_expr_datumblock();
-        }
-    }
-
-    let r_t_in = CastTy::from_ty(t_in).expect("bad input type for cast");
-    let r_t_out = CastTy::from_ty(t_out).expect("bad output type for cast");
-
-    let (llexpr, signed) = if let Int(CEnum) = r_t_in {
-        let repr = adt::represent_type(ccx, t_in);
-        let datum = unpack_datum!(
-            bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
-        let llexpr_ptr = datum.to_llref();
-        let discr = adt::trans_get_discr(bcx, &repr, llexpr_ptr,
-                                         Some(Type::i64(ccx)), true);
-        ll_t_in = val_ty(discr);
-        (discr, adt::is_discr_signed(&repr))
-    } else {
-        (datum.to_llscalarish(bcx), t_in.is_signed())
-    };
-
-    let newval = match (r_t_in, r_t_out) {
-        (Ptr(_), Ptr(_)) | (FnPtr, Ptr(_)) | (RPtr(_), Ptr(_)) => {
-            PointerCast(bcx, llexpr, ll_t_out)
-        }
-        (Ptr(_), Int(_)) | (FnPtr, Int(_)) => PtrToInt(bcx, llexpr, ll_t_out),
-        (Int(_), Ptr(_)) => IntToPtr(bcx, llexpr, ll_t_out),
-
-        (Int(_), Int(_)) => int_cast(bcx, ll_t_out, ll_t_in, llexpr, signed),
-        (Float, Float) => float_cast(bcx, ll_t_out, ll_t_in, llexpr),
-        (Int(_), Float) if signed => SIToFP(bcx, llexpr, ll_t_out),
-        (Int(_), Float) => UIToFP(bcx, llexpr, ll_t_out),
-        (Float, Int(I)) => FPToSI(bcx, llexpr, ll_t_out),
-        (Float, Int(_)) => FPToUI(bcx, llexpr, ll_t_out),
-
-        _ => span_bug!(expr.span,
-                       "translating unsupported cast: \
-                        {:?} -> {:?}",
-                       t_in,
-                       t_out)
-    };
-    return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock();
-}
-
-fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                               expr: &hir::Expr,
-                               op: hir::BinOp,
-                               dst: &hir::Expr,
-                               src: &hir::Expr)
-                               -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_assign_op");
-    let mut bcx = bcx;
-
-    debug!("trans_assign_op(expr={:?})", expr);
-
-    // User-defined operator methods cannot be used with `+=` etc right now
-    assert!(!bcx.tcx().is_method_call(expr.id));
-
-    // Evaluate LHS (destination), which should be an lvalue
-    let dst = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
-    assert!(!bcx.fcx.type_needs_drop(dst.ty));
-    let lhs = load_ty(bcx, dst.val, dst.ty);
-    let lhs = immediate_rvalue(lhs, dst.ty);
-
-    // Evaluate RHS - FIXME(#28160) this sucks
-    let rhs = unpack_datum!(bcx, trans(bcx, &src));
-    let rhs = unpack_datum!(bcx, rhs.to_rvalue_datum(bcx, "assign_op_rhs"));
-
-    // Perform computation and store the result
-    let result_datum = unpack_datum!(
-        bcx, trans_scalar_binop(bcx, expr, dst.ty, op, lhs, rhs));
-    return result_datum.store_to(bcx, dst.val);
-}
-
-fn auto_ref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                        datum: Datum<'tcx, Expr>,
-                        expr: &hir::Expr)
-                        -> DatumBlock<'blk, 'tcx, Expr> {
-    let mut bcx = bcx;
-
-    // Ensure cleanup of `datum` if not already scheduled and obtain
-    // a "by ref" pointer.
-    let lv_datum = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "autoref", expr.id));
-
-    // Compute final type. Note that we are loose with the region and
-    // mutability, since those things don't matter in trans.
-    let referent_ty = lv_datum.ty;
-    let ptr_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReErased), referent_ty);
-
-    // Construct the resulting datum. The right datum to return here would be an Lvalue datum,
-    // because there is cleanup scheduled and the datum doesn't own the data, but for thin pointers
-    // we microoptimize it to be an Rvalue datum to avoid the extra alloca and level of
-    // indirection and for thin pointers, this has no ill effects.
-    let kind  = if type_is_sized(bcx.tcx(), referent_ty) {
-        RvalueExpr(Rvalue::new(ByValue))
-    } else {
-        LvalueExpr(lv_datum.kind)
-    };
-
-    // Get the pointer.
-    let llref = lv_datum.to_llref();
-    DatumBlock::new(bcx, Datum::new(llref, ptr_ty, kind))
-}
-
-fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                              expr: &hir::Expr,
-                              datum: Datum<'tcx, Expr>,
-                              times: usize)
-                              -> DatumBlock<'blk, 'tcx, Expr> {
-    let mut bcx = bcx;
-    let mut datum = datum;
-    for i in 0..times {
-        let method_call = MethodCall::autoderef(expr.id, i as u32);
-        datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call));
-    }
-    DatumBlock { bcx: bcx, datum: datum }
-}
-
-fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                          expr: &hir::Expr,
-                          datum: Datum<'tcx, Expr>,
-                          method_call: MethodCall)
-                          -> DatumBlock<'blk, 'tcx, Expr> {
-    let ccx = bcx.ccx();
-
-    debug!("deref_once(expr={:?}, datum={:?}, method_call={:?})",
-           expr, datum, method_call);
-
-    let mut bcx = bcx;
-
-    // Check for overloaded deref.
-    let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned();
-    let datum = match method {
-        Some(method) => {
-            let method_ty = monomorphize_type(bcx, method.ty);
-
-            // Overloaded. Invoke the deref() method, which basically
-            // converts from the `Smaht<T>` pointer that we have into
-            // a `&T` pointer.  We can then proceed down the normal
-            // path (below) to dereference that `&T`.
-            let datum = if method_call.autoderef == 0 {
-                datum
-            } else {
-                // Always perform an AutoPtr when applying an overloaded auto-deref
-                unpack_datum!(bcx, auto_ref(bcx, datum, expr))
-            };
-
-            let ref_ty = // invoked methods have their LB regions instantiated
-                ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap();
-            let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");
-
-            bcx = Callee::method(bcx, method)
-                .call(bcx, expr.debug_loc(),
-                      ArgOverloadedOp(datum, None),
-                      Some(SaveIn(scratch.val))).bcx;
-            scratch.to_expr_datum()
-        }
-        None => {
-            // Not overloaded. We already have a pointer we know how to deref.
-            datum
-        }
-    };
-
-    let r = match datum.ty.sty {
-        ty::TyBox(content_ty) => {
-            // Make sure we have an lvalue datum here to get the
-            // proper cleanups scheduled
-            let datum = unpack_datum!(
-                bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));
-
-            if type_is_sized(bcx.tcx(), content_ty) {
-                let ptr = load_ty(bcx, datum.val, datum.ty);
-                DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr(datum.kind)))
-            } else {
-                // A fat pointer and a DST lvalue have the same representation
-                // just different types. Since there is no temporary for `*e`
-                // here (because it is unsized), we cannot emulate the sized
-                // object code path for running drop glue and free. Instead,
-                // we schedule cleanup for `e`, turning it into an lvalue.
-
-                let lval = Lvalue::new("expr::deref_once ty_uniq");
-                let datum = Datum::new(datum.val, content_ty, LvalueExpr(lval));
-                DatumBlock::new(bcx, datum)
-            }
-        }
-
-        ty::TyRawPtr(ty::TypeAndMut { ty: content_ty, .. }) |
-        ty::TyRef(_, ty::TypeAndMut { ty: content_ty, .. }) => {
-            let lval = Lvalue::new("expr::deref_once ptr");
-            if type_is_sized(bcx.tcx(), content_ty) {
-                let ptr = datum.to_llscalarish(bcx);
-
-                // Always generate an lvalue datum, even if datum.mode is
-                // an rvalue.  This is because datum.mode is only an
-                // rvalue for non-owning pointers like &T or *T, in which
-                // case cleanup *is* scheduled elsewhere, by the true
-                // owner (or, in the case of *T, by the user).
-                DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr(lval)))
-            } else {
-                // A fat pointer and a DST lvalue have the same representation
-                // just different types.
-                DatumBlock::new(bcx, Datum::new(datum.val, content_ty, LvalueExpr(lval)))
-            }
-        }
-
-        _ => {
-            span_bug!(
-                expr.span,
-                "deref invoked on expr of invalid type {:?}",
-                datum.ty);
-        }
-    };
-
-    debug!("deref_once(expr={}, method_call={:?}, result={:?})",
-           expr.id, method_call, r.datum);
-
-    return r;
-}
-
-#[derive(Debug)]
-enum OverflowOp {
-    Add,
-    Sub,
-    Mul,
-    Shl,
-    Shr,
-}
-
-impl OverflowOp {
-    fn codegen_strategy(&self) -> OverflowCodegen {
-        use self::OverflowCodegen::{ViaIntrinsic, ViaInputCheck};
-        match *self {
-            OverflowOp::Add => ViaIntrinsic(OverflowOpViaIntrinsic::Add),
-            OverflowOp::Sub => ViaIntrinsic(OverflowOpViaIntrinsic::Sub),
-            OverflowOp::Mul => ViaIntrinsic(OverflowOpViaIntrinsic::Mul),
-
-            OverflowOp::Shl => ViaInputCheck(OverflowOpViaInputCheck::Shl),
-            OverflowOp::Shr => ViaInputCheck(OverflowOpViaInputCheck::Shr),
-        }
-    }
-}
-
-enum OverflowCodegen {
-    ViaIntrinsic(OverflowOpViaIntrinsic),
-    ViaInputCheck(OverflowOpViaInputCheck),
-}
-
-enum OverflowOpViaInputCheck { Shl, Shr, }
-
-#[derive(Debug)]
-enum OverflowOpViaIntrinsic { Add, Sub, Mul, }
-
-impl OverflowOpViaIntrinsic {
-    fn to_intrinsic<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>, lhs_ty: Ty) -> ValueRef {
-        let name = self.to_intrinsic_name(bcx.tcx(), lhs_ty);
-        bcx.ccx().get_intrinsic(&name)
-    }
-    fn to_intrinsic_name(&self, tcx: TyCtxt, ty: Ty) -> &'static str {
-        use syntax::ast::IntTy::*;
-        use syntax::ast::UintTy::*;
-        use rustc::ty::{TyInt, TyUint};
-
-        let new_sty = match ty.sty {
-            TyInt(Is) => match &tcx.sess.target.target.target_pointer_width[..] {
-                "16" => TyInt(I16),
-                "32" => TyInt(I32),
-                "64" => TyInt(I64),
-                _ => bug!("unsupported target word size")
-            },
-            TyUint(Us) => match &tcx.sess.target.target.target_pointer_width[..] {
-                "16" => TyUint(U16),
-                "32" => TyUint(U32),
-                "64" => TyUint(U64),
-                _ => bug!("unsupported target word size")
-            },
-            ref t @ TyUint(_) | ref t @ TyInt(_) => t.clone(),
-            _ => bug!("tried to get overflow intrinsic for {:?} applied to non-int type",
-                      *self)
-        };
-
-        match *self {
-            OverflowOpViaIntrinsic::Add => match new_sty {
-                TyInt(I8) => "llvm.sadd.with.overflow.i8",
-                TyInt(I16) => "llvm.sadd.with.overflow.i16",
-                TyInt(I32) => "llvm.sadd.with.overflow.i32",
-                TyInt(I64) => "llvm.sadd.with.overflow.i64",
-
-                TyUint(U8) => "llvm.uadd.with.overflow.i8",
-                TyUint(U16) => "llvm.uadd.with.overflow.i16",
-                TyUint(U32) => "llvm.uadd.with.overflow.i32",
-                TyUint(U64) => "llvm.uadd.with.overflow.i64",
-
-                _ => bug!(),
-            },
-            OverflowOpViaIntrinsic::Sub => match new_sty {
-                TyInt(I8) => "llvm.ssub.with.overflow.i8",
-                TyInt(I16) => "llvm.ssub.with.overflow.i16",
-                TyInt(I32) => "llvm.ssub.with.overflow.i32",
-                TyInt(I64) => "llvm.ssub.with.overflow.i64",
-
-                TyUint(U8) => "llvm.usub.with.overflow.i8",
-                TyUint(U16) => "llvm.usub.with.overflow.i16",
-                TyUint(U32) => "llvm.usub.with.overflow.i32",
-                TyUint(U64) => "llvm.usub.with.overflow.i64",
-
-                _ => bug!(),
-            },
-            OverflowOpViaIntrinsic::Mul => match new_sty {
-                TyInt(I8) => "llvm.smul.with.overflow.i8",
-                TyInt(I16) => "llvm.smul.with.overflow.i16",
-                TyInt(I32) => "llvm.smul.with.overflow.i32",
-                TyInt(I64) => "llvm.smul.with.overflow.i64",
-
-                TyUint(U8) => "llvm.umul.with.overflow.i8",
-                TyUint(U16) => "llvm.umul.with.overflow.i16",
-                TyUint(U32) => "llvm.umul.with.overflow.i32",
-                TyUint(U64) => "llvm.umul.with.overflow.i64",
-
-                _ => bug!(),
-            },
-        }
-    }
-
-    fn build_intrinsic_call<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>,
-                                        info: NodeIdAndSpan,
-                                        lhs_t: Ty<'tcx>, lhs: ValueRef,
-                                        rhs: ValueRef,
-                                        binop_debug_loc: DebugLoc)
-                                        -> (Block<'blk, 'tcx>, ValueRef) {
-        use rustc_const_math::{ConstMathErr, Op};
-
-        let llfn = self.to_intrinsic(bcx, lhs_t);
-
-        let val = Call(bcx, llfn, &[lhs, rhs], binop_debug_loc);
-        let result = ExtractValue(bcx, val, 0); // iN operation result
-        let overflow = ExtractValue(bcx, val, 1); // i1 "did it overflow?"
-
-        let cond = ICmp(bcx, llvm::IntEQ, overflow, C_integral(Type::i1(bcx.ccx()), 1, false),
-                        binop_debug_loc);
-
-        let expect = bcx.ccx().get_intrinsic(&"llvm.expect.i1");
-        let expected = Call(bcx, expect, &[cond, C_bool(bcx.ccx(), false)],
-                            binop_debug_loc);
-
-        let op = match *self {
-            OverflowOpViaIntrinsic::Add => Op::Add,
-            OverflowOpViaIntrinsic::Sub => Op::Sub,
-            OverflowOpViaIntrinsic::Mul => Op::Mul
-        };
-
-        let bcx =
-            base::with_cond(bcx, expected, |bcx|
-                controlflow::trans_fail(bcx, info,
-                    InternedString::new(ConstMathErr::Overflow(op).description())));
-
-        (bcx, result)
-    }
-}
-
-impl OverflowOpViaInputCheck {
-    fn build_with_input_check<'blk, 'tcx>(&self,
-                                          bcx: Block<'blk, 'tcx>,
-                                          info: NodeIdAndSpan,
-                                          lhs_t: Ty<'tcx>,
-                                          lhs: ValueRef,
-                                          rhs: ValueRef,
-                                          binop_debug_loc: DebugLoc)
-                                          -> (Block<'blk, 'tcx>, ValueRef)
-    {
-        use rustc_const_math::{ConstMathErr, Op};
-
-        let lhs_llty = val_ty(lhs);
-        let rhs_llty = val_ty(rhs);
-
-        // Panic if any bits are set outside of bits that we always
-        // mask in.
-        //
-        // Note that the mask's value is derived from the LHS type
-        // (since that is where the 32/64 distinction is relevant) but
-        // the mask's type must match the RHS type (since they will
-        // both be fed into an and-binop)
-        let invert_mask = shift_mask_val(bcx, lhs_llty, rhs_llty, true);
-
-        let outer_bits = And(bcx, rhs, invert_mask, binop_debug_loc);
-        let cond = build_nonzero_check(bcx, outer_bits, binop_debug_loc);
-        let (result, op) = match *self {
-            OverflowOpViaInputCheck::Shl =>
-                (build_unchecked_lshift(bcx, lhs, rhs, binop_debug_loc), Op::Shl),
-            OverflowOpViaInputCheck::Shr =>
-                (build_unchecked_rshift(bcx, lhs_t, lhs, rhs, binop_debug_loc), Op::Shr)
-        };
-        let bcx =
-            base::with_cond(bcx, cond, |bcx|
-                controlflow::trans_fail(bcx, info,
-                    InternedString::new(ConstMathErr::Overflow(op).description())));
-
-        (bcx, result)
-    }
-}
-
-// Check if an integer or vector contains a nonzero element.
-fn build_nonzero_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                   value: ValueRef,
-                                   binop_debug_loc: DebugLoc) -> ValueRef {
-    let llty = val_ty(value);
-    let kind = llty.kind();
-    match kind {
-        TypeKind::Integer => ICmp(bcx, llvm::IntNE, value, C_null(llty), binop_debug_loc),
-        TypeKind::Vector => {
-            // Check if any elements of the vector are nonzero by treating
-            // it as a wide integer and checking if the integer is nonzero.
-            let width = llty.vector_length() as u64 * llty.element_type().int_width();
-            let int_value = BitCast(bcx, value, Type::ix(bcx.ccx(), width));
-            build_nonzero_check(bcx, int_value, binop_debug_loc)
-        },
-        _ => bug!("build_nonzero_check: expected Integer or Vector, found {:?}", kind),
-    }
-}
-
-fn with_overflow_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, oop: OverflowOp, info: NodeIdAndSpan,
-                                   lhs_t: Ty<'tcx>, lhs: ValueRef,
-                                   rhs: ValueRef,
-                                   binop_debug_loc: DebugLoc)
-                                   -> (Block<'blk, 'tcx>, ValueRef) {
-    if bcx.unreachable.get() { return (bcx, _Undef(lhs)); }
-    if bcx.ccx().check_overflow() {
-
-        match oop.codegen_strategy() {
-            OverflowCodegen::ViaIntrinsic(oop) =>
-                oop.build_intrinsic_call(bcx, info, lhs_t, lhs, rhs, binop_debug_loc),
-            OverflowCodegen::ViaInputCheck(oop) =>
-                oop.build_with_input_check(bcx, info, lhs_t, lhs, rhs, binop_debug_loc),
-        }
-    } else {
-        let res = match oop {
-            OverflowOp::Add => Add(bcx, lhs, rhs, binop_debug_loc),
-            OverflowOp::Sub => Sub(bcx, lhs, rhs, binop_debug_loc),
-            OverflowOp::Mul => Mul(bcx, lhs, rhs, binop_debug_loc),
-
-            OverflowOp::Shl =>
-                build_unchecked_lshift(bcx, lhs, rhs, binop_debug_loc),
-            OverflowOp::Shr =>
-                build_unchecked_rshift(bcx, lhs_t, lhs, rhs, binop_debug_loc),
-        };
-        (bcx, res)
-    }
-}
-
-/// We categorize expressions into three kinds.  The distinction between
-/// lvalue/rvalue is fundamental to the language.  The distinction between the
-/// two kinds of rvalues is an artifact of trans which reflects how we will
-/// generate code for that kind of expression.  See trans/expr.rs for more
-/// information.
-#[derive(Copy, Clone)]
-enum ExprKind {
-    Lvalue,
-    RvalueDps,
-    RvalueDatum,
-    RvalueStmt
-}
-
-fn expr_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, expr: &hir::Expr) -> ExprKind {
-    if tcx.is_method_call(expr.id) {
-        // Overloaded operations are generally calls, and hence they are
-        // generated via DPS, but there are a few exceptions:
-        return match expr.node {
-            // `a += b` has a unit result.
-            hir::ExprAssignOp(..) => ExprKind::RvalueStmt,
-
-            // the deref method invoked for `*a` always yields an `&T`
-            hir::ExprUnary(hir::UnDeref, _) => ExprKind::Lvalue,
-
-            // the index method invoked for `a[i]` always yields an `&T`
-            hir::ExprIndex(..) => ExprKind::Lvalue,
-
-            // in the general case, result could be any type, use DPS
-            _ => ExprKind::RvalueDps
-        };
-    }
-
-    match expr.node {
-        hir::ExprPath(..) => {
-            match tcx.expect_def(expr.id) {
-                // Put functions and ctors with the ADTs, as they
-                // are zero-sized, so DPS is the cheapest option.
-                Def::Struct(..) | Def::Variant(..) |
-                Def::Fn(..) | Def::Method(..) => {
-                    ExprKind::RvalueDps
-                }
-
-                // Note: there is actually a good case to be made that
-                // DefArg's, particularly those of immediate type, ought to
-                // considered rvalues.
-                Def::Static(..) |
-                Def::Upvar(..) |
-                Def::Local(..) => ExprKind::Lvalue,
-
-                Def::Const(..) |
-                Def::AssociatedConst(..) => ExprKind::RvalueDatum,
-
-                def => {
-                    span_bug!(
-                        expr.span,
-                        "uncategorized def for expr {}: {:?}",
-                        expr.id,
-                        def);
-                }
-            }
-        }
-
-        hir::ExprType(ref expr, _) => {
-            expr_kind(tcx, expr)
-        }
-
-        hir::ExprUnary(hir::UnDeref, _) |
-        hir::ExprField(..) |
-        hir::ExprTupField(..) |
-        hir::ExprIndex(..) => {
-            ExprKind::Lvalue
-        }
-
-        hir::ExprCall(..) |
-        hir::ExprMethodCall(..) |
-        hir::ExprStruct(..) |
-        hir::ExprTup(..) |
-        hir::ExprIf(..) |
-        hir::ExprMatch(..) |
-        hir::ExprClosure(..) |
-        hir::ExprBlock(..) |
-        hir::ExprRepeat(..) |
-        hir::ExprVec(..) => {
-            ExprKind::RvalueDps
-        }
-
-        hir::ExprLit(ref lit) if lit.node.is_str() => {
-            ExprKind::RvalueDps
-        }
-
-        hir::ExprBreak(..) |
-        hir::ExprAgain(..) |
-        hir::ExprRet(..) |
-        hir::ExprWhile(..) |
-        hir::ExprLoop(..) |
-        hir::ExprAssign(..) |
-        hir::ExprInlineAsm(..) |
-        hir::ExprAssignOp(..) => {
-            ExprKind::RvalueStmt
-        }
-
-        hir::ExprLit(_) | // Note: LitStr is carved out above
-        hir::ExprUnary(..) |
-        hir::ExprBox(_) |
-        hir::ExprAddrOf(..) |
-        hir::ExprBinary(..) |
-        hir::ExprCast(..) => {
-            ExprKind::RvalueDatum
-        }
-    }
-}
index 080844782f2051c31983602065c5afa43255a448..9e1e415f62a67b528f56e1ef70652627d0100175 100644 (file)
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use adt;
-use adt::GetDtorType; // for tcx.dtor_type()
 use base::*;
 use build::*;
-use callee::{Callee, ArgVals};
-use cleanup;
-use cleanup::CleanupMethods;
+use callee::{Callee};
 use common::*;
 use debuginfo::DebugLoc;
-use expr;
 use machine::*;
 use monomorphize;
 use trans_item::TransItem;
+use tvec;
 use type_of::{type_of, sizing_type_of, align_of};
 use type_::Type;
 use value::Value;
+use Disr;
 
 use arena::TypedArena;
 use syntax_pos::DUMMY_SP;
@@ -51,7 +49,7 @@ pub fn trans_exchange_free_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let def_id = langcall(bcx.tcx(), None, "", ExchangeFreeFnLangItem);
     let args = [PointerCast(bcx, v, Type::i8p(bcx.ccx())), size, align];
     Callee::def(bcx.ccx(), def_id, Substs::empty(bcx.tcx()))
-        .call(bcx, debug_loc, ArgVals(&args), None).bcx
+        .call(bcx, debug_loc, &args, None).bcx
 }
 
 pub fn trans_exchange_free<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
@@ -115,7 +113,7 @@ pub fn get_drop_glue_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     match t.sty {
         ty::TyBox(typ) if !type_needs_drop(tcx, typ)
                          && type_is_sized(tcx, typ) => {
-            tcx.normalizing_infer_ctxt(traits::Reveal::All).enter(|infcx| {
+            tcx.infer_ctxt(None, None, traits::Reveal::All).enter(|infcx| {
                 let layout = t.layout(&infcx).unwrap();
                 if layout.size(&tcx.data_layout).bytes() == 0 {
                     // `Box<ZeroSizeType>` does not allocate.
@@ -133,20 +131,18 @@ pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                            v: ValueRef,
                            t: Ty<'tcx>,
                            debug_loc: DebugLoc) -> Block<'blk, 'tcx> {
-    drop_ty_core(bcx, v, t, debug_loc, false, None)
+    drop_ty_core(bcx, v, t, debug_loc, false)
 }
 
 pub fn drop_ty_core<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                 v: ValueRef,
                                 t: Ty<'tcx>,
                                 debug_loc: DebugLoc,
-                                skip_dtor: bool,
-                                drop_hint: Option<cleanup::DropHintValue>)
+                                skip_dtor: bool)
                                 -> Block<'blk, 'tcx> {
     // NB: v is an *alias* of type t here, not a direct value.
-    debug!("drop_ty_core(t={:?}, skip_dtor={} drop_hint={:?})", t, skip_dtor, drop_hint);
+    debug!("drop_ty_core(t={:?}, skip_dtor={})", t, skip_dtor);
     let _icx = push_ctxt("drop_ty");
-    let mut bcx = bcx;
     if bcx.fcx.type_needs_drop(t) {
         let ccx = bcx.ccx();
         let g = if skip_dtor {
@@ -162,23 +158,8 @@ pub fn drop_ty_core<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             v
         };
 
-        match drop_hint {
-            Some(drop_hint) => {
-                let hint_val = load_ty(bcx, drop_hint.value(), bcx.tcx().types.u8);
-                let moved_val =
-                    C_integral(Type::i8(bcx.ccx()), adt::DTOR_MOVED_HINT as u64, false);
-                let may_need_drop =
-                    ICmp(bcx, llvm::IntNE, hint_val, moved_val, DebugLoc::None);
-                bcx = with_cond(bcx, may_need_drop, |cx| {
-                    Call(cx, glue, &[ptr], debug_loc);
-                    cx
-                })
-            }
-            None => {
-                // No drop-hint ==> call standard drop glue
-                Call(bcx, glue, &[ptr], debug_loc);
-            }
-        }
+        // No drop-hint ==> call standard drop glue
+        Call(bcx, glue, &[ptr], debug_loc);
     }
     bcx
 }
@@ -193,7 +174,7 @@ pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let vp = alloc_ty(bcx, t, "");
     call_lifetime_start(bcx, vp);
     store_ty(bcx, v, vp, t);
-    let bcx = drop_ty_core(bcx, vp, t, debug_loc, skip_dtor, None);
+    let bcx = drop_ty_core(bcx, vp, t, debug_loc, skip_dtor);
     call_lifetime_end(bcx, vp);
     bcx
 }
@@ -240,10 +221,6 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                     g,
                     TransItem::DropGlue(g).to_raw_string(),
                     ccx.codegen_unit().name());
-
-            ccx.stats().n_fallback_instantiations.set(ccx.stats()
-                                                         .n_fallback_instantiations
-                                                         .get() + 1);
         }
     }
 
@@ -273,7 +250,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     arena = TypedArena::new();
     fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &arena);
 
-    let bcx = fcx.init(false, None);
+    let bcx = fcx.init(false);
 
     ccx.stats().n_glues_created.set(ccx.stats().n_glues_created.get() + 1);
     // All glue functions take values passed *by alias*; this is a
@@ -288,40 +265,6 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     fcx.finish(bcx, DebugLoc::None);
 }
 
-
-fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
-                                      t: Ty<'tcx>,
-                                      struct_data: ValueRef)
-                                      -> Block<'blk, 'tcx> {
-    assert!(type_is_sized(bcx.tcx(), t), "Precondition: caller must ensure t is sized");
-
-    let repr = adt::represent_type(bcx.ccx(), t);
-    let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &repr, struct_data));
-    let loaded = load_ty(bcx, drop_flag.val, bcx.tcx().dtor_type());
-    let drop_flag_llty = type_of(bcx.fcx.ccx, bcx.tcx().dtor_type());
-    let init_val = C_integral(drop_flag_llty, adt::DTOR_NEEDED as u64, false);
-
-    let bcx = if !bcx.ccx().check_drop_flag_for_sanity() {
-        bcx
-    } else {
-        let drop_flag_llty = type_of(bcx.fcx.ccx, bcx.tcx().dtor_type());
-        let done_val = C_integral(drop_flag_llty, adt::DTOR_DONE as u64, false);
-        let not_init = ICmp(bcx, llvm::IntNE, loaded, init_val, DebugLoc::None);
-        let not_done = ICmp(bcx, llvm::IntNE, loaded, done_val, DebugLoc::None);
-        let drop_flag_neither_initialized_nor_cleared =
-            And(bcx, not_init, not_done, DebugLoc::None);
-        with_cond(bcx, drop_flag_neither_initialized_nor_cleared, |cx| {
-            let llfn = cx.ccx().get_intrinsic(&("llvm.debugtrap"));
-            Call(cx, llfn, &[], DebugLoc::None);
-            cx
-        })
-    };
-
-    let drop_flag_dtor_needed = ICmp(bcx, llvm::IntEQ, loaded, init_val, DebugLoc::None);
-    with_cond(bcx, drop_flag_dtor_needed, |cx| {
-        trans_struct_drop(cx, t, struct_data)
-    })
-}
 fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                  t: Ty<'tcx>,
                                  v0: ValueRef)
@@ -343,20 +286,23 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     // Issue #23611: schedule cleanup of contents, re-inspecting the
     // discriminant (if any) in case of variant swap in drop code.
-    bcx.fcx.schedule_drop_adt_contents(cleanup::CustomScope(contents_scope), v0, t);
+    bcx.fcx.schedule_drop_adt_contents(contents_scope, v0, t);
 
     let (sized_args, unsized_args);
     let args: &[ValueRef] = if type_is_sized(tcx, t) {
         sized_args = [v0];
         &sized_args
     } else {
-        unsized_args = [Load(bcx, expr::get_dataptr(bcx, v0)), Load(bcx, expr::get_meta(bcx, v0))];
+        unsized_args = [
+            Load(bcx, get_dataptr(bcx, v0)),
+            Load(bcx, get_meta(bcx, v0))
+        ];
         &unsized_args
     };
 
     let trait_ref = ty::Binder(ty::TraitRef {
         def_id: tcx.lang_items.drop_trait().unwrap(),
-        substs: Substs::new_trait(tcx, vec![], vec![], t)
+        substs: Substs::new_trait(tcx, t, &[])
     });
     let vtbl = match fulfill_obligation(bcx.ccx().shared(), DUMMY_SP, trait_ref) {
         traits::VtableImpl(data) => data,
@@ -364,7 +310,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     };
     let dtor_did = def.destructor().unwrap();
     bcx = Callee::def(bcx.ccx(), dtor_did, vtbl.substs)
-        .call(bcx, DebugLoc::None, ArgVals(args), None).bcx;
+        .call(bcx, DebugLoc::None, args, None).bcx;
 
     bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope)
 }
@@ -392,13 +338,22 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
         ty::TyStruct(def, substs) => {
             let ccx = bcx.ccx();
             // First get the size of all statically known fields.
-            // Don't use type_of::sizing_type_of because that expects t to be sized.
+            // Don't use type_of::sizing_type_of because that expects t to be sized,
+            // and it also rounds up to alignment, which we want to avoid,
+            // as the unsized field's alignment could be smaller.
             assert!(!t.is_simd());
-            let repr = adt::represent_type(ccx, t);
-            let sizing_type = adt::sizing_type_context_of(ccx, &repr, true);
-            debug!("DST {} sizing_type: {:?}", t, sizing_type);
-            let sized_size = llsize_of_alloc(ccx, sizing_type.prefix());
-            let sized_align = llalign_of_min(ccx, sizing_type.prefix());
+            let layout = ccx.layout_of(t);
+            debug!("DST {} layout: {:?}", t, layout);
+
+            let (sized_size, sized_align) = match *layout {
+                ty::layout::Layout::Univariant { ref variant, .. } => {
+                    (variant.min_size().bytes(), variant.align.abi())
+                }
+                _ => {
+                    bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}",
+                         t, layout);
+                }
+            };
             debug!("DST {} statically sized prefix size: {} align: {}",
                    t, sized_size, sized_align);
             let sized_size = C_uint(ccx, sized_size);
@@ -418,15 +373,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
             // here. But this is where the add would go.)
 
             // Return the sum of sizes and max of aligns.
-            let mut size = bcx.add(sized_size, unsized_size);
-
-            // Issue #27023: If there is a drop flag, *now* we add 1
-            // to the size.  (We can do this without adding any
-            // padding because drop flags do not have any alignment
-            // constraints.)
-            if sizing_type.needs_drop_flag() {
-                size = bcx.add(size, C_uint(bcx.ccx(), 1_u64));
-            }
+            let size = bcx.add(sized_size, unsized_size);
 
             // Choose max of two known alignments (combined value must
             // be aligned according to more restrictive of the two).
@@ -492,9 +439,6 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
     // must definitely check for special bit-patterns corresponding to
     // the special dtor markings.
 
-    let inttype = Type::int(bcx.ccx());
-    let dropped_pattern = C_integral(inttype, adt::DTOR_DONE_U64, false);
-
     match t.sty {
         ty::TyBox(content_ty) => {
             // Support for TyBox is built-in and its drop glue is
@@ -502,65 +446,28 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
             // a safe-guard, assert TyBox not used with TyContents.
             assert!(!skip_dtor);
             if !type_is_sized(bcx.tcx(), content_ty) {
-                let llval = expr::get_dataptr(bcx, v0);
+                let llval = get_dataptr(bcx, v0);
                 let llbox = Load(bcx, llval);
-                let llbox_as_usize = PtrToInt(bcx, llbox, Type::int(bcx.ccx()));
-                let drop_flag_not_dropped_already =
-                    ICmp(bcx, llvm::IntNE, llbox_as_usize, dropped_pattern, DebugLoc::None);
-                with_cond(bcx, drop_flag_not_dropped_already, |bcx| {
-                    let bcx = drop_ty(bcx, v0, content_ty, DebugLoc::None);
-                    let info = expr::get_meta(bcx, v0);
-                    let info = Load(bcx, info);
-                    let (llsize, llalign) =
-                        size_and_align_of_dst(&bcx.build(), content_ty, info);
-
-                    // `Box<ZeroSizeType>` does not allocate.
-                    let needs_free = ICmp(bcx,
-                                          llvm::IntNE,
-                                          llsize,
-                                          C_uint(bcx.ccx(), 0u64),
-                                          DebugLoc::None);
-                    with_cond(bcx, needs_free, |bcx| {
-                        trans_exchange_free_dyn(bcx, llbox, llsize, llalign, DebugLoc::None)
-                    })
+                let bcx = drop_ty(bcx, v0, content_ty, DebugLoc::None);
+                let info = get_meta(bcx, v0);
+                let info = Load(bcx, info);
+                let (llsize, llalign) =
+                    size_and_align_of_dst(&bcx.build(), content_ty, info);
+
+                // `Box<ZeroSizeType>` does not allocate.
+                let needs_free = ICmp(bcx,
+                                        llvm::IntNE,
+                                        llsize,
+                                        C_uint(bcx.ccx(), 0u64),
+                                        DebugLoc::None);
+                with_cond(bcx, needs_free, |bcx| {
+                    trans_exchange_free_dyn(bcx, llbox, llsize, llalign, DebugLoc::None)
                 })
             } else {
                 let llval = v0;
                 let llbox = Load(bcx, llval);
-                let llbox_as_usize = PtrToInt(bcx, llbox, inttype);
-                let drop_flag_not_dropped_already =
-                    ICmp(bcx, llvm::IntNE, llbox_as_usize, dropped_pattern, DebugLoc::None);
-                with_cond(bcx, drop_flag_not_dropped_already, |bcx| {
-                    let bcx = drop_ty(bcx, llbox, content_ty, DebugLoc::None);
-                    trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None)
-                })
-            }
-        }
-        ty::TyStruct(def, _) | ty::TyEnum(def, _) => {
-            match (def.dtor_kind(), skip_dtor) {
-                (ty::TraitDtor(true), false) => {
-                    // FIXME(16758) Since the struct is unsized, it is hard to
-                    // find the drop flag (which is at the end of the struct).
-                    // Lets just ignore the flag and pretend everything will be
-                    // OK.
-                    if type_is_sized(bcx.tcx(), t) {
-                        trans_struct_drop_flag(bcx, t, v0)
-                    } else {
-                        // Give the user a heads up that we are doing something
-                        // stupid and dangerous.
-                        bcx.sess().warn(&format!("Ignoring drop flag in destructor for {} \
-                                                 because the struct is unsized. See issue \
-                                                 #16758", t));
-                        trans_struct_drop(bcx, t, v0)
-                    }
-                }
-                (ty::TraitDtor(false), false) => {
-                    trans_struct_drop(bcx, t, v0)
-                }
-                (ty::NoDtor, _) | (_, true) => {
-                    // No dtor? Just the default case
-                    iter_structural_ty(bcx, v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, DebugLoc::None))
-                }
+                let bcx = drop_ty(bcx, llbox, content_ty, DebugLoc::None);
+                trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None)
             }
         }
         ty::TyTrait(..) => {
@@ -568,8 +475,8 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
             // versus without calling Drop::drop. Assert caller is
             // okay with always calling the Drop impl, if any.
             assert!(!skip_dtor);
-            let data_ptr = expr::get_dataptr(bcx, v0);
-            let vtable_ptr = Load(bcx, expr::get_meta(bcx, v0));
+            let data_ptr = get_dataptr(bcx, v0);
+            let vtable_ptr = Load(bcx, get_meta(bcx, v0));
             let dtor = Load(bcx, vtable_ptr);
             Call(bcx,
                  dtor,
@@ -577,15 +484,159 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
                  DebugLoc::None);
             bcx
         }
+        ty::TyStruct(def, _) | ty::TyEnum(def, _)
+                if def.dtor_kind().is_present() && !skip_dtor => {
+            trans_struct_drop(bcx, t, v0)
+        }
         _ => {
             if bcx.fcx.type_needs_drop(t) {
-                iter_structural_ty(bcx,
-                                   v0,
-                                   t,
-                                   |bb, vv, tt| drop_ty(bb, vv, tt, DebugLoc::None))
+                drop_structural_ty(bcx, v0, t)
             } else {
                 bcx
             }
         }
     }
 }
+
+// Iterates through the elements of a structural type, dropping them.
+fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
+                                  av: ValueRef,
+                                  t: Ty<'tcx>)
+                                  -> Block<'blk, 'tcx> {
+    let _icx = push_ctxt("drop_structural_ty");
+
+    fn iter_variant<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
+                                repr: &adt::Repr<'tcx>,
+                                av: adt::MaybeSizedValue,
+                                variant: ty::VariantDef<'tcx>,
+                                substs: &Substs<'tcx>)
+                                -> Block<'blk, 'tcx> {
+        let _icx = push_ctxt("iter_variant");
+        let tcx = cx.tcx();
+        let mut cx = cx;
+
+        for (i, field) in variant.fields.iter().enumerate() {
+            let arg = monomorphize::field_ty(tcx, substs, field);
+            cx = drop_ty(cx,
+                         adt::trans_field_ptr(cx, repr, av, Disr::from(variant.disr_val), i),
+                         arg, DebugLoc::None);
+        }
+        return cx;
+    }
+
+    let value = if type_is_sized(cx.tcx(), t) {
+        adt::MaybeSizedValue::sized(av)
+    } else {
+        let data = Load(cx, get_dataptr(cx, av));
+        let info = Load(cx, get_meta(cx, av));
+        adt::MaybeSizedValue::unsized_(data, info)
+    };
+
+    let mut cx = cx;
+    match t.sty {
+        ty::TyStruct(..) => {
+            let repr = adt::represent_type(cx.ccx(), t);
+            let VariantInfo { fields, discr } = VariantInfo::from_ty(cx.tcx(), t, None);
+            for (i, &Field(_, field_ty)) in fields.iter().enumerate() {
+                let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr::from(discr), i);
+
+                let val = if type_is_sized(cx.tcx(), field_ty) {
+                    llfld_a
+                } else {
+                    let scratch = alloc_ty(cx, field_ty, "__fat_ptr_iter");
+                    Store(cx, llfld_a, get_dataptr(cx, scratch));
+                    Store(cx, value.meta, get_meta(cx, scratch));
+                    scratch
+                };
+                cx = drop_ty(cx, val, field_ty, DebugLoc::None);
+            }
+        }
+        ty::TyClosure(_, ref substs) => {
+            let repr = adt::represent_type(cx.ccx(), t);
+            for (i, upvar_ty) in substs.upvar_tys.iter().enumerate() {
+                let llupvar = adt::trans_field_ptr(cx, &repr, value, Disr(0), i);
+                cx = drop_ty(cx, llupvar, upvar_ty, DebugLoc::None);
+            }
+        }
+        ty::TyArray(_, n) => {
+            let base = get_dataptr(cx, value.value);
+            let len = C_uint(cx.ccx(), n);
+            let unit_ty = t.sequence_element_type(cx.tcx());
+            cx = tvec::slice_for_each(cx, base, unit_ty, len,
+                |bb, vv| drop_ty(bb, vv, unit_ty, DebugLoc::None));
+        }
+        ty::TySlice(_) | ty::TyStr => {
+            let unit_ty = t.sequence_element_type(cx.tcx());
+            cx = tvec::slice_for_each(cx, value.value, unit_ty, value.meta,
+                |bb, vv| drop_ty(bb, vv, unit_ty, DebugLoc::None));
+        }
+        ty::TyTuple(ref args) => {
+            let repr = adt::represent_type(cx.ccx(), t);
+            for (i, arg) in args.iter().enumerate() {
+                let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr(0), i);
+                cx = drop_ty(cx, llfld_a, *arg, DebugLoc::None);
+            }
+        }
+        ty::TyEnum(en, substs) => {
+            let fcx = cx.fcx;
+            let ccx = fcx.ccx;
+
+            let repr = adt::represent_type(ccx, t);
+            let n_variants = en.variants.len();
+
+            // NB: we must hit the discriminant first so that structural
+            // comparison know not to proceed when the discriminants differ.
+
+            match adt::trans_switch(cx, &repr, av, false) {
+                (adt::BranchKind::Single, None) => {
+                    if n_variants != 0 {
+                        assert!(n_variants == 1);
+                        cx = iter_variant(cx, &repr, adt::MaybeSizedValue::sized(av),
+                                          &en.variants[0], substs);
+                    }
+                }
+                (adt::BranchKind::Switch, Some(lldiscrim_a)) => {
+                    cx = drop_ty(cx, lldiscrim_a, cx.tcx().types.isize, DebugLoc::None);
+
+                    // Create a fall-through basic block for the "else" case of
+                    // the switch instruction we're about to generate. Note that
+                    // we do **not** use an Unreachable instruction here, even
+                    // though most of the time this basic block will never be hit.
+                    //
+                    // When an enum is dropped it's contents are currently
+                    // overwritten to DTOR_DONE, which means the discriminant
+                    // could have changed value to something not within the actual
+                    // range of the discriminant. Currently this function is only
+                    // used for drop glue so in this case we just return quickly
+                    // from the outer function, and any other use case will only
+                    // call this for an already-valid enum in which case the `ret
+                    // void` will never be hit.
+                    let ret_void_cx = fcx.new_block("enum-iter-ret-void");
+                    RetVoid(ret_void_cx, DebugLoc::None);
+                    let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb, n_variants);
+                    let next_cx = fcx.new_block("enum-iter-next");
+
+                    for variant in &en.variants {
+                        let variant_cx = fcx.new_block(&format!("enum-iter-variant-{}",
+                                                                     &variant.disr_val
+                                                                             .to_string()));
+                        let case_val = adt::trans_case(cx, &repr, Disr::from(variant.disr_val));
+                        AddCase(llswitch, case_val, variant_cx.llbb);
+                        let variant_cx = iter_variant(variant_cx,
+                                                      &repr,
+                                                      value,
+                                                      variant,
+                                                      substs);
+                        Br(variant_cx, next_cx.llbb, DebugLoc::None);
+                    }
+                    cx = next_cx;
+                }
+                _ => ccx.sess().unimpl("value from adt::trans_switch in drop_structural_ty"),
+            }
+        }
+        _ => {
+            cx.sess().unimpl(&format!("type in drop_structural_ty: {}", t))
+        }
+    }
+    return cx;
+}
diff --git a/src/librustc_trans/inline.rs b/src/librustc_trans/inline.rs
deleted file mode 100644 (file)
index 8581fcc..0000000
+++ /dev/null
@@ -1,52 +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.
-
-use rustc::hir::def_id::DefId;
-use base::push_ctxt;
-use common::*;
-use monomorphize::Instance;
-
-use rustc::dep_graph::DepNode;
-
-fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option<DefId> {
-    debug!("instantiate_inline({:?})", fn_id);
-    let _icx = push_ctxt("instantiate_inline");
-    let tcx = ccx.tcx();
-    let _task = tcx.dep_graph.in_task(DepNode::TransInlinedItem(fn_id));
-
-    tcx.sess
-       .cstore
-       .maybe_get_item_ast(tcx, fn_id)
-       .map(|(_, inline_id)| {
-            tcx.map.local_def_id(inline_id)
-       })
-}
-
-pub fn get_local_instance(ccx: &CrateContext, fn_id: DefId)
-    -> Option<DefId> {
-    if let Some(_) = ccx.tcx().map.as_local_node_id(fn_id) {
-        Some(fn_id)
-    } else {
-        instantiate_inline(ccx, fn_id)
-    }
-}
-
-pub fn maybe_instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> DefId {
-    get_local_instance(ccx, fn_id).unwrap_or(fn_id)
-}
-
-pub fn maybe_inline_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                       instance: Instance<'tcx>) -> Instance<'tcx> {
-    let def_id = maybe_instantiate_inline(ccx, instance.def);
-    Instance {
-        def: def_id,
-        substs: instance.substs
-    }
-}
index ecee4705510595bc991844e1d79b48882acf5122..8bef7584db9e22639be49f5fd6ae451e1f96f468 100644 (file)
 use intrinsics::{self, Intrinsic};
 use libc;
 use llvm;
-use llvm::{ValueRef, TypeKind};
-use rustc::ty::subst::Substs;
+use llvm::{ValueRef};
 use abi::{Abi, FnType};
 use adt;
 use base::*;
 use build::*;
-use callee::{self, Callee};
-use cleanup;
-use cleanup::CleanupMethods;
 use common::*;
-use consts;
-use datum::*;
 use debuginfo::DebugLoc;
 use declare;
-use expr;
 use glue;
 use type_of;
 use machine;
 use Disr;
 use rustc::hir;
 use syntax::ast;
-use syntax::ptr::P;
 use syntax::parse::token;
 
 use rustc::session::Session;
-use rustc_const_eval::fatal_const_eval_err;
 use syntax_pos::{Span, DUMMY_SP};
 
 use std::cmp::Ordering;
@@ -98,8 +89,8 @@ fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
 pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                             callee_ty: Ty<'tcx>,
                                             fn_ty: &FnType,
-                                            args: callee::CallArgs<'a, 'tcx>,
-                                            dest: expr::Dest,
+                                            llargs: &[ValueRef],
+                                            llresult: ValueRef,
                                             call_debug_location: DebugLoc)
                                             -> Result<'blk, 'tcx> {
     let fcx = bcx.fcx;
@@ -120,217 +111,26 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
     let name = tcx.item_name(def_id).as_str();
 
     let span = match call_debug_location {
-        DebugLoc::At(_, span) | DebugLoc::ScopeAt(_, span) => span,
+        DebugLoc::ScopeAt(_, span) => span,
         DebugLoc::None => {
             span_bug!(fcx.span.unwrap_or(DUMMY_SP),
                       "intrinsic `{}` called with missing span", name);
         }
     };
 
-    let cleanup_scope = fcx.push_custom_cleanup_scope();
-
-    // For `transmute` we can just trans the input expr directly into dest
-    if name == "transmute" {
-        let llret_ty = type_of::type_of(ccx, ret_ty);
-        match args {
-            callee::ArgExprs(arg_exprs) => {
-                assert_eq!(arg_exprs.len(), 1);
-
-                let (in_type, out_type) = (substs.types[0],
-                                           substs.types[1]);
-                let llintype = type_of::type_of(ccx, in_type);
-                let llouttype = type_of::type_of(ccx, out_type);
-
-                let in_type_size = machine::llbitsize_of_real(ccx, llintype);
-                let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
-
-                if let ty::TyFnDef(def_id, substs, _) = in_type.sty {
-                    if out_type_size != 0 {
-                        // FIXME #19925 Remove this hack after a release cycle.
-                        let _ = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0]));
-                        let llfn = Callee::def(ccx, def_id, substs).reify(ccx).val;
-                        let llfnty = val_ty(llfn);
-                        let llresult = match dest {
-                            expr::SaveIn(d) => d,
-                            expr::Ignore => alloc_ty(bcx, out_type, "ret")
-                        };
-                        Store(bcx, llfn, PointerCast(bcx, llresult, llfnty.ptr_to()));
-                        if dest == expr::Ignore {
-                            bcx = glue::drop_ty(bcx, llresult, out_type,
-                                                call_debug_location);
-                        }
-                        fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
-                        fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope);
-                        return Result::new(bcx, llresult);
-                    }
-                }
-
-                // This should be caught by the intrinsicck pass
-                assert_eq!(in_type_size, out_type_size);
-
-                let nonpointer_nonaggregate = |llkind: TypeKind| -> bool {
-                    use llvm::TypeKind::*;
-                    match llkind {
-                        Half | Float | Double | X86_FP80 | FP128 |
-                            PPC_FP128 | Integer | Vector | X86_MMX => true,
-                        _ => false
-                    }
-                };
-
-                // An approximation to which types can be directly cast via
-                // LLVM's bitcast.  This doesn't cover pointer -> pointer casts,
-                // but does, importantly, cover SIMD types.
-                let in_kind = llintype.kind();
-                let ret_kind = llret_ty.kind();
-                let bitcast_compatible =
-                    (nonpointer_nonaggregate(in_kind) && nonpointer_nonaggregate(ret_kind)) || {
-                        in_kind == TypeKind::Pointer && ret_kind == TypeKind::Pointer
-                    };
-
-                let dest = if bitcast_compatible {
-                    // if we're here, the type is scalar-like (a primitive, a
-                    // SIMD type or a pointer), and so can be handled as a
-                    // by-value ValueRef and can also be directly bitcast to the
-                    // target type.  Doing this special case makes conversions
-                    // like `u32x4` -> `u64x2` much nicer for LLVM and so more
-                    // efficient (these are done efficiently implicitly in C
-                    // with the `__m128i` type and so this means Rust doesn't
-                    // lose out there).
-                    let expr = &arg_exprs[0];
-                    let datum = unpack_datum!(bcx, expr::trans(bcx, expr));
-                    let datum = unpack_datum!(bcx, datum.to_rvalue_datum(bcx, "transmute_temp"));
-                    let val = if datum.kind.is_by_ref() {
-                        load_ty(bcx, datum.val, datum.ty)
-                    } else {
-                        from_immediate(bcx, datum.val)
-                    };
-
-                    let cast_val = BitCast(bcx, val, llret_ty);
-
-                    match dest {
-                        expr::SaveIn(d) => {
-                            // this often occurs in a sequence like `Store(val,
-                            // d); val2 = Load(d)`, so disappears easily.
-                            Store(bcx, cast_val, d);
-                        }
-                        expr::Ignore => {}
-                    }
-                    dest
-                } else {
-                    // The types are too complicated to do with a by-value
-                    // bitcast, so pointer cast instead. We need to cast the
-                    // dest so the types work out.
-                    let dest = match dest {
-                        expr::SaveIn(d) => expr::SaveIn(PointerCast(bcx, d, llintype.ptr_to())),
-                        expr::Ignore => expr::Ignore
-                    };
-                    bcx = expr::trans_into(bcx, &arg_exprs[0], dest);
-                    dest
-                };
-
-                fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
-                fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope);
-
-                return match dest {
-                    expr::SaveIn(d) => Result::new(bcx, d),
-                    expr::Ignore => Result::new(bcx, C_undef(llret_ty.ptr_to()))
-                };
-
-            }
-
-            _ => {
-                bug!("expected expr as argument for transmute");
-            }
-        }
-    }
-
-    // For `move_val_init` we can evaluate the destination address
-    // (the first argument) and then trans the source value (the
-    // second argument) directly into the resulting destination
-    // address.
-    if name == "move_val_init" {
-        if let callee::ArgExprs(ref exprs) = args {
-            let (dest_expr, source_expr) = if exprs.len() != 2 {
-                bug!("expected two exprs as arguments for `move_val_init` intrinsic");
-            } else {
-                (&exprs[0], &exprs[1])
-            };
-
-            // evaluate destination address
-            let dest_datum = unpack_datum!(bcx, expr::trans(bcx, dest_expr));
-            let dest_datum = unpack_datum!(
-                bcx, dest_datum.to_rvalue_datum(bcx, "arg"));
-            let dest_datum = unpack_datum!(
-                bcx, dest_datum.to_appropriate_datum(bcx));
-
-            // `expr::trans_into(bcx, expr, dest)` is equiv to
-            //
-            //    `trans(bcx, expr).store_to_dest(dest)`,
-            //
-            // which for `dest == expr::SaveIn(addr)`, is equivalent to:
-            //
-            //    `trans(bcx, expr).store_to(bcx, addr)`.
-            let lldest = expr::Dest::SaveIn(dest_datum.val);
-            bcx = expr::trans_into(bcx, source_expr, lldest);
-
-            let llresult = C_nil(ccx);
-            fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope);
-
-            return Result::new(bcx, llresult);
-        } else {
-            bug!("expected two exprs as arguments for `move_val_init` intrinsic");
-        }
-    }
-
-    // save the actual AST arguments for later (some places need to do
-    // const-evaluation on them)
-    let expr_arguments = match args {
-        callee::ArgExprs(args) => Some(args),
-        _ => None,
-    };
-
-    // Push the arguments.
-    let mut llargs = Vec::new();
-    bcx = callee::trans_args(bcx,
-                             Abi::RustIntrinsic,
-                             fn_ty,
-                             &mut callee::Intrinsic,
-                             args,
-                             &mut llargs,
-                             cleanup::CustomScope(cleanup_scope));
-
-    fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
-
     // These are the only intrinsic functions that diverge.
     if name == "abort" {
         let llfn = ccx.get_intrinsic(&("llvm.trap"));
         Call(bcx, llfn, &[], call_debug_location);
-        fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope);
         Unreachable(bcx);
         return Result::new(bcx, C_undef(Type::nil(ccx).ptr_to()));
     } else if &name[..] == "unreachable" {
-        fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope);
         Unreachable(bcx);
         return Result::new(bcx, C_nil(ccx));
     }
 
     let llret_ty = type_of::type_of(ccx, ret_ty);
 
-    // Get location to store the result. If the user does
-    // not care about the result, just make a stack slot
-    let llresult = match dest {
-        expr::SaveIn(d) => d,
-        expr::Ignore => {
-            if !type_is_zero_size(ccx, ret_ty) {
-                let llresult = alloc_ty(bcx, ret_ty, "intrinsic_result");
-                call_lifetime_start(bcx, llresult);
-                llresult
-            } else {
-                C_undef(llret_ty.ptr_to())
-            }
-        }
-    };
-
     let simple = get_simple_intrinsic(ccx, &name);
     let llval = match (simple, &name[..]) {
         (Some(llfn), _) => {
@@ -346,12 +146,12 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             Call(bcx, llfn, &[], call_debug_location)
         }
         (_, "size_of") => {
-            let tp_ty = substs.types[0];
+            let tp_ty = substs.type_at(0);
             let lltp_ty = type_of::type_of(ccx, tp_ty);
             C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
         }
         (_, "size_of_val") => {
-            let tp_ty = substs.types[0];
+            let tp_ty = substs.type_at(0);
             if !type_is_sized(tcx, tp_ty) {
                 let (llsize, _) =
                     glue::size_and_align_of_dst(&bcx.build(), tp_ty, llargs[1]);
@@ -362,11 +162,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             }
         }
         (_, "min_align_of") => {
-            let tp_ty = substs.types[0];
+            let tp_ty = substs.type_at(0);
             C_uint(ccx, type_of::align_of(ccx, tp_ty))
         }
         (_, "min_align_of_val") => {
-            let tp_ty = substs.types[0];
+            let tp_ty = substs.type_at(0);
             if !type_is_sized(tcx, tp_ty) {
                 let (_, llalign) =
                     glue::size_and_align_of_dst(&bcx.build(), tp_ty, llargs[1]);
@@ -376,41 +176,38 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             }
         }
         (_, "pref_align_of") => {
-            let tp_ty = substs.types[0];
+            let tp_ty = substs.type_at(0);
             let lltp_ty = type_of::type_of(ccx, tp_ty);
             C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty))
         }
         (_, "drop_in_place") => {
-            let tp_ty = substs.types[0];
-            let ptr = if type_is_sized(tcx, tp_ty) {
+            let tp_ty = substs.type_at(0);
+            let is_sized = type_is_sized(tcx, tp_ty);
+            let ptr = if is_sized {
                 llargs[0]
             } else {
-                let scratch = rvalue_scratch_datum(bcx, tp_ty, "tmp");
-                Store(bcx, llargs[0], expr::get_dataptr(bcx, scratch.val));
-                Store(bcx, llargs[1], expr::get_meta(bcx, scratch.val));
-                fcx.schedule_lifetime_end(cleanup::CustomScope(cleanup_scope), scratch.val);
-                scratch.val
+                let scratch = alloc_ty(bcx, tp_ty, "drop");
+                call_lifetime_start(bcx, scratch);
+                Store(bcx, llargs[0], get_dataptr(bcx, scratch));
+                Store(bcx, llargs[1], get_meta(bcx, scratch));
+                scratch
             };
             glue::drop_ty(bcx, ptr, tp_ty, call_debug_location);
+            if !is_sized {
+                call_lifetime_end(bcx, ptr);
+            }
             C_nil(ccx)
         }
         (_, "type_name") => {
-            let tp_ty = substs.types[0];
+            let tp_ty = substs.type_at(0);
             let ty_name = token::intern_and_get_ident(&tp_ty.to_string());
             C_str_slice(ccx, ty_name)
         }
         (_, "type_id") => {
-            C_u64(ccx, ccx.tcx().type_id_hash(substs.types[0]))
-        }
-        (_, "init_dropped") => {
-            let tp_ty = substs.types[0];
-            if !type_is_zero_size(ccx, tp_ty) {
-                drop_done_fill_mem(bcx, llresult, tp_ty);
-            }
-            C_nil(ccx)
+            C_u64(ccx, ccx.tcx().type_id_hash(substs.type_at(0)))
         }
         (_, "init") => {
-            let tp_ty = substs.types[0];
+            let tp_ty = substs.type_at(0);
             if !type_is_zero_size(ccx, tp_ty) {
                 // Just zero out the stack slot. (See comment on base::memzero for explanation)
                 init_zero_mem(bcx, llresult, tp_ty);
@@ -422,7 +219,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             C_nil(ccx)
         }
         (_, "needs_drop") => {
-            let tp_ty = substs.types[0];
+            let tp_ty = substs.type_at(0);
 
             C_bool(ccx, bcx.fcx.type_needs_drop(tp_ty))
         }
@@ -441,7 +238,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             copy_intrinsic(bcx,
                            false,
                            false,
-                           substs.types[0],
+                           substs.type_at(0),
                            llargs[1],
                            llargs[0],
                            llargs[2],
@@ -451,7 +248,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             copy_intrinsic(bcx,
                            true,
                            false,
-                           substs.types[0],
+                           substs.type_at(0),
                            llargs[1],
                            llargs[0],
                            llargs[2],
@@ -460,7 +257,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         (_, "write_bytes") => {
             memset_intrinsic(bcx,
                              false,
-                             substs.types[0],
+                             substs.type_at(0),
                              llargs[0],
                              llargs[1],
                              llargs[2],
@@ -471,7 +268,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             copy_intrinsic(bcx,
                            false,
                            true,
-                           substs.types[0],
+                           substs.type_at(0),
                            llargs[0],
                            llargs[1],
                            llargs[2],
@@ -481,7 +278,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             copy_intrinsic(bcx,
                            true,
                            true,
-                           substs.types[0],
+                           substs.type_at(0),
                            llargs[0],
                            llargs[1],
                            llargs[2],
@@ -490,14 +287,14 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         (_, "volatile_set_memory") => {
             memset_intrinsic(bcx,
                              true,
-                             substs.types[0],
+                             substs.type_at(0),
                              llargs[0],
                              llargs[1],
                              llargs[2],
                              call_debug_location)
         }
         (_, "volatile_load") => {
-            let tp_ty = substs.types[0];
+            let tp_ty = substs.type_at(0);
             let mut ptr = llargs[0];
             if let Some(ty) = fn_ty.ret.cast {
                 ptr = PointerCast(bcx, ptr, ty.ptr_to());
@@ -509,10 +306,10 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             to_immediate(bcx, load, tp_ty)
         },
         (_, "volatile_store") => {
-            let tp_ty = substs.types[0];
+            let tp_ty = substs.type_at(0);
             if type_is_fat_ptr(bcx.tcx(), tp_ty) {
-                VolatileStore(bcx, llargs[1], expr::get_dataptr(bcx, llargs[0]));
-                VolatileStore(bcx, llargs[2], expr::get_meta(bcx, llargs[0]));
+                VolatileStore(bcx, llargs[1], get_dataptr(bcx, llargs[0]));
+                VolatileStore(bcx, llargs[2], get_meta(bcx, llargs[0]));
             } else {
                 let val = if fn_ty.args[1].is_indirect() {
                     Load(bcx, llargs[1])
@@ -609,7 +406,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         },
 
         (_, "discriminant_value") => {
-            let val_ty = substs.types[0];
+            let val_ty = substs.type_at(0);
             match val_ty.sty {
                 ty::TyEnum(..) => {
                     let repr = adt::represent_type(ccx, val_ty);
@@ -621,9 +418,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         }
         (_, name) if name.starts_with("simd_") => {
             generic_simd_intrinsic(bcx, name,
-                                   substs,
                                    callee_ty,
-                                   expr_arguments,
                                    &llargs,
                                    ret_ty, llret_ty,
                                    call_debug_location,
@@ -663,7 +458,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
             match split[1] {
                 "cxchg" | "cxchgweak" => {
-                    let sty = &substs.types[0].sty;
+                    let sty = &substs.type_at(0).sty;
                     if int_type_width_signed(sty, ccx).is_some() {
                         let weak = if split[1] == "cxchgweak" { llvm::True } else { llvm::False };
                         let val = AtomicCmpXchg(bcx, llargs[0], llargs[1], llargs[2],
@@ -682,7 +477,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                 }
 
                 "load" => {
-                    let sty = &substs.types[0].sty;
+                    let sty = &substs.type_at(0).sty;
                     if int_type_width_signed(sty, ccx).is_some() {
                         AtomicLoad(bcx, llargs[0], order)
                     } else {
@@ -695,7 +490,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                 }
 
                 "store" => {
-                    let sty = &substs.types[0].sty;
+                    let sty = &substs.type_at(0).sty;
                     if int_type_width_signed(sty, ccx).is_some() {
                         AtomicStore(bcx, llargs[1], llargs[0], order);
                     } else {
@@ -734,7 +529,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                         _ => ccx.sess().fatal("unknown atomic operation")
                     };
 
-                    let sty = &substs.types[0].sty;
+                    let sty = &substs.type_at(0).sty;
                     if int_type_width_signed(sty, ccx).is_some() {
                         AtomicRMW(bcx, atom_op, llargs[0], llargs[1], order)
                     } else {
@@ -868,13 +663,13 @@ fn modify_as_needed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
             let llargs = if !any_changes_needed {
                 // no aggregates to flatten, so no change needed
-                llargs
+                llargs.to_vec()
             } else {
                 // there are some aggregates that need to be flattened
                 // in the LLVM call, so we need to run over the types
                 // again to find them and extract the arguments
                 intr.inputs.iter()
-                           .zip(&llargs)
+                           .zip(llargs)
                            .zip(&arg_tys)
                            .flat_map(|((t, llarg), ty)| modify_as_needed(bcx, t, ty, *llarg))
                            .collect()
@@ -919,17 +714,6 @@ fn modify_as_needed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         }
     }
 
-    // If we made a temporary stack slot, let's clean it up
-    match dest {
-        expr::Ignore => {
-            bcx = glue::drop_ty(bcx, llresult, ret_ty, call_debug_location);
-            call_lifetime_end(bcx, llresult);
-        }
-        expr::SaveIn(_) => {}
-    }
-
-    fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope);
-
     Result::new(bcx, llresult)
 }
 
@@ -1064,10 +848,10 @@ fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
         SetPersonalityFn(bcx, bcx.fcx.eh_personality());
 
-        let normal = bcx.fcx.new_temp_block("normal");
-        let catchswitch = bcx.fcx.new_temp_block("catchswitch");
-        let catchpad = bcx.fcx.new_temp_block("catchpad");
-        let caught = bcx.fcx.new_temp_block("caught");
+        let normal = bcx.fcx.new_block("normal");
+        let catchswitch = bcx.fcx.new_block("catchswitch");
+        let catchpad = bcx.fcx.new_block("catchpad");
+        let caught = bcx.fcx.new_block("caught");
 
         let func = llvm::get_param(bcx.fcx.llfn, 0);
         let data = llvm::get_param(bcx.fcx.llfn, 1);
@@ -1123,7 +907,7 @@ fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
         let tcx = ccx.tcx();
         let tydesc = match tcx.lang_items.msvc_try_filter() {
-            Some(did) => ::consts::get_static(ccx, did).to_llref(),
+            Some(did) => ::consts::get_static(ccx, did),
             None => bug!("msvc_try_filter not defined"),
         };
         let tok = CatchPad(catchpad, cs, &[tydesc, C_i32(ccx, 0), slot]);
@@ -1184,8 +968,8 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         // expected to be `*mut *mut u8` for this to actually work, but that's
         // managed by the standard library.
 
-        let then = bcx.fcx.new_temp_block("then");
-        let catch = bcx.fcx.new_temp_block("catch");
+        let then = bcx.fcx.new_block("then");
+        let catch = bcx.fcx.new_block("catch");
 
         let func = llvm::get_param(bcx.fcx.llfn, 0);
         let data = llvm::get_param(bcx.fcx.llfn, 1);
@@ -1240,8 +1024,7 @@ fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
     let (fcx, block_arena);
     block_arena = TypedArena::new();
     fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &block_arena);
-    let bcx = fcx.init(true, None);
-    trans(bcx);
+    trans(fcx.init(true));
     fcx.cleanup();
     llfn
 }
@@ -1283,9 +1066,7 @@ fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
 fn generic_simd_intrinsic<'blk, 'tcx, 'a>
     (bcx: Block<'blk, 'tcx>,
      name: &str,
-     substs: &'tcx Substs<'tcx>,
      callee_ty: Ty<'tcx>,
-     args: Option<&[P<hir::Expr>]>,
      llargs: &[ValueRef],
      ret_ty: Ty<'tcx>,
      llret_ty: Type,
@@ -1386,20 +1167,7 @@ macro_rules! require_simd {
 
         let total_len = in_len as u64 * 2;
 
-        let vector = match args {
-            Some(args) => {
-                match consts::const_expr(bcx.ccx(), &args[2], substs, None,
-                                         // this should probably help simd error reporting
-                                         consts::TrueConst::Yes) {
-                    Ok((vector, _)) => vector,
-                    Err(err) => {
-                        fatal_const_eval_err(bcx.tcx(), err.as_inner(), span,
-                                             "shuffle indices");
-                    }
-                }
-            }
-            None => llargs[2]
-        };
+        let vector = llargs[2];
 
         let indices: Option<Vec<_>> = (0..n)
             .map(|i| {
index 81a1dbeb7fe74db7431b49909611326134d1d58c..6ede55d5ff49af1bccc8c917cb9812809ad476d9 100644 (file)
@@ -98,6 +98,7 @@ pub mod back {
 mod cabi_arm;
 mod cabi_asmjs;
 mod cabi_mips;
+mod cabi_mips64;
 mod cabi_powerpc;
 mod cabi_powerpc64;
 mod cabi_x86;
@@ -110,17 +111,12 @@ pub mod back {
 mod common;
 mod consts;
 mod context;
-mod controlflow;
-mod datum;
 mod debuginfo;
 mod declare;
 mod disr;
-mod expr;
 mod glue;
-mod inline;
 mod intrinsic;
 mod machine;
-mod _match;
 mod meth;
 mod mir;
 mod monomorphize;
index b051028ebda6b6036f880752e352163c1f6b0c31..e958795570eee1ed7fe72cd99bc7a411251666fb 100644 (file)
 use abi::FnType;
 use base::*;
 use build::*;
-use callee::{Callee, Virtual, ArgVals, trans_fn_pointer_shim};
+use callee::{Callee, Virtual, trans_fn_pointer_shim};
 use closure;
 use common::*;
 use consts;
 use debuginfo::DebugLoc;
 use declare;
-use expr;
 use glue;
 use machine;
 use type_::Type;
@@ -96,25 +95,21 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
     let (block_arena, fcx): (TypedArena<_>, FunctionContext);
     block_arena = TypedArena::new();
     fcx = FunctionContext::new(ccx, llfn, fn_ty, None, &block_arena);
-    let mut bcx = fcx.init(false, None);
-    assert!(!fcx.needs_ret_allocas);
+    let mut bcx = fcx.init(false);
 
-
-    let dest =
-        fcx.llretslotptr.get().map(
-            |_| expr::SaveIn(fcx.get_ret_slot(bcx, "ret_slot")));
+    let dest = fcx.llretslotptr.get();
 
     debug!("trans_object_shim: method_offset_in_vtable={}",
            vtable_index);
 
     let llargs = get_params(fcx.llfn);
-    let args = ArgVals(&llargs[fcx.fn_ty.ret.is_indirect() as usize..]);
 
     let callee = Callee {
         data: Virtual(vtable_index),
         ty: method_ty
     };
-    bcx = callee.call(bcx, DebugLoc::None, args, dest).bcx;
+    bcx = callee.call(bcx, DebugLoc::None,
+                      &llargs[fcx.fn_ty.ret.is_indirect() as usize..], dest).bcx;
 
     fcx.finish(bcx, DebugLoc::None);
 
@@ -160,7 +155,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                 get_vtable_methods(tcx, id, substs)
                     .into_iter()
                     .map(|opt_mth| opt_mth.map_or(nullptr, |mth| {
-                        Callee::def(ccx, mth.method.def_id, &mth.substs).reify(ccx).val
+                        Callee::def(ccx, mth.method.def_id, &mth.substs).reify(ccx)
                     }))
                     .collect::<Vec<_>>()
                     .into_iter()
@@ -270,7 +265,7 @@ pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             // the method may have some early-bound lifetimes, add
             // regions for those
             let method_substs = Substs::for_item(tcx, trait_method_def_id,
-                                                 |_, _| ty::ReErased,
+                                                 |_, _| tcx.mk_region(ty::ReErased),
                                                  |_, _| tcx.types.err);
 
             // The substitutions we have are on the impl, so we grab
@@ -312,14 +307,14 @@ pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                  name: Name)
                                  -> ImplMethod<'tcx>
 {
-    assert!(!substs.types.needs_infer());
+    assert!(!substs.needs_infer());
 
     let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
     let trait_def = tcx.lookup_trait_def(trait_def_id);
 
     match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() {
         Some(node_item) => {
-            let substs = tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
+            let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
                 let substs = substs.rebase_onto(tcx, trait_def_id, impl_substs);
                 let substs = traits::translate_substs(&infcx, impl_def_id,
                                                       substs, node_item.node);
index e0d959f4774a64e3a2952f85bb6dcf081f931025..cfd1ec09968616d7f118382e19809ef09c9d4852 100644 (file)
@@ -15,6 +15,7 @@
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use rustc::mir::repr as mir;
 use rustc::mir::repr::TerminatorKind;
+use rustc::mir::repr::Location;
 use rustc::mir::visit::{Visitor, LvalueContext};
 use rustc::mir::traversal;
 use common::{self, Block, BlockAndBuilder};
@@ -48,6 +49,12 @@ pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
                     common::type_is_fat_ptr(bcx.tcx(), ty));
         } else if common::type_is_imm_pair(bcx.ccx(), ty) {
             // We allow pairs and uses of any of their 2 fields.
+        } else if !analyzer.seen_assigned.contains(index) {
+            // No assignment has been seen, which means that
+            // either the local has been marked as lvalue
+            // already, or there is no possible initialization
+            // for the local, making any reads invalid.
+            // This is useful in weeding out dead temps.
         } else {
             // These sorts of types require an alloca. Note that
             // type_is_immediate() may *still* be true, particularly
@@ -98,7 +105,8 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
     fn visit_assign(&mut self,
                     block: mir::BasicBlock,
                     lvalue: &mir::Lvalue<'tcx>,
-                    rvalue: &mir::Rvalue<'tcx>) {
+                    rvalue: &mir::Rvalue<'tcx>,
+                    location: Location) {
         debug!("visit_assign(block={:?}, lvalue={:?}, rvalue={:?})", block, lvalue, rvalue);
 
         if let Some(index) = self.mir.local_index(lvalue) {
@@ -107,15 +115,16 @@ fn visit_assign(&mut self,
                 self.mark_as_lvalue(index);
             }
         } else {
-            self.visit_lvalue(lvalue, LvalueContext::Store);
+            self.visit_lvalue(lvalue, LvalueContext::Store, location);
         }
 
-        self.visit_rvalue(rvalue);
+        self.visit_rvalue(rvalue, location);
     }
 
     fn visit_terminator_kind(&mut self,
                              block: mir::BasicBlock,
-                             kind: &mir::TerminatorKind<'tcx>) {
+                             kind: &mir::TerminatorKind<'tcx>,
+                             location: Location) {
         match *kind {
             mir::TerminatorKind::Call {
                 func: mir::Operand::Constant(mir::Constant {
@@ -127,18 +136,19 @@ fn visit_terminator_kind(&mut self,
                 // is not guaranteed to be statically dominated by the
                 // definition of x, so x must always be in an alloca.
                 if let mir::Operand::Consume(ref lvalue) = args[0] {
-                    self.visit_lvalue(lvalue, LvalueContext::Drop);
+                    self.visit_lvalue(lvalue, LvalueContext::Drop, location);
                 }
             }
             _ => {}
         }
 
-        self.super_terminator_kind(block, kind);
+        self.super_terminator_kind(block, kind, location);
     }
 
     fn visit_lvalue(&mut self,
                     lvalue: &mir::Lvalue<'tcx>,
-                    context: LvalueContext) {
+                    context: LvalueContext,
+                    location: Location) {
         debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context);
 
         // Allow uses of projections of immediate pair fields.
@@ -190,11 +200,11 @@ fn visit_lvalue(&mut self,
         // A deref projection only reads the pointer, never needs the lvalue.
         if let mir::Lvalue::Projection(ref proj) = *lvalue {
             if let mir::ProjectionElem::Deref = proj.elem {
-                return self.visit_lvalue(&proj.base, LvalueContext::Consume);
+                return self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
             }
         }
 
-        self.super_lvalue(lvalue, context);
+        self.super_lvalue(lvalue, context, location);
     }
 }
 
index 56d02fa1fac4fbc02bdfe337ff48f77607b2e7dd..3ab4290e7b9b98284492cca8f107de83cc051593 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use llvm::{self, ValueRef};
-use rustc_const_eval::ErrKind;
+use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
 use rustc::middle::lang_items;
 use rustc::ty;
 use rustc::mir::repr as mir;
@@ -78,7 +78,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
 
                         debug!("llblock: creating cleanup trampoline for {:?}", target);
                         let name = &format!("{:?}_cleanup_trampoline_{:?}", bb, target);
-                        let trampoline = this.fcx.new_block(name, None).build();
+                        let trampoline = this.fcx.new_block(name).build();
                         trampoline.set_personality_fn(this.fcx.eh_personality());
                         trampoline.cleanup_ret(cp, Some(lltarget));
                         trampoline.llbb()
@@ -291,7 +291,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
 
                 // Create the failure block and the conditional branch to it.
                 let lltarget = llblock(self, target);
-                let panic_block = self.fcx.new_block("panic", None);
+                let panic_block = self.fcx.new_block("panic");
                 if expected {
                     bcx.cond_br(cond, lltarget, panic_block.llbb);
                 } else {
@@ -354,9 +354,11 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                 // is also constant, then we can produce a warning.
                 if const_cond == Some(!expected) {
                     if let Some(err) = const_err {
-                        let _ = consts::const_err(bcx.ccx(), span,
-                                                  Err::<(), _>(err),
-                                                  consts::TrueConst::No);
+                        let err = ConstEvalErr{ span: span, kind: err };
+                        let mut diag = bcx.tcx().sess.struct_span_warn(
+                            span, "this expression will panic at run-time");
+                        note_const_eval_err(bcx.tcx(), &err, span, "expression", &mut diag);
+                        diag.emit();
                     }
                 }
 
@@ -364,7 +366,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                 let def_id = common::langcall(bcx.tcx(), Some(span), "", lang_item);
                 let callee = Callee::def(bcx.ccx(), def_id,
                     bcx.ccx().empty_substs_for_def_id(def_id));
-                let llfn = callee.reify(bcx.ccx()).val;
+                let llfn = callee.reify(bcx.ccx());
 
                 // Translate the actual panic invoke/call.
                 if let Some(unwind) = cleanup {
@@ -497,28 +499,27 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                 let fn_ptr = match callee.data {
                     NamedTupleConstructor(_) => {
                         // FIXME translate this like mir::Rvalue::Aggregate.
-                        callee.reify(bcx.ccx()).val
+                        callee.reify(bcx.ccx())
                     }
                     Intrinsic => {
-                        use callee::ArgVals;
-                        use expr::{Ignore, SaveIn};
                         use intrinsic::trans_intrinsic_call;
 
                         let (dest, llargs) = match ret_dest {
                             _ if fn_ty.ret.is_indirect() => {
-                                (SaveIn(llargs[0]), &llargs[1..])
+                                (llargs[0], &llargs[1..])
+                            }
+                            ReturnDest::Nothing => {
+                                (C_undef(fn_ty.ret.original_ty.ptr_to()), &llargs[..])
                             }
-                            ReturnDest::Nothing => (Ignore, &llargs[..]),
                             ReturnDest::IndirectOperand(dst, _) |
-                            ReturnDest::Store(dst) => (SaveIn(dst), &llargs[..]),
+                            ReturnDest::Store(dst) => (dst, &llargs[..]),
                             ReturnDest::DirectOperand(_) =>
                                 bug!("Cannot use direct operand with an intrinsic call")
                         };
 
                         bcx.with_block(|bcx| {
                             trans_intrinsic_call(bcx, callee.ty, &fn_ty,
-                                                           ArgVals(llargs), dest,
-                                                           debug_loc);
+                                                 &llargs, dest, debug_loc);
                         });
 
                         if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
@@ -766,7 +767,7 @@ fn landing_pad_to(&mut self, target_bb: mir::BasicBlock) -> Block<'bcx, 'tcx>
 
         let target = self.bcx(target_bb);
 
-        let block = self.fcx.new_block("cleanup", None);
+        let block = self.fcx.new_block("cleanup");
         self.landing_pads[target_bb] = Some(block);
 
         let bcx = block.build();
@@ -809,7 +810,7 @@ pub fn init_cpad(&mut self, bb: mir::BasicBlock) {
 
     fn unreachable_block(&mut self) -> Block<'bcx, 'tcx> {
         self.unreachable_block.unwrap_or_else(|| {
-            let bl = self.fcx.new_block("unreachable", None);
+            let bl = self.fcx.new_block("unreachable");
             bl.build().unreachable();
             self.unreachable_block = Some(bl);
             bl
@@ -878,10 +879,13 @@ fn trans_transmute(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>,
             if out_type_size != 0 {
                 // FIXME #19925 Remove this hack after a release cycle.
                 let f = Callee::def(bcx.ccx(), def_id, substs);
-                let datum = f.reify(bcx.ccx());
+                let ty = match f.ty.sty {
+                    ty::TyFnDef(_, _, f) => bcx.tcx().mk_fn_ptr(f),
+                    _ => f.ty
+                };
                 val = OperandRef {
-                    val: Immediate(datum.val),
-                    ty: datum.ty
+                    val: Immediate(f.reify(bcx.ccx())),
+                    ty: ty
                 };
             }
         }
index 4da973bb7f946ec2d5754d27b9aba4c7389857bd..ade266a580e7873ddb02b1b6d9110a26b39c49da 100644 (file)
 
 use llvm::{self, ValueRef};
 use rustc::middle::const_val::ConstVal;
-use rustc_const_eval::ErrKind;
+use rustc_const_eval::{ErrKind, ConstEvalErr, report_const_eval_err};
 use rustc_const_math::ConstInt::*;
 use rustc_const_math::ConstFloat::*;
-use rustc_const_math::ConstMathErr;
+use rustc_const_math::{ConstInt, ConstIsize, ConstUsize, ConstMathErr};
 use rustc::hir::def_id::DefId;
 use rustc::infer::TransNormalize;
 use rustc::mir::repr as mir;
 use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty};
 use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral};
 use common::{C_null, C_struct, C_str_slice, C_undef, C_uint};
-use consts::{self, ConstEvalFailure, TrueConst, to_const_int};
+use common::{const_to_opt_int, const_to_opt_uint};
+use consts;
 use monomorphize::{self, Instance};
 use type_of;
 use type_::Type;
 use value::Value;
 
+use syntax::ast;
 use syntax_pos::{Span, DUMMY_SP};
 
 use std::ptr;
@@ -230,7 +232,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>>)
-                 -> Result<Const<'tcx>, ConstEvalFailure> {
+                 -> Result<Const<'tcx>, ConstEvalErr> {
         // Try to resolve associated constants.
         if let Some(trait_id) = ccx.tcx().trait_of_item(instance.def) {
             let trait_ref = ty::TraitRef::new(trait_id, instance.substs);
@@ -256,12 +258,12 @@ fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
     fn monomorphize<T>(&self, value: &T) -> T
         where T: TransNormalize<'tcx>
     {
-        monomorphize::apply_param_substs(self.ccx.tcx(),
+        monomorphize::apply_param_substs(self.ccx.shared(),
                                          self.substs,
                                          value)
     }
 
-    fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalFailure> {
+    fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr> {
         let tcx = self.ccx.tcx();
         let mut bb = mir::START_BLOCK;
 
@@ -320,10 +322,10 @@ fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalFailure> {
                                 ErrKind::Math(err.clone())
                             }
                         };
-                        match consts::const_err(self.ccx, span, Err(err), TrueConst::Yes) {
-                            Ok(()) => {}
-                            Err(err) => if failure.is_ok() { failure = Err(err); }
-                        }
+
+                        let err = ConstEvalErr{ span: span, kind: err };
+                        report_const_eval_err(tcx, &err, span, "expression").emit();
+                        failure = Err(err);
                     }
                     target
                 }
@@ -370,7 +372,7 @@ fn store(&mut self, dest: &mir::Lvalue<'tcx>, value: Const<'tcx>, span: Span) {
     }
 
     fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
-                    -> Result<ConstLvalue<'tcx>, ConstEvalFailure> {
+                    -> Result<ConstLvalue<'tcx>, ConstEvalErr> {
         let tcx = self.ccx.tcx();
 
         if let Some(index) = self.mir.local_index(lvalue) {
@@ -386,7 +388,7 @@ fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
             mir::Lvalue::ReturnPointer => bug!(), // handled above
             mir::Lvalue::Static(def_id) => {
                 ConstLvalue {
-                    base: Base::Static(consts::get_static(self.ccx, def_id).val),
+                    base: Base::Static(consts::get_static(self.ccx, def_id)),
                     llextra: ptr::null_mut(),
                     ty: lvalue.ty(self.mir, tcx).to_ty(tcx)
                 }
@@ -411,11 +413,18 @@ fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
                         } else if let ty::TyStr = projected_ty.sty {
                             (Base::Str(base), extra)
                         } else {
-                            let val = consts::load_const(self.ccx, base, projected_ty);
+                            let v = base;
+                            let v = self.ccx.const_unsized().borrow().get(&v).map_or(v, |&v| v);
+                            let mut val = unsafe { llvm::LLVMGetInitializer(v) };
                             if val.is_null() {
                                 span_bug!(span, "dereference of non-constant pointer `{:?}`",
                                           Value(base));
                             }
+                            if projected_ty.is_bool() {
+                                unsafe {
+                                    val = llvm::LLVMConstTrunc(val, Type::i1(self.ccx).to_ref());
+                                }
+                            }
                             (Base::Value(val), extra)
                         }
                     }
@@ -462,7 +471,7 @@ fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
     }
 
     fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span)
-                     -> Result<Const<'tcx>, ConstEvalFailure> {
+                     -> Result<Const<'tcx>, ConstEvalErr> {
         match *operand {
             mir::Operand::Consume(ref lvalue) => {
                 Ok(self.const_lvalue(lvalue, span)?.to_const(span))
@@ -497,7 +506,7 @@ fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span)
 
     fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
                     dest_ty: Ty<'tcx>, span: Span)
-                    -> Result<Const<'tcx>, ConstEvalFailure> {
+                    -> Result<Const<'tcx>, ConstEvalErr> {
         let tcx = self.ccx.tcx();
         let val = match *rvalue {
             mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?,
@@ -565,7 +574,7 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
                         match operand.ty.sty {
                             ty::TyFnDef(def_id, substs, _) => {
                                 Callee::def(self.ccx, def_id, substs)
-                                    .reify(self.ccx).val
+                                    .reify(self.ccx)
                             }
                             _ => {
                                 span_bug!(span, "{} cannot be reified to a fn ptr",
@@ -782,6 +791,54 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
 
 }
 
+fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
+    match t.sty {
+        ty::TyInt(int_type) => const_to_opt_int(value).and_then(|input| match int_type {
+            ast::IntTy::I8 => {
+                assert_eq!(input as i8 as i64, input);
+                Some(ConstInt::I8(input as i8))
+            },
+            ast::IntTy::I16 => {
+                assert_eq!(input as i16 as i64, input);
+                Some(ConstInt::I16(input as i16))
+            },
+            ast::IntTy::I32 => {
+                assert_eq!(input as i32 as i64, input);
+                Some(ConstInt::I32(input as i32))
+            },
+            ast::IntTy::I64 => {
+                Some(ConstInt::I64(input))
+            },
+            ast::IntTy::Is => {
+                ConstIsize::new(input, tcx.sess.target.int_type)
+                    .ok().map(ConstInt::Isize)
+            },
+        }),
+        ty::TyUint(uint_type) => const_to_opt_uint(value).and_then(|input| match uint_type {
+            ast::UintTy::U8 => {
+                assert_eq!(input as u8 as u64, input);
+                Some(ConstInt::U8(input as u8))
+            },
+            ast::UintTy::U16 => {
+                assert_eq!(input as u16 as u64, input);
+                Some(ConstInt::U16(input as u16))
+            },
+            ast::UintTy::U32 => {
+                assert_eq!(input as u32 as u64, input);
+                Some(ConstInt::U32(input as u32))
+            },
+            ast::UintTy::U64 => {
+                Some(ConstInt::U64(input))
+            },
+            ast::UintTy::Us => {
+                ConstUsize::new(input, tcx.sess.target.uint_type)
+                    .ok().map(ConstInt::Usize)
+            },
+        }),
+        _ => None,
+    }
+}
+
 pub fn const_scalar_binop(op: mir::BinOp,
                           lhs: ValueRef,
                           rhs: ValueRef,
@@ -902,25 +959,17 @@ pub fn trans_constant(&mut self,
             }
         };
 
-        match result {
-            Ok(v) => v,
-            Err(ConstEvalFailure::Compiletime(_)) => {
-                // We've errored, so we don't have to produce working code.
-                let llty = type_of::type_of(bcx.ccx(), ty);
-                Const::new(C_undef(llty), ty)
-            }
-            Err(ConstEvalFailure::Runtime(err)) => {
-                span_bug!(constant.span,
-                          "MIR constant {:?} results in runtime panic: {:?}",
-                          constant, err.description())
-            }
-        }
+        result.unwrap_or_else(|_| {
+            // We've errored, so we don't have to produce working code.
+            let llty = type_of::type_of(bcx.ccx(), ty);
+            Const::new(C_undef(llty), ty)
+        })
     }
 }
 
 
 pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
-                                -> Result<ValueRef, ConstEvalFailure> {
+                                -> Result<ValueRef, ConstEvalErr> {
     let instance = Instance::mono(ccx.shared(), def_id);
     MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval)
 }
index 94db2e3c23cef29a965a16c4bb7feec768e9f3b7..5e180887a36043c3f14feab5639d6f52392ad8fc 100644 (file)
@@ -109,7 +109,7 @@ pub fn trans_lvalue(&mut self,
             mir::Lvalue::ReturnPointer => 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).val,
+                LvalueRef::new_sized(consts::get_static(ccx, def_id),
                                      LvalueTy::from_ty(const_ty))
             },
             mir::Lvalue::Projection(box mir::Projection {
index 727b680541dd7cf81579f2ce97e17982009beb0f..1934f7b870d187be0f06dbd18ca2b306a20c7570 100644 (file)
 
 use libc::c_uint;
 use llvm::{self, ValueRef};
-use llvm::debuginfo::DIScope;
 use rustc::ty;
 use rustc::mir::repr as mir;
 use rustc::mir::tcx::LvalueTy;
 use session::config::FullDebugInfo;
 use base;
 use common::{self, Block, BlockAndBuilder, CrateContext, FunctionContext, C_null};
-use debuginfo::{self, declare_local, DebugLoc, VariableAccess, VariableKind};
+use debuginfo::{self, declare_local, DebugLoc, VariableAccess, VariableKind, FunctionDebugContext};
 use machine;
 use type_of;
 
-use syntax_pos::DUMMY_SP;
+use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos};
 use syntax::parse::token::keywords;
 
 use std::ops::Deref;
@@ -103,12 +102,67 @@ pub struct MirContext<'bcx, 'tcx:'bcx> {
     locals: IndexVec<mir::Local, LocalRef<'tcx>>,
 
     /// Debug information for MIR scopes.
-    scopes: IndexVec<mir::VisibilityScope, DIScope>
+    scopes: IndexVec<mir::VisibilityScope, debuginfo::MirDebugScope>,
 }
 
 impl<'blk, 'tcx> MirContext<'blk, 'tcx> {
-    pub fn debug_loc(&self, source_info: mir::SourceInfo) -> DebugLoc {
-        DebugLoc::ScopeAt(self.scopes[source_info.scope], source_info.span)
+    pub fn debug_loc(&mut self, source_info: mir::SourceInfo) -> DebugLoc {
+        // Bail out if debug info emission is not enabled.
+        match self.fcx.debug_context {
+            FunctionDebugContext::DebugInfoDisabled |
+            FunctionDebugContext::FunctionWithoutDebugInfo => {
+                // Can't return DebugLoc::None here because intrinsic::trans_intrinsic_call()
+                // relies on debug location to obtain span of the call site.
+                return DebugLoc::ScopeAt(self.scopes[source_info.scope].scope_metadata,
+                                         source_info.span);
+            }
+            FunctionDebugContext::RegularContext(_) =>{}
+        }
+
+        // In order to have a good line stepping behavior in debugger, we overwrite debug
+        // locations of macro expansions with that of the outermost expansion site
+        // (unless the crate is being compiled with `-Z debug-macros`).
+        if source_info.span.expn_id == NO_EXPANSION ||
+            source_info.span.expn_id == COMMAND_LINE_EXPN ||
+            self.fcx.ccx.sess().opts.debugging_opts.debug_macros {
+
+            let scope_metadata = self.scope_metadata_for_loc(source_info.scope,
+                                                             source_info.span.lo);
+            DebugLoc::ScopeAt(scope_metadata, source_info.span)
+        } else {
+            let cm = self.fcx.ccx.sess().codemap();
+            // Walk up the macro expansion chain until we reach a non-expanded span.
+            let mut span = source_info.span;
+            while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN {
+                if let Some(callsite_span) = cm.with_expn_info(span.expn_id,
+                                                    |ei| ei.map(|ei| ei.call_site.clone())) {
+                    span = callsite_span;
+                } else {
+                    break;
+                }
+            }
+            let scope_metadata = self.scope_metadata_for_loc(source_info.scope, span.lo);
+            // Use span of the outermost call site, while keeping the original lexical scope
+            DebugLoc::ScopeAt(scope_metadata, span)
+        }
+    }
+
+    // DILocations inherit source file name from the parent DIScope.  Due to macro expansions
+    // it may so happen that the current span belongs to a different file than the DIScope
+    // corresponding to span's containing visibility scope.  If so, we need to create a DIScope
+    // "extension" into that file.
+    fn scope_metadata_for_loc(&self, scope_id: mir::VisibilityScope, pos: BytePos)
+                               -> llvm::debuginfo::DIScope {
+        let scope_metadata = self.scopes[scope_id].scope_metadata;
+        if pos < self.scopes[scope_id].file_start_pos ||
+           pos >= self.scopes[scope_id].file_end_pos {
+            let cm = self.fcx.ccx.sess().codemap();
+            debuginfo::extend_scope_to_file(self.fcx.ccx,
+                                            scope_metadata,
+                                            &cm.lookup_char_pos(pos).file)
+        } else {
+            scope_metadata
+        }
     }
 }
 
@@ -145,7 +199,7 @@ fn new_operand<'bcx>(ccx: &CrateContext<'bcx, 'tcx>,
 ///////////////////////////////////////////////////////////////////////////
 
 pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
-    let bcx = fcx.init(false, None).build();
+    let bcx = fcx.init(true).build();
     let mir = bcx.mir();
 
     // Analyze the temps to determine which must be lvalues
@@ -155,16 +209,38 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
          analyze::cleanup_kinds(bcx, &mir))
     });
 
+    // Allocate a `Block` for every basic block
+    let block_bcxs: IndexVec<mir::BasicBlock, Block<'blk,'tcx>> =
+        mir.basic_blocks().indices().map(|bb| {
+            if bb == mir::START_BLOCK {
+                fcx.new_block("start")
+            } else {
+                fcx.new_block(&format!("{:?}", bb))
+            }
+        }).collect();
+
     // Compute debuginfo scopes from MIR scopes.
     let scopes = debuginfo::create_mir_scopes(fcx);
 
+    let mut mircx = MirContext {
+        mir: mir.clone(),
+        fcx: fcx,
+        llpersonalityslot: None,
+        blocks: block_bcxs,
+        unreachable_block: None,
+        cleanup_kinds: cleanup_kinds,
+        landing_pads: IndexVec::from_elem(None, mir.basic_blocks()),
+        scopes: scopes,
+        locals: IndexVec::new(),
+    };
+
     // Allocate variable and temp allocas
-    let locals = {
-        let args = arg_local_refs(&bcx, &mir, &scopes, &lvalue_locals);
+    mircx.locals = {
+        let args = arg_local_refs(&bcx, &mir, &mircx.scopes, &lvalue_locals);
         let vars = mir.var_decls.iter().enumerate().map(|(i, decl)| {
             let ty = bcx.monomorphize(&decl.ty);
-            let scope = scopes[decl.source_info.scope];
-            let dbg = !scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo;
+            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 {
@@ -173,11 +249,16 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
 
             let lvalue = LvalueRef::alloca(&bcx, ty, &decl.name.as_str());
             if dbg {
-                bcx.with_block(|bcx| {
-                    declare_local(bcx, decl.name, ty, scope,
-                                VariableAccess::DirectVariable { alloca: lvalue.llval },
-                                VariableKind::LocalVariable, decl.source_info.span);
-                });
+                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");
+                }
             }
             LocalRef::Lvalue(lvalue)
         });
@@ -203,18 +284,8 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
         })).collect()
     };
 
-    // Allocate a `Block` for every basic block
-    let block_bcxs: IndexVec<mir::BasicBlock, Block<'blk,'tcx>> =
-        mir.basic_blocks().indices().map(|bb| {
-            if bb == mir::START_BLOCK {
-                fcx.new_block("start", None)
-            } else {
-                fcx.new_block(&format!("{:?}", bb), None)
-            }
-        }).collect();
-
     // Branch to the START block
-    let start_bcx = block_bcxs[mir::START_BLOCK];
+    let start_bcx = mircx.blocks[mir::START_BLOCK];
     bcx.br(start_bcx.llbb);
 
     // Up until here, IR instructions for this function have explicitly not been annotated with
@@ -222,18 +293,6 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
     // emitting should be enabled.
     debuginfo::start_emitting_source_locations(fcx);
 
-    let mut mircx = MirContext {
-        mir: mir.clone(),
-        fcx: fcx,
-        llpersonalityslot: None,
-        blocks: block_bcxs,
-        unreachable_block: None,
-        cleanup_kinds: cleanup_kinds,
-        landing_pads: IndexVec::from_elem(None, mir.basic_blocks()),
-        locals: locals,
-        scopes: scopes
-    };
-
     let mut visited = BitVector::new(mir.basic_blocks().len());
 
     let mut rpo = traversal::reverse_postorder(&mir);
@@ -271,7 +330,7 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
 /// indirect.
 fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
                               mir: &mir::Mir<'tcx>,
-                              scopes: &IndexVec<mir::VisibilityScope, DIScope>,
+                              scopes: &IndexVec<mir::VisibilityScope, debuginfo::MirDebugScope>,
                               lvalue_locals: &BitVector)
                               -> Vec<LocalRef<'tcx>> {
     let fcx = bcx.fcx();
@@ -281,8 +340,8 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
 
     // Get the argument scope, if it exists and if we need it.
     let arg_scope = scopes[mir::ARGUMENT_VISIBILITY_SCOPE];
-    let arg_scope = if !arg_scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo {
-        Some(arg_scope)
+    let arg_scope = if arg_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo {
+        Some(arg_scope.scope_metadata)
     } else {
         None
     };
index 9f7c2ee219eb5abafed3bc90684a3ffc6a159fbb..13484cb7a4ece286527df91b0bdc17313cf523d9 100644 (file)
@@ -17,7 +17,6 @@
 use base;
 use callee::Callee;
 use common::{self, val_ty, C_bool, C_null, C_uint, BlockAndBuilder, Result};
-use datum::{Datum, Lvalue};
 use debuginfo::DebugLoc;
 use adt;
 use machine;
@@ -101,7 +100,7 @@ pub fn trans_rvalue(&mut self,
                 let size = C_uint(bcx.ccx(), size);
                 let base = get_dataptr(&bcx, dest.llval);
                 let bcx = bcx.map_block(|block| {
-                    tvec::iter_vec_raw(block, base, tr_elem.ty, size, |block, llslot, _| {
+                    tvec::slice_for_each(block, base, tr_elem.ty, size, |block, llslot| {
                         self.store_operand_direct(block, llslot, tr_elem);
                         block
                     })
@@ -157,8 +156,7 @@ pub fn trans_rvalue(&mut self,
             mir::Rvalue::InlineAsm { ref asm, ref outputs, ref inputs } => {
                 let outputs = outputs.iter().map(|output| {
                     let lvalue = self.trans_lvalue(&bcx, output);
-                    Datum::new(lvalue.llval, lvalue.ty.to_ty(bcx.tcx()),
-                               Lvalue::new("out"))
+                    (lvalue.llval, lvalue.ty.to_ty(bcx.tcx()))
                 }).collect();
 
                 let input_vals = inputs.iter().map(|input| {
@@ -202,7 +200,7 @@ pub fn trans_rvalue_operand(&mut self,
                             ty::TyFnDef(def_id, substs, _) => {
                                 OperandValue::Immediate(
                                     Callee::def(bcx.ccx(), def_id, substs)
-                                        .reify(bcx.ccx()).val)
+                                        .reify(bcx.ccx()))
                             }
                             _ => {
                                 bug!("{} cannot be reified to a fn ptr", operand.ty)
index d1837883aaeb032cbb91328b4013d0f344c3cb92..ab2a39864336fe2703b8cf9b55bb99a71d3617e9 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::ValueRef;
-use llvm;
+use common::*;
 use rustc::hir::def_id::DefId;
 use rustc::infer::TransNormalize;
+use rustc::ty::fold::{TypeFolder, TypeFoldable};
 use rustc::ty::subst::{Subst, Substs};
-use rustc::ty::{self, Ty, TypeFoldable, TyCtxt};
-use attributes;
-use base::{push_ctxt};
-use base;
-use common::*;
-use declare;
-use Disr;
-use rustc::hir::map as hir_map;
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc::util::ppaux;
-
-use rustc::hir;
-
-use errors;
-
+use rustc::util::common::MemoizationMap;
 use std::fmt;
-use trans_item::TransItem;
-
-pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                fn_id: DefId,
-                                psubsts: &'tcx Substs<'tcx>)
-                                -> (ValueRef, Ty<'tcx>) {
-    debug!("monomorphic_fn(fn_id={:?}, real_substs={:?})", fn_id, psubsts);
-    assert!(!psubsts.types.needs_infer() && !psubsts.types.has_param_types());
-
-    let _icx = push_ctxt("monomorphic_fn");
-
-    let instance = Instance::new(fn_id, psubsts);
-
-    let item_ty = ccx.tcx().lookup_item_type(fn_id).ty;
-
-    debug!("monomorphic_fn about to subst into {:?}", item_ty);
-    let mono_ty = apply_param_substs(ccx.tcx(), psubsts, &item_ty);
-    debug!("mono_ty = {:?} (post-substitution)", mono_ty);
-
-    if let Some(&val) = ccx.instances().borrow().get(&instance) {
-        debug!("leaving monomorphic fn {:?}", instance);
-        return (val, mono_ty);
-    } else {
-        assert!(!ccx.codegen_unit().contains_item(&TransItem::Fn(instance)));
-    }
-
-    debug!("monomorphic_fn({:?})", instance);
-
-    ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1);
-
-    let depth;
-    {
-        let mut monomorphizing = ccx.monomorphizing().borrow_mut();
-        depth = match monomorphizing.get(&fn_id) {
-            Some(&d) => d, None => 0
-        };
-
-        debug!("monomorphic_fn: depth for fn_id={:?} is {:?}", fn_id, depth+1);
-
-        // Random cut-off -- code that needs to instantiate the same function
-        // recursively more than thirty times can probably safely be assumed
-        // to be causing an infinite expansion.
-        if depth > ccx.sess().recursion_limit.get() {
-            let error = format!("reached the recursion limit while instantiating `{}`",
-                                instance);
-            if let Some(id) = ccx.tcx().map.as_local_node_id(fn_id) {
-                ccx.sess().span_fatal(ccx.tcx().map.span(id), &error);
-            } else {
-                ccx.sess().fatal(&error);
-            }
-        }
-
-        monomorphizing.insert(fn_id, depth + 1);
-    }
-
-    let symbol = ccx.symbol_map().get_or_compute(ccx.shared(),
-                                                 TransItem::Fn(instance));
-
-    debug!("monomorphize_fn mangled to {}", &symbol);
-    assert!(declare::get_defined_value(ccx, &symbol).is_none());
-
-    // FIXME(nagisa): perhaps needs a more fine grained selection?
-    let lldecl = declare::define_internal_fn(ccx, &symbol, mono_ty);
-    // FIXME(eddyb) Doubt all extern fn should allow unwinding.
-    attributes::unwind(lldecl, true);
-
-    ccx.instances().borrow_mut().insert(instance, lldecl);
-
-    // we can only monomorphize things in this crate (or inlined into it)
-    let fn_node_id = ccx.tcx().map.as_local_node_id(fn_id).unwrap();
-    let map_node = errors::expect(
-        ccx.sess().diagnostic(),
-        ccx.tcx().map.find(fn_node_id),
-        || {
-            format!("while instantiating `{}`, couldn't find it in \
-                     the item map (may have attempted to monomorphize \
-                     an item defined in a different crate?)",
-                    instance)
-        });
-    match map_node {
-        hir_map::NodeItem(&hir::Item {
-            ref attrs,
-            node: hir::ItemFn(..), ..
-        }) |
-        hir_map::NodeImplItem(&hir::ImplItem {
-            ref attrs, node: hir::ImplItemKind::Method(
-                hir::MethodSig { .. }, _), ..
-        }) |
-        hir_map::NodeTraitItem(&hir::TraitItem {
-            ref attrs, node: hir::MethodTraitItem(
-                hir::MethodSig { .. }, Some(_)), ..
-        }) => {
-            let trans_item = TransItem::Fn(instance);
-
-            if ccx.shared().translation_items().borrow().contains(&trans_item) {
-                attributes::from_fn_attrs(ccx, attrs, lldecl);
-                unsafe {
-                    llvm::LLVMSetLinkage(lldecl, llvm::ExternalLinkage);
-                }
-            } else {
-                // FIXME: #34151
-                // Normally, getting here would indicate a bug in trans::collector,
-                // since it seems to have missed a translation item. When we are
-                // translating with non-MIR based trans, however, the results of
-                // the collector are not entirely reliable since it bases its
-                // analysis on MIR. Thus, we'll instantiate the missing function
-                // privately in this codegen unit, so that things keep working.
-                ccx.stats().n_fallback_instantiations.set(ccx.stats()
-                                                             .n_fallback_instantiations
-                                                             .get() + 1);
-                trans_item.predefine(ccx, llvm::InternalLinkage);
-                trans_item.define(ccx);
-            }
-        }
-
-        hir_map::NodeVariant(_) | hir_map::NodeStructCtor(_) => {
-            let disr = match map_node {
-                hir_map::NodeVariant(_) => {
-                    Disr::from(inlined_variant_def(ccx, fn_node_id).disr_val)
-                }
-                hir_map::NodeStructCtor(_) => Disr(0),
-                _ => bug!()
-            };
-            attributes::inline(lldecl, attributes::InlineAttr::Hint);
-            attributes::set_frame_pointer_elimination(ccx, lldecl);
-            base::trans_ctor_shim(ccx, fn_node_id, disr, psubsts, lldecl);
-        }
-
-        _ => bug!("can't monomorphize a {:?}", map_node)
-    };
-
-    ccx.monomorphizing().borrow_mut().insert(fn_id, depth);
-
-    debug!("leaving monomorphic fn {}", ccx.tcx().item_path_str(fn_id));
-    (lldecl, mono_ty)
-}
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub struct Instance<'tcx> {
@@ -180,7 +33,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl<'tcx> Instance<'tcx> {
     pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
                -> Instance<'tcx> {
-        assert!(substs.regions.iter().all(|&r| r == ty::ReErased));
+        assert!(substs.regions().all(|&r| r == ty::ReErased));
         Instance { def: def_id, substs: substs }
     }
     pub fn mono<'a>(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> {
@@ -190,14 +43,17 @@ pub fn mono<'a>(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'
 
 /// Monomorphizes a type from the AST by first applying the in-scope
 /// substitutions and then normalizing any associated types.
-pub fn apply_param_substs<'a, 'tcx, T>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>,
                                        param_substs: &Substs<'tcx>,
                                        value: &T)
                                        -> T
     where T: TransNormalize<'tcx>
 {
+    let tcx = scx.tcx();
+    debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value);
     let substituted = value.subst(tcx, param_substs);
-    tcx.normalize_associated_type(&substituted)
+    let substituted = scx.tcx().erase_regions(&substituted);
+    AssociatedTypeNormalizer::new(scx).fold(&substituted)
 }
 
 
@@ -209,3 +65,40 @@ pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 {
     tcx.normalize_associated_type(&f.ty(tcx, param_substs))
 }
+
+struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b> {
+    shared: &'a SharedCrateContext<'b, 'gcx>,
+}
+
+impl<'a, 'b, 'gcx> AssociatedTypeNormalizer<'a, 'b, 'gcx> {
+    fn new(shared: &'a SharedCrateContext<'b, 'gcx>) -> Self {
+        AssociatedTypeNormalizer {
+            shared: shared,
+        }
+    }
+
+    fn fold<T:TypeFoldable<'gcx>>(&mut self, value: &T) -> T {
+        if !value.has_projection_types() {
+            value.clone()
+        } else {
+            value.fold_with(self)
+        }
+    }
+}
+
+impl<'a, 'b, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'b, 'gcx> {
+    fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> {
+        self.shared.tcx()
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> {
+        if !ty.has_projection_types() {
+            ty
+        } else {
+            self.shared.project_cache().memoize(ty, || {
+                debug!("AssociatedTypeNormalizer: ty={:?}", ty);
+                self.shared.tcx().normalize_associated_type(&ty)
+            })
+        }
+    }
+}
index 87d0ea0fe81f30d83b20ac75099a7c0ca098d1d9..a161bd199b1f6768ecf982d86b13b345bd499696 100644 (file)
 //! inlining, even when they are not marked #[inline].
 
 use collector::InliningMap;
+use context::SharedCrateContext;
 use llvm;
 use monomorphize;
 use rustc::dep_graph::{DepNode, WorkProductId};
@@ -250,7 +251,7 @@ fn local_node_id(tcx: TyCtxt, trans_item: TransItem) -> Option<NodeId> {
 // Anything we can't find a proper codegen unit for goes into this.
 const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit";
 
-pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
                               trans_items: I,
                               strategy: PartitioningStrategy,
                               inlining_map: &InliningMap<'tcx>,
@@ -258,6 +259,8 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                               -> Vec<CodegenUnit<'tcx>>
     where I: Iterator<Item = TransItem<'tcx>>
 {
+    let tcx = scx.tcx();
+
     if let PartitioningStrategy::FixedUnitCount(1) = strategy {
         // If there is only a single codegen-unit, we can use a very simple
         // scheme and don't have to bother with doing much analysis.
@@ -267,7 +270,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // In the first step, we place all regular translation items into their
     // respective 'home' codegen unit. Regular translation items are all
     // functions and statics defined in the local crate.
-    let mut initial_partitioning = place_root_translation_items(tcx,
+    let mut initial_partitioning = place_root_translation_items(scx,
                                                                 trans_items,
                                                                 reachable);
 
@@ -306,12 +309,13 @@ struct PreInliningPartitioning<'tcx> {
 
 struct PostInliningPartitioning<'tcx>(Vec<CodegenUnit<'tcx>>);
 
-fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
                                              trans_items: I,
                                              _reachable: &NodeSet)
                                              -> PreInliningPartitioning<'tcx>
     where I: Iterator<Item = TransItem<'tcx>>
 {
+    let tcx = scx.tcx();
     let mut roots = FnvHashSet();
     let mut codegen_units = FnvHashMap();
 
@@ -319,7 +323,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let is_root = !trans_item.is_instantiated_only_on_demand();
 
         if is_root {
-            let characteristic_def_id = characteristic_def_id_of_trans_item(tcx, trans_item);
+            let characteristic_def_id = characteristic_def_id_of_trans_item(scx, trans_item);
             let is_volatile = trans_item.is_generic_fn();
 
             let codegen_unit_name = match characteristic_def_id {
@@ -342,7 +346,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         TransItem::DropGlue(..) => unreachable!(),
                         // Is there any benefit to using ExternalLinkage?:
                         TransItem::Fn(ref instance) => {
-                            if instance.substs.types.is_empty() {
+                            if instance.substs.types().next().is_none() {
                                 // This is a non-generic functions, we always
                                 // make it visible externally on the chance that
                                 // it might be used in another codegen unit.
@@ -477,9 +481,10 @@ fn follow_inlining<'tcx>(trans_item: TransItem<'tcx>,
     }
 }
 
-fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                                                  trans_item: TransItem<'tcx>)
                                                  -> Option<DefId> {
+    let tcx = scx.tcx();
     match trans_item {
         TransItem::Fn(instance) => {
             // If this is a method, we want to put it into the same module as
@@ -487,7 +492,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             // DefId, we use the location of the impl after all.
 
             if tcx.trait_of_item(instance.def).is_some() {
-                let self_ty = instance.substs.types[0];
+                let self_ty = instance.substs.type_at(0);
                 // This is an implementation of a trait method.
                 return characteristic_def_id_of_type(self_ty).or(Some(instance.def));
             }
@@ -497,7 +502,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 // self-type is:
                 let impl_self_ty = tcx.lookup_item_type(impl_def_id).ty;
                 let impl_self_ty = tcx.erase_regions(&impl_self_ty);
-                let impl_self_ty = monomorphize::apply_param_substs(tcx,
+                let impl_self_ty = monomorphize::apply_param_substs(scx,
                                                                     instance.substs,
                                                                     &impl_self_ty);
 
index 9a7fe54e0d9f5a9f3dc55cfb96e9efc8af1294e2..25c30151ad45dbcac159cae4a97b0a49698a7a4a 100644 (file)
@@ -17,7 +17,6 @@
 use rustc::hir;
 use rustc::hir::intravisit::{self, Visitor};
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 
 use common::SharedCrateContext;
 use monomorphize::Instance;
index 580882e31dd603248fba65ca64b4c96eb6dbefc4..8a0f37230c8dfa21730fda3bd4e725c7cf7a7169 100644 (file)
 use glue::DropGlueKind;
 use llvm;
 use monomorphize::{self, Instance};
-use inline;
 use rustc::dep_graph::DepNode;
 use rustc::hir;
-use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::subst::Substs;
 use rustc_const_eval::fatal_const_eval_err;
 use std::hash::{Hash, Hasher};
 use syntax::ast::{self, NodeId};
-use syntax::{attr,errors};
+use syntax::attr;
 use type_of;
 use glue;
 use abi::{Abi, FnType};
@@ -88,13 +86,13 @@ pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) {
                 let def_id = ccx.tcx().map.local_def_id(node_id);
                 let _task = ccx.tcx().dep_graph.in_task(DepNode::TransCrateItem(def_id)); // (*)
                 let item = ccx.tcx().map.expect_item(node_id);
-                if let hir::ItemStatic(_, m, ref expr) = item.node {
-                    match consts::trans_static(&ccx, m, expr, item.id, &item.attrs) {
+                if let hir::ItemStatic(_, m, _) = item.node {
+                    match consts::trans_static(&ccx, m, item.id, &item.attrs) {
                         Ok(_) => { /* Cool, everything's alright. */ },
                         Err(err) => {
                             // FIXME: shouldn't this be a `span_err`?
                             fatal_const_eval_err(
-                                ccx.tcx(), &err, expr.span, "static");
+                                ccx.tcx(), &err, item.span, "static");
                         }
                     };
                 } else {
@@ -157,70 +155,41 @@ fn predefine_static(ccx: &CrateContext<'a, 'tcx>,
         let ty = ccx.tcx().lookup_item_type(def_id).ty;
         let llty = type_of::type_of(ccx, ty);
 
-        match ccx.tcx().map.get(node_id) {
-            hir::map::NodeItem(&hir::Item {
-                span, node: hir::ItemStatic(..), ..
-            }) => {
-                let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| {
-                    ccx.sess().span_fatal(span,
-                        &format!("symbol `{}` is already defined", symbol_name))
-                });
+        let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| {
+            ccx.sess().span_fatal(ccx.tcx().map.span(node_id),
+                &format!("symbol `{}` is already defined", symbol_name))
+        });
 
-                unsafe { llvm::LLVMSetLinkage(g, linkage) };
-            }
+        unsafe { llvm::LLVMSetLinkage(g, linkage) };
 
-            item => bug!("predefine_static: expected static, found {:?}", item)
-        }
+        let instance = Instance::mono(ccx.shared(), def_id);
+        ccx.instances().borrow_mut().insert(instance, g);
+        ccx.statics().borrow_mut().insert(g, def_id);
     }
 
     fn predefine_fn(ccx: &CrateContext<'a, 'tcx>,
                     instance: Instance<'tcx>,
                     linkage: llvm::Linkage,
                     symbol_name: &str) {
-        assert!(!instance.substs.types.needs_infer() &&
-                !instance.substs.types.has_param_types());
-
-        let instance = inline::maybe_inline_instance(ccx, instance);
+        assert!(!instance.substs.needs_infer() &&
+                !instance.substs.has_param_types());
 
         let item_ty = ccx.tcx().lookup_item_type(instance.def).ty;
         let item_ty = ccx.tcx().erase_regions(&item_ty);
-        let mono_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &item_ty);
-
-        let fn_node_id = ccx.tcx().map.as_local_node_id(instance.def).unwrap();
-        let map_node = errors::expect(
-            ccx.sess().diagnostic(),
-            ccx.tcx().map.find(fn_node_id),
-            || {
-                format!("while instantiating `{}`, couldn't find it in \
-                     the item map (may have attempted to monomorphize \
-                     an item defined in a different crate?)",
-                    instance)
-            });
-
-        match map_node {
-            hir_map::NodeItem(&hir::Item {
-                ref attrs, node: hir::ItemFn(..), ..
-            }) |
-            hir_map::NodeTraitItem(&hir::TraitItem {
-                ref attrs, node: hir::MethodTraitItem(..), ..
-            }) |
-            hir_map::NodeImplItem(&hir::ImplItem {
-                ref attrs, node: hir::ImplItemKind::Method(..), ..
-            }) => {
-                let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty);
-                unsafe { llvm::LLVMSetLinkage(lldecl, linkage) };
-                base::set_link_section(ccx, lldecl, attrs);
-                if linkage == llvm::LinkOnceODRLinkage ||
-                   linkage == llvm::WeakODRLinkage {
-                    llvm::SetUniqueComdat(ccx.llmod(), lldecl);
-                }
+        let mono_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &item_ty);
 
-                attributes::from_fn_attrs(ccx, attrs, lldecl);
-                ccx.instances().borrow_mut().insert(instance, lldecl);
-            }
-            _ => bug!("Invalid item for TransItem::Fn: `{:?}`", map_node)
-        };
+        let attrs = ccx.tcx().get_attrs(instance.def);
+        let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty);
+        unsafe { llvm::LLVMSetLinkage(lldecl, linkage) };
+        base::set_link_section(ccx, lldecl, &attrs);
+        if linkage == llvm::LinkOnceODRLinkage ||
+            linkage == llvm::WeakODRLinkage {
+            llvm::SetUniqueComdat(ccx.llmod(), lldecl);
+        }
+
+        attributes::from_fn_attrs(ccx, &attrs, lldecl);
 
+        ccx.instances().borrow_mut().insert(instance, lldecl);
     }
 
     fn predefine_drop_glue(ccx: &CrateContext<'a, 'tcx>,
@@ -275,7 +244,7 @@ pub fn compute_symbol_name(&self,
     pub fn requests_inline(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
         match *self {
             TransItem::Fn(ref instance) => {
-                !instance.substs.types.is_empty() || {
+                instance.substs.types().next().is_some() || {
                     let attributes = tcx.get_attrs(instance.def);
                     attr::requests_inline(&attributes[..])
                 }
@@ -295,8 +264,9 @@ pub fn is_from_extern_crate(&self) -> bool {
 
     pub fn is_instantiated_only_on_demand(&self) -> bool {
         match *self {
-            TransItem::Fn(ref instance) => !instance.def.is_local() ||
-                                           !instance.substs.types.is_empty(),
+            TransItem::Fn(ref instance) => {
+                !instance.def.is_local() || instance.substs.types().next().is_some()
+            }
             TransItem::DropGlue(..) => true,
             TransItem::Static(..)   => false,
         }
@@ -304,7 +274,9 @@ pub fn is_instantiated_only_on_demand(&self) -> bool {
 
     pub fn is_generic_fn(&self) -> bool {
         match *self {
-            TransItem::Fn(ref instance) => !instance.substs.types.is_empty(),
+            TransItem::Fn(ref instance) => {
+                instance.substs.types().next().is_some()
+            }
             TransItem::DropGlue(..) |
             TransItem::Static(..)   => false,
         }
@@ -405,7 +377,7 @@ pub fn to_raw_string(&self) -> String {
 /// Same as `unique_type_name()` but with the result pushed onto the given
 /// `output` parameter.
 pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                       t: ty::Ty<'tcx>,
+                                       t: Ty<'tcx>,
                                        output: &mut String) {
     match t.sty {
         ty::TyBool              => output.push_str("bool"),
@@ -427,7 +399,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         ty::TyStruct(adt_def, substs) |
         ty::TyEnum(adt_def, substs) => {
             push_item_name(tcx, adt_def.did, output);
-            push_type_params(tcx, &substs.types, &[], output);
+            push_type_params(tcx, substs, &[], output);
         },
         ty::TyTuple(component_types) => {
             output.push('(');
@@ -477,7 +449,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         ty::TyTrait(ref trait_data) => {
             push_item_name(tcx, trait_data.principal.def_id(), output);
             push_type_params(tcx,
-                             &trait_data.principal.skip_binder().substs.types,
+                             trait_data.principal.skip_binder().substs,
                              &trait_data.projection_bounds,
                              output);
         },
@@ -525,7 +497,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             output.push_str("{");
             output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize()));
             output.push_str("}");
-            push_type_params(tcx, &closure_substs.func_substs.types, &[], output);
+            push_type_params(tcx, closure_substs.func_substs, &[], output);
         }
         ty::TyError |
         ty::TyInfer(_) |
@@ -560,16 +532,16 @@ fn push_item_name(tcx: TyCtxt,
 }
 
 fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                              types: &[Ty<'tcx>],
+                              substs: &Substs<'tcx>,
                               projections: &[ty::PolyExistentialProjection<'tcx>],
                               output: &mut String) {
-    if types.is_empty() && projections.is_empty() {
+    if substs.types().next().is_none() && projections.is_empty() {
         return;
     }
 
     output.push('<');
 
-    for &type_parameter in types {
+    for type_parameter in substs.types() {
         push_unique_type_name(tcx, type_parameter, output);
         output.push_str(", ");
     }
@@ -593,7 +565,7 @@ fn push_instance_as_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                      instance: Instance<'tcx>,
                                      output: &mut String) {
     push_item_name(tcx, instance.def, output);
-    push_type_params(tcx, &instance.substs.types, &[], output);
+    push_type_params(tcx, instance.substs, &[], output);
 }
 
 pub fn def_id_to_string(tcx: TyCtxt, def_id: DefId) -> String {
@@ -603,7 +575,7 @@ pub fn def_id_to_string(tcx: TyCtxt, def_id: DefId) -> String {
 }
 
 pub fn type_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                ty: ty::Ty<'tcx>)
+                                ty: Ty<'tcx>)
                                 -> String {
     let mut output = String::new();
     push_unique_type_name(tcx, ty, &mut output);
index 92a2d3787bfd6b60bc5184233f24893e10e91ab3..7e4719870cd83a426f458c65d5c680971c7d9bc7 100644 (file)
 use llvm;
 use llvm::ValueRef;
 use base::*;
-use base;
 use build::*;
-use cleanup;
-use cleanup::CleanupMethods;
 use common::*;
-use consts;
-use datum::*;
 use debuginfo::DebugLoc;
-use expr::{Dest, Ignore, SaveIn};
-use expr;
-use machine::llsize_of_alloc;
-use type_::Type;
-use type_of;
-use value::Value;
-use rustc::ty::{self, Ty};
-
-use rustc::hir;
-use rustc_const_eval::eval_length;
-
-use syntax::ast;
-use syntax::parse::token::InternedString;
-
-#[derive(Copy, Clone, Debug)]
-struct VecTypes<'tcx> {
-    unit_ty: Ty<'tcx>,
-    llunit_ty: Type
-}
-
-pub fn trans_fixed_vstore<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                      expr: &hir::Expr,
-                                      dest: expr::Dest)
-                                      -> Block<'blk, 'tcx> {
-    //!
-    //
-    // [...] allocates a fixed-size array and moves it around "by value".
-    // In this case, it means that the caller has already given us a location
-    // to store the array of the suitable size, so all we have to do is
-    // generate the content.
-
-    debug!("trans_fixed_vstore(expr={:?}, dest={:?})", expr, dest);
-
-    let vt = vec_types_from_expr(bcx, expr);
-
-    return match dest {
-        Ignore => write_content(bcx, &vt, expr, expr, dest),
-        SaveIn(lldest) => {
-            // lldest will have type *[T x N], but we want the type *T,
-            // so use GEP to convert:
-            let lldest = StructGEP(bcx, lldest, 0);
-            write_content(bcx, &vt, expr, expr, SaveIn(lldest))
-        }
-    };
-}
-
-/// &[...] allocates memory on the stack and writes the values into it, returning the vector (the
-/// caller must make the reference).  "..." is similar except that the memory can be statically
-/// allocated and we return a reference (strings are always by-ref).
-pub fn trans_slice_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                   slice_expr: &hir::Expr,
-                                   content_expr: &hir::Expr)
-                                   -> DatumBlock<'blk, 'tcx, Expr> {
+use rustc::ty::Ty;
+
+pub fn slice_for_each<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
+                                     data_ptr: ValueRef,
+                                     unit_ty: Ty<'tcx>,
+                                     len: ValueRef,
+                                     f: F)
+                                     -> Block<'blk, 'tcx> where
+    F: FnOnce(Block<'blk, 'tcx>, ValueRef) -> Block<'blk, 'tcx>,
+{
+    let _icx = push_ctxt("tvec::slice_for_each");
     let fcx = bcx.fcx;
-    let mut bcx = bcx;
-
-    debug!("trans_slice_vec(slice_expr={:?})",
-           slice_expr);
-
-    let vec_ty = node_id_type(bcx, slice_expr.id);
-
-    // Handle the "..." case (returns a slice since strings are always unsized):
-    if let hir::ExprLit(ref lit) = content_expr.node {
-        if let ast::LitKind::Str(ref s, _) = lit.node {
-            let scratch = rvalue_scratch_datum(bcx, vec_ty, "");
-            bcx = trans_lit_str(bcx,
-                                content_expr,
-                                s.clone(),
-                                SaveIn(scratch.val));
-            return DatumBlock::new(bcx, scratch.to_expr_datum());
-        }
-    }
-
-    // Handle the &[...] case:
-    let vt = vec_types_from_expr(bcx, content_expr);
-    let count = elements_required(bcx, content_expr);
-    debug!("    vt={:?}, count={}", vt, count);
 
-    let fixed_ty = bcx.tcx().mk_array(vt.unit_ty, count);
-
-    // Always create an alloca even if zero-sized, to preserve
-    // the non-null invariant of the inner slice ptr
-    let llfixed;
-    // Issue 30018: ensure state is initialized as dropped if necessary.
-    if fcx.type_needs_drop(vt.unit_ty) {
-        llfixed = base::alloc_ty_init(bcx, fixed_ty, InitAlloca::Dropped, "");
+    // Special-case vectors with elements of size 0  so they don't go out of bounds (#9890)
+    let zst = type_is_zero_size(bcx.ccx(), unit_ty);
+    let add = |bcx, a, b| if zst {
+        Add(bcx, a, b, DebugLoc::None)
     } else {
-        let uninit = InitAlloca::Uninit("fcx says vt.unit_ty is non-drop");
-        llfixed = base::alloc_ty_init(bcx, fixed_ty, uninit, "");
-        call_lifetime_start(bcx, llfixed);
-    };
-
-    if count > 0 {
-        // Arrange for the backing array to be cleaned up.
-        let cleanup_scope = cleanup::temporary_scope(bcx.tcx(), content_expr.id);
-        fcx.schedule_lifetime_end(cleanup_scope, llfixed);
-        fcx.schedule_drop_mem(cleanup_scope, llfixed, fixed_ty, None);
-
-        // Generate the content into the backing array.
-        // llfixed has type *[T x N], but we want the type *T,
-        // so use GEP to convert
-        bcx = write_content(bcx, &vt, slice_expr, content_expr,
-                            SaveIn(StructGEP(bcx, llfixed, 0)));
+        InBoundsGEP(bcx, a, &[b])
     };
 
-    immediate_rvalue_bcx(bcx, llfixed, vec_ty).to_expr_datumblock()
-}
-
-/// Literal strings translate to slices into static memory.  This is different from
-/// trans_slice_vstore() above because it doesn't need to copy the content anywhere.
-pub fn trans_lit_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                 lit_expr: &hir::Expr,
-                                 str_lit: InternedString,
-                                 dest: Dest)
-                                 -> Block<'blk, 'tcx> {
-    debug!("trans_lit_str(lit_expr={:?}, dest={:?})", lit_expr, dest);
-
-    match dest {
-        Ignore => bcx,
-        SaveIn(lldest) => {
-            let bytes = str_lit.len();
-            let llbytes = C_uint(bcx.ccx(), bytes);
-            let llcstr = C_cstr(bcx.ccx(), str_lit, false);
-            let llcstr = consts::ptrcast(llcstr, Type::i8p(bcx.ccx()));
-            Store(bcx, llcstr, expr::get_dataptr(bcx, lldest));
-            Store(bcx, llbytes, expr::get_meta(bcx, lldest));
-            bcx
-        }
-    }
-}
-
-fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                             vt: &VecTypes<'tcx>,
-                             vstore_expr: &hir::Expr,
-                             content_expr: &hir::Expr,
-                             dest: Dest)
-                             -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("tvec::write_content");
-    let fcx = bcx.fcx;
-    let mut bcx = bcx;
-
-    debug!("write_content(vt={:?}, dest={:?}, vstore_expr={:?})",
-           vt, dest, vstore_expr);
-
-    match content_expr.node {
-        hir::ExprLit(ref lit) => {
-            match lit.node {
-                ast::LitKind::Str(ref s, _) => {
-                    match dest {
-                        Ignore => return bcx,
-                        SaveIn(lldest) => {
-                            let bytes = s.len();
-                            let llbytes = C_uint(bcx.ccx(), bytes);
-                            let llcstr = C_cstr(bcx.ccx(), (*s).clone(), false);
-                            if !bcx.unreachable.get() {
-                                base::call_memcpy(&B(bcx), lldest, llcstr, llbytes, 1);
-                            }
-                            return bcx;
-                        }
-                    }
-                }
-                _ => {
-                    span_bug!(content_expr.span, "unexpected evec content");
-                }
-            }
-        }
-        hir::ExprVec(ref elements) => {
-            match dest {
-                Ignore => {
-                    for element in elements {
-                        bcx = expr::trans_into(bcx, &element, Ignore);
-                    }
-                }
-
-                SaveIn(lldest) => {
-                    let temp_scope = fcx.push_custom_cleanup_scope();
-                    for (i, element) in elements.iter().enumerate() {
-                        let lleltptr = GEPi(bcx, lldest, &[i]);
-                        debug!("writing index {} with lleltptr={:?}",
-                               i, Value(lleltptr));
-                        bcx = expr::trans_into(bcx, &element,
-                                               SaveIn(lleltptr));
-                        let scope = cleanup::CustomScope(temp_scope);
-                        // Issue #30822: mark memory as dropped after running destructor
-                        fcx.schedule_drop_and_fill_mem(scope, lleltptr, vt.unit_ty, None);
-                    }
-                    fcx.pop_custom_cleanup_scope(temp_scope);
-                }
-            }
-            return bcx;
-        }
-        hir::ExprRepeat(ref element, ref count_expr) => {
-            match dest {
-                Ignore => {
-                    return expr::trans_into(bcx, &element, Ignore);
-                }
-                SaveIn(lldest) => {
-                    match eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap() {
-                        0 => expr::trans_into(bcx, &element, Ignore),
-                        1 => expr::trans_into(bcx, &element, SaveIn(lldest)),
-                        count => {
-                            let elem = unpack_datum!(bcx, expr::trans(bcx, &element));
-                            let bcx = iter_vec_loop(bcx, lldest, vt,
-                                                    C_uint(bcx.ccx(), count),
-                                                    |set_bcx, lleltptr, _| {
-                                                        elem.shallow_copy(set_bcx, lleltptr)
-                                                    });
-                            bcx
-                        }
-                    }
-                }
-            }
-        }
-        _ => {
-            span_bug!(content_expr.span, "unexpected vec content");
-        }
-    }
-}
-
-fn vec_types_from_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, vec_expr: &hir::Expr)
-                                   -> VecTypes<'tcx> {
-    let vec_ty = node_id_type(bcx, vec_expr.id);
-    vec_types(bcx, vec_ty.sequence_element_type(bcx.tcx()))
-}
-
-fn vec_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, unit_ty: Ty<'tcx>)
-                         -> VecTypes<'tcx> {
-    VecTypes {
-        unit_ty: unit_ty,
-        llunit_ty: type_of::type_of(bcx.ccx(), unit_ty)
-    }
-}
-
-fn elements_required(bcx: Block, content_expr: &hir::Expr) -> usize {
-    //! Figure out the number of elements we need to store this content
-
-    match content_expr.node {
-        hir::ExprLit(ref lit) => {
-            match lit.node {
-                ast::LitKind::Str(ref s, _) => s.len(),
-                _ => {
-                    span_bug!(content_expr.span, "unexpected evec content")
-                }
-            }
-        },
-        hir::ExprVec(ref es) => es.len(),
-        hir::ExprRepeat(_, ref count_expr) => {
-            eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap()
-        }
-        _ => span_bug!(content_expr.span, "unexpected vec content")
-    }
-}
-
-/// Converts a fixed-length vector into the slice pair. The vector should be stored in `llval`
-/// which should be by ref.
-pub fn get_fixed_base_and_len(bcx: Block,
-                              llval: ValueRef,
-                              vec_length: usize)
-                              -> (ValueRef, ValueRef) {
-    let ccx = bcx.ccx();
-
-    let base = expr::get_dataptr(bcx, llval);
-    let len = C_uint(ccx, vec_length);
-    (base, len)
-}
-
-/// Converts a vector into the slice pair.  The vector should be stored in `llval` which should be
-/// by-reference.  If you have a datum, you would probably prefer to call
-/// `Datum::get_base_and_len()` which will handle any conversions for you.
-pub fn get_base_and_len<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                    llval: ValueRef,
-                                    vec_ty: Ty<'tcx>)
-                                    -> (ValueRef, ValueRef) {
-    match vec_ty.sty {
-        ty::TyArray(_, n) => get_fixed_base_and_len(bcx, llval, n),
-        ty::TySlice(_) | ty::TyStr => {
-            let base = Load(bcx, expr::get_dataptr(bcx, llval));
-            let len = Load(bcx, expr::get_meta(bcx, llval));
-            (base, len)
-        }
-
-        // Only used for pattern matching.
-        ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) => {
-            let inner = if type_is_sized(bcx.tcx(), ty) {
-                Load(bcx, llval)
-            } else {
-                llval
-            };
-            get_base_and_len(bcx, inner, ty)
-        },
-        _ => bug!("unexpected type in get_base_and_len"),
-    }
-}
+    let header_bcx = fcx.new_block("slice_loop_header");
+    let body_bcx = fcx.new_block("slice_loop_body");
+    let next_bcx = fcx.new_block("slice_loop_next");
 
-fn iter_vec_loop<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
-                                data_ptr: ValueRef,
-                                vt: &VecTypes<'tcx>,
-                                count: ValueRef,
-                                f: F)
-                                -> Block<'blk, 'tcx> where
-    F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
-{
-    let _icx = push_ctxt("tvec::iter_vec_loop");
-
-    if bcx.unreachable.get() {
-        return bcx;
-    }
-
-    let fcx = bcx.fcx;
-    let loop_bcx = fcx.new_temp_block("expr_repeat");
-    let next_bcx = fcx.new_temp_block("expr_repeat: next");
-
-    Br(bcx, loop_bcx.llbb, DebugLoc::None);
-
-    let loop_counter = Phi(loop_bcx, bcx.ccx().int_type(),
-                           &[C_uint(bcx.ccx(), 0 as usize)], &[bcx.llbb]);
-
-    let bcx = loop_bcx;
-
-    let lleltptr = if llsize_of_alloc(bcx.ccx(), vt.llunit_ty) == 0 {
-        data_ptr
+    let start = if zst {
+        C_uint(bcx.ccx(), 0 as usize)
     } else {
-        InBoundsGEP(bcx, data_ptr, &[loop_counter])
+        data_ptr
     };
-    let bcx = f(bcx, lleltptr, vt.unit_ty);
-    let plusone = Add(bcx, loop_counter, C_uint(bcx.ccx(), 1usize), DebugLoc::None);
-    AddIncomingToPhi(loop_counter, plusone, bcx.llbb);
+    let end = add(bcx, start, len);
 
-    let cond_val = ICmp(bcx, llvm::IntULT, plusone, count, DebugLoc::None);
-    CondBr(bcx, cond_val, loop_bcx.llbb, next_bcx.llbb, DebugLoc::None);
+    Br(bcx, header_bcx.llbb, DebugLoc::None);
+    let current = Phi(header_bcx, val_ty(start), &[start], &[bcx.llbb]);
 
-    next_bcx
-}
+    let keep_going =
+        ICmp(header_bcx, llvm::IntULT, current, end, DebugLoc::None);
+    CondBr(header_bcx, keep_going, body_bcx.llbb, next_bcx.llbb, DebugLoc::None);
 
-pub fn iter_vec_raw<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
-                                   data_ptr: ValueRef,
-                                   unit_ty: Ty<'tcx>,
-                                   len: ValueRef,
-                                   f: F)
-                                   -> Block<'blk, 'tcx> where
-    F: FnOnce(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
-{
-    let _icx = push_ctxt("tvec::iter_vec_raw");
-    let fcx = bcx.fcx;
-
-    let vt = vec_types(bcx, unit_ty);
-
-    if llsize_of_alloc(bcx.ccx(), vt.llunit_ty) == 0 {
-        // Special-case vectors with elements of size 0  so they don't go out of bounds (#9890)
-        iter_vec_loop(bcx, data_ptr, &vt, len, f)
-    } else {
-        // Calculate the last pointer address we want to handle.
-        let data_end_ptr = InBoundsGEP(bcx, data_ptr, &[len]);
-
-        // Now perform the iteration.
-        let header_bcx = fcx.new_temp_block("iter_vec_loop_header");
-        Br(bcx, header_bcx.llbb, DebugLoc::None);
-        let data_ptr =
-            Phi(header_bcx, val_ty(data_ptr), &[data_ptr], &[bcx.llbb]);
-        let not_yet_at_end =
-            ICmp(header_bcx, llvm::IntULT, data_ptr, data_end_ptr, DebugLoc::None);
-        let body_bcx = fcx.new_temp_block("iter_vec_loop_body");
-        let next_bcx = fcx.new_temp_block("iter_vec_next");
-        CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb, DebugLoc::None);
-        let body_bcx = f(body_bcx, data_ptr, unit_ty);
-        AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr,
-                                               &[C_int(bcx.ccx(), 1)]),
-                         body_bcx.llbb);
-        Br(body_bcx, header_bcx.llbb, DebugLoc::None);
-        next_bcx
-    }
+    let body_bcx = f(body_bcx, if zst { data_ptr } else { current });
+    let next = add(body_bcx, current, C_uint(bcx.ccx(), 1usize));
+    AddIncomingToPhi(current, next, body_bcx.llbb);
+    Br(body_bcx, header_bcx.llbb, DebugLoc::None);
+    next_bcx
 }
index 6862002ed83b25a448e2319656cb7610d506b6be..6605d12e2e127b3c27f497015bae54e4c0944598 100644 (file)
@@ -15,8 +15,8 @@
 use adt;
 use common::*;
 use machine;
-use rustc::traits::Reveal;
 use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::subst::Substs;
 
 use type_::Type;
 
@@ -124,37 +124,31 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
     cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
 
     // FIXME(eddyb) Temporary sanity check for ty::layout.
-    let layout = cx.tcx().normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
-        t.layout(&infcx)
-    });
-    match layout {
-        Ok(layout) => {
-            if !type_is_sized(cx.tcx(), t) {
-                if !layout.is_unsized() {
-                    bug!("layout should be unsized for type `{}` / {:#?}",
-                         t, layout);
-                }
-
-                // Unsized types get turned into a fat pointer for LLVM.
-                return llsizingty;
-            }
-            let r = layout.size(&cx.tcx().data_layout).bytes();
-            let l = machine::llsize_of_alloc(cx, llsizingty);
-            if r != l {
-                bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
-                     r, l, t, layout);
-            }
-            let r = layout.align(&cx.tcx().data_layout).abi();
-            let l = machine::llalign_of_min(cx, llsizingty) as u64;
-            if r != l {
-                bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
-                     r, l, t, layout);
-            }
-        }
-        Err(e) => {
-            bug!("failed to get layout for `{}`: {}", t, e);
+    let layout = cx.layout_of(t);
+    if !type_is_sized(cx.tcx(), t) {
+        if !layout.is_unsized() {
+            bug!("layout should be unsized for type `{}` / {:#?}",
+                 t, layout);
         }
+
+        // Unsized types get turned into a fat pointer for LLVM.
+        return llsizingty;
+    }
+
+    let r = layout.size(&cx.tcx().data_layout).bytes();
+    let l = machine::llsize_of_alloc(cx, llsizingty);
+    if r != l {
+        bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
+             r, l, t, layout);
     }
+
+    let r = layout.align(&cx.tcx().data_layout).abi();
+    let l = machine::llalign_of_min(cx, llsizingty) as u64;
+    if r != l {
+        bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
+             r, l, t, layout);
+    }
+
     llsizingty
 }
 
@@ -256,7 +250,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
           // avoids creating more than one copy of the enum when one
           // of the enum's variants refers to the enum itself.
           let repr = adt::represent_type(cx, t);
-          let name = llvm_type_name(cx, def.did, &substs.types);
+          let name = llvm_type_name(cx, def.did, substs);
           adt::incomplete_type_of(cx, &repr, &name[..])
       }
       ty::TyClosure(..) => {
@@ -330,7 +324,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
               // in *after* placing it into the type cache. This prevents
               // infinite recursion with recursive struct types.
               let repr = adt::represent_type(cx, t);
-              let name = llvm_type_name(cx, def.did, &substs.types);
+              let name = llvm_type_name(cx, def.did, substs);
               adt::incomplete_type_of(cx, &repr, &name[..])
           }
       }
@@ -367,10 +361,10 @@ pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>)
 
 fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                             did: DefId,
-                            tps: &[Ty<'tcx>])
+                            substs: &Substs<'tcx>)
                             -> String {
     let base = cx.tcx().item_path_str(did);
-    let strings: Vec<String> = tps.iter().map(|t| t.to_string()).collect();
+    let strings: Vec<String> = substs.types().map(|t| t.to_string()).collect();
     let tstr = if strings.is_empty() {
         base
     } else {
index f6984f42cab341301d52864b2b6e691d1e5217ac..6c9cc5f5e132ac7e32730c1174a0d1decfbf7371 100644 (file)
@@ -178,8 +178,9 @@ struct ConvertedBinding<'tcx> {
 /// This type must not appear anywhere in other converted types.
 const TRAIT_OBJECT_DUMMY_SELF: ty::TypeVariants<'static> = ty::TyInfer(ty::FreshTy(0));
 
-pub fn ast_region_to_region(tcx: TyCtxt, lifetime: &hir::Lifetime)
-                            -> ty::Region {
+pub fn ast_region_to_region<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                            lifetime: &hir::Lifetime)
+                                            -> &'tcx ty::Region {
     let r = match tcx.named_region_map.defs.get(&lifetime.id) {
         None => {
             // should have been recorded by the `resolve_lifetime` pass
@@ -238,7 +239,7 @@ pub fn ast_region_to_region(tcx: TyCtxt, lifetime: &hir::Lifetime)
            lifetime.id,
            r);
 
-    r
+    tcx.mk_region(r)
 }
 
 fn report_elision_failure(
@@ -313,14 +314,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     pub fn opt_ast_region_to_region(&self,
         rscope: &RegionScope,
         default_span: Span,
-        opt_lifetime: &Option<hir::Lifetime>) -> ty::Region
+        opt_lifetime: &Option<hir::Lifetime>) -> &'tcx ty::Region
     {
         let r = match *opt_lifetime {
             Some(ref lifetime) => {
                 ast_region_to_region(self.tcx(), lifetime)
             }
 
-            None => match rscope.anon_regions(default_span, 1) {
+            None => self.tcx().mk_region(match rscope.anon_regions(default_span, 1) {
                 Ok(rs) => rs[0],
                 Err(params) => {
                     let ampersand_span = Span { hi: default_span.lo, ..default_span};
@@ -335,7 +336,7 @@ pub fn opt_ast_region_to_region(&self,
                     err.emit();
                     ty::ReStatic
                 }
-            }
+            })
         };
 
         debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {:?}",
@@ -366,7 +367,7 @@ pub fn ast_path_substs_for_ty(&self,
                     .emit();
 
                 return Substs::for_item(tcx, def_id, |_, _| {
-                    ty::ReStatic
+                    tcx.mk_region(ty::ReStatic)
                 }, |_, _| {
                     tcx.types.err
                 });
@@ -431,7 +432,7 @@ fn create_substs_for_ast_path(&self,
         let expected_num_region_params = decl_generics.regions.len();
         let supplied_num_region_params = lifetimes.len();
         let regions = if expected_num_region_params == supplied_num_region_params {
-            lifetimes.iter().map(|l| ast_region_to_region(tcx, l)).collect()
+            lifetimes.iter().map(|l| *ast_region_to_region(tcx, l)).collect()
         } else {
             let anon_regions =
                 rscope.anon_regions(span, expected_num_region_params);
@@ -472,7 +473,8 @@ fn create_substs_for_ast_path(&self,
 
         let mut output_assoc_binding = None;
         let substs = Substs::for_item(tcx, def_id, |def, _| {
-            regions[def.index as usize]
+            let i = def.index as usize - self_ty.is_some() as usize;
+            tcx.mk_region(regions[i])
         }, |def, substs| {
             let i = def.index as usize;
 
@@ -481,7 +483,7 @@ fn create_substs_for_ast_path(&self,
                 return ty;
             }
 
-            let i = i - self_ty.is_some() as usize;
+            let i = i - self_ty.is_some() as usize - decl_generics.regions.len();
             if num_types_provided.map_or(false, |n| i < n) {
                 // A provided type parameter.
                 match *parameters {
@@ -513,12 +515,13 @@ fn create_substs_for_ast_path(&self,
                 // defaults. This will lead to an ICE if we are not
                 // careful!
                 if default_needs_object_self(def) {
-                    span_err!(tcx.sess, span, E0393,
-                              "the type parameter `{}` must be explicitly specified \
-                               in an object type because its default value `{}` references \
-                               the type `Self`",
-                              def.name,
-                              default);
+                    struct_span_err!(tcx.sess, span, E0393,
+                                     "the type parameter `{}` must be explicitly specified",
+                                     def.name)
+                        .span_label(span, &format!("missing reference to `{}`", def.name))
+                        .note(&format!("because of the default `Self` reference, \
+                                        type parameters must be specified on object types"))
+                        .emit();
                     tcx.types.err
                 } else {
                     // This is a default type parameter.
@@ -588,7 +591,7 @@ fn find_implied_output_region(&self,
         }
 
         if lifetimes_for_params.iter().map(|e| e.lifetime_count).sum::<usize>() == 1 {
-            Ok(possible_implied_output_region.unwrap())
+            Ok(*possible_implied_output_region.unwrap())
         } else {
             Err(Some(lifetimes_for_params))
         }
@@ -937,8 +940,8 @@ fn ast_path_to_ty(&self,
 
         // FIXME(#12938): This is a hack until we have full support for DST.
         if Some(did) == self.tcx().lang_items.owned_box() {
-            assert_eq!(substs.types.len(), 1);
-            return self.tcx().mk_box(substs.types[0]);
+            assert_eq!(substs.types().count(), 1);
+            return self.tcx().mk_box(substs.type_at(0));
         }
 
         decl_ty.subst(self.tcx(), substs)
@@ -1100,7 +1103,7 @@ fn trait_path_to_object_type(&self,
         let region_bound = match region_bound {
             Some(r) => r,
             None => {
-                match rscope.object_lifetime_default(span) {
+                tcx.mk_region(match rscope.object_lifetime_default(span) {
                     Some(r) => r,
                     None => {
                         span_err!(self.tcx().sess, span, E0228,
@@ -1108,7 +1111,7 @@ fn trait_path_to_object_type(&self,
                                    from context; please supply an explicit bound");
                         ty::ReStatic
                     }
-                }
+                })
             }
         };
 
@@ -1126,8 +1129,8 @@ fn trait_path_to_object_type(&self,
             tcx.astconv_object_safety_violations(principal.def_id());
         if !object_safety_violations.is_empty() {
             tcx.report_object_safety_error(
-                span, principal.def_id(), None, object_safety_violations)
-                .unwrap().emit();
+                span, principal.def_id(), object_safety_violations)
+                .emit();
             return tcx.types.err;
         }
 
@@ -1643,7 +1646,7 @@ pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> {
                         rscope,
                         ty::ObjectLifetimeDefault::Specific(r));
                 let t = self.ast_ty_to_ty(rscope1, &mt.ty);
-                tcx.mk_ref(tcx.mk_region(r), ty::TypeAndMut {ty: t, mutbl: mt.mutbl})
+                tcx.mk_ref(r, ty::TypeAndMut {ty: t, mutbl: mt.mutbl})
             }
             hir::TyNever => {
                 tcx.types.never
@@ -1801,7 +1804,7 @@ pub fn ty_of_method(&self,
                         sig: &hir::MethodSig,
                         untransformed_self_ty: Ty<'tcx>,
                         anon_scope: Option<AnonTypeScope>)
-                        -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) {
+                        -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory<'tcx>) {
         self.ty_of_method_or_bare_fn(sig.unsafety,
                                      sig.abi,
                                      Some(untransformed_self_ty),
@@ -1826,7 +1829,7 @@ fn ty_of_method_or_bare_fn(&self,
                                decl: &hir::FnDecl,
                                arg_anon_scope: Option<AnonTypeScope>,
                                ret_anon_scope: Option<AnonTypeScope>)
-                               -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory)
+                               -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory<'tcx>)
     {
         debug!("ty_of_method_or_bare_fn");
 
@@ -1863,7 +1866,7 @@ fn ty_of_method_or_bare_fn(&self,
         // reference) in the arguments, then any anonymous regions in the output
         // have that lifetime.
         let implied_output_region = match explicit_self_category {
-            ty::ExplicitSelfCategory::ByReference(region, _) => Ok(region),
+            ty::ExplicitSelfCategory::ByReference(region, _) => Ok(*region),
             _ => self.find_implied_output_region(&arg_tys, arg_pats)
         };
 
@@ -1875,11 +1878,16 @@ fn ty_of_method_or_bare_fn(&self,
             hir::DefaultReturn(..) => self.tcx().mk_nil(),
         };
 
+        let input_tys = self_ty.into_iter().chain(arg_tys).collect();
+
+        debug!("ty_of_method_or_bare_fn: input_tys={:?}", input_tys);
+        debug!("ty_of_method_or_bare_fn: output_ty={:?}", output_ty);
+
         (self.tcx().mk_bare_fn(ty::BareFnTy {
             unsafety: unsafety,
             abi: abi,
             sig: ty::Binder(ty::FnSig {
-                inputs: self_ty.into_iter().chain(arg_tys).collect(),
+                inputs: input_tys,
                 output: output_ty,
                 variadic: decl.variadic
             }),
@@ -1890,7 +1898,7 @@ fn determine_self_type<'a>(&self,
                                rscope: &RegionScope,
                                untransformed_self_ty: Ty<'tcx>,
                                explicit_self: &hir::ExplicitSelf)
-                               -> (Ty<'tcx>, ty::ExplicitSelfCategory)
+                               -> (Ty<'tcx>, ty::ExplicitSelfCategory<'tcx>)
     {
         return match explicit_self.node {
             SelfKind::Value(..) => {
@@ -1902,8 +1910,7 @@ fn determine_self_type<'a>(&self,
                                              rscope,
                                              explicit_self.span,
                                              lifetime);
-                (self.tcx().mk_ref(
-                    self.tcx().mk_region(region),
+                (self.tcx().mk_ref(region,
                     ty::TypeAndMut {
                         ty: untransformed_self_ty,
                         mutbl: mutability
@@ -1957,7 +1964,7 @@ fn determine_self_type<'a>(&self,
                     ty::ExplicitSelfCategory::ByValue
                 } else {
                     match explicit_type.sty {
-                        ty::TyRef(r, mt) => ty::ExplicitSelfCategory::ByReference(*r, mt.mutbl),
+                        ty::TyRef(r, mt) => ty::ExplicitSelfCategory::ByReference(r, mt.mutbl),
                         ty::TyBox(_) => ty::ExplicitSelfCategory::ByBox,
                         _ => ty::ExplicitSelfCategory::ByValue,
                     }
@@ -2070,7 +2077,7 @@ fn compute_object_lifetime_bound(&self,
         explicit_region_bounds: &[&hir::Lifetime],
         principal_trait_ref: ty::PolyExistentialTraitRef<'tcx>,
         builtin_bounds: ty::BuiltinBounds)
-        -> Option<ty::Region> // if None, use the default
+        -> Option<&'tcx ty::Region> // if None, use the default
     {
         let tcx = self.tcx();
 
@@ -2093,7 +2100,7 @@ fn compute_object_lifetime_bound(&self,
 
         if let Err(ErrorReported) =
                 self.ensure_super_predicates(span, principal_trait_ref.def_id()) {
-            return Some(ty::ReStatic);
+            return Some(tcx.mk_region(ty::ReStatic));
         }
 
         // No explicit region bound specified. Therefore, examine trait
@@ -2109,8 +2116,8 @@ fn compute_object_lifetime_bound(&self,
 
         // If any of the derived region bounds are 'static, that is always
         // the best choice.
-        if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) {
-            return Some(ty::ReStatic);
+        if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) {
+            return Some(tcx.mk_region(ty::ReStatic));
         }
 
         // Determine whether there is exactly one unique region in the set
@@ -2242,7 +2249,7 @@ fn report_lifetime_number_error(tcx: TyCtxt, span: Span, number: usize, expected
 // and return from functions in multiple places.
 #[derive(PartialEq, Eq, Clone, Debug)]
 pub struct Bounds<'tcx> {
-    pub region_bounds: Vec<ty::Region>,
+    pub region_bounds: Vec<&'tcx ty::Region>,
     pub builtin_bounds: ty::BuiltinBounds,
     pub trait_bounds: Vec<ty::PolyTraitRef<'tcx>>,
     pub projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
@@ -2264,7 +2271,7 @@ pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, param_ty: Ty<'tcx>)
         for &region_bound in &self.region_bounds {
             // account for the binder being introduced below; no need to shift `param_ty`
             // because, at present at least, it can only refer to early-bound regions
-            let region_bound = ty::fold::shift_region(region_bound, 1);
+            let region_bound = tcx.mk_region(ty::fold::shift_region(*region_bound, 1));
             vec.push(ty::Binder(ty::OutlivesPredicate(param_ty, region_bound)).to_predicate());
         }
 
index af24a7b51176ccca97c67e3f167da966e33a44a4..f8a2e82edc2a632ce445f071a129aad40cb8256d 100644 (file)
@@ -122,7 +122,7 @@ pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
                         // and T is the expected type.
                         let region_var = self.next_region_var(infer::PatternRegion(pat.span));
                         let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl };
-                        let region_ty = tcx.mk_ref(tcx.mk_region(region_var), mt);
+                        let region_ty = tcx.mk_ref(region_var, mt);
 
                         // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is
                         // required. However, we use equality, which is stronger. See (*) for
@@ -220,7 +220,7 @@ pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
                             let inner_ty = self.next_ty_var();
                             let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
                             let region = self.next_region_var(infer::PatternRegion(pat.span));
-                            let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt);
+                            let rptr_ty = tcx.mk_ref(region, mt);
                             self.demand_eqtype(pat.span, expected, rptr_ty);
                             (rptr_ty, inner_ty)
                         }
@@ -248,9 +248,12 @@ pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
                         } else if let Some(rest) = size.checked_sub(min_len) {
                             (inner_ty, tcx.mk_array(inner_ty, rest))
                         } else {
-                            span_err!(tcx.sess, pat.span, E0528,
-                                      "pattern requires at least {} elements but array has {}",
-                                      min_len, size);
+                            struct_span_err!(tcx.sess, pat.span, E0528,
+                                    "pattern requires at least {} elements but array has {}",
+                                    min_len, size)
+                                .span_label(pat.span,
+                                    &format!("pattern cannot match array of {} elements", size))
+                                .emit();
                             (inner_ty, tcx.types.err)
                         }
                     }
@@ -270,7 +273,10 @@ pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
                                     _ => {}
                                 }
                             }
-                            err.emit();
+
+                            err.span_label( pat.span,
+                                &format!("pattern cannot match with input type `{}`", expected_ty)
+                            ).emit();
                         }
                         (tcx.types.err, tcx.types.err)
                     }
@@ -347,9 +353,11 @@ pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::
                 if let ty::TyTrait(..) = mt.ty.sty {
                     // This is "x = SomeTrait" being reduced from
                     // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
-                    span_err!(self.tcx.sess, span, E0033,
-                              "type `{}` cannot be dereferenced",
-                              self.ty_to_string(expected));
+                    let type_str = self.ty_to_string(expected);
+                    struct_span_err!(self.tcx.sess, span, E0033,
+                              "type `{}` cannot be dereferenced", type_str)
+                        .span_label(span, &format!("type `{}` cannot be dereferenced", type_str))
+                        .emit();
                     return false
                 }
             }
@@ -572,7 +580,8 @@ fn check_pat_tuple_struct(&self,
                 tcx.sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
                                   pat.id, pat.span, msg);
             } else {
-                span_err!(tcx.sess, pat.span, E0164, "{}", msg);
+                struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg)
+                    .span_label(pat.span, &format!("not a tuple variant or struct")).emit();
                 on_error();
             }
         };
index 9a3cbabe553314fd77bf3719a3686c8aba61bc62..19261a2447f9100ed8b7dee42319073e7ad4fdc0 100644 (file)
@@ -101,7 +101,7 @@ fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
                 Some(f) => f,
                 None => return None
             },
-            substs: Substs::new_trait(tcx, vec![], vec![], self.cur_ty)
+            substs: Substs::new_trait(tcx, self.cur_ty, &[])
         };
 
         let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
index 985c3be149617dc388a08a2e932b92f41f1eeef9..acb6653214dcbd8847d2db5ca4c34b4f68c94687 100644 (file)
@@ -29,7 +29,7 @@
 pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: DefId) {
     if ccx.tcx.lang_items.drop_trait() == Some(trait_id) {
         struct_span_err!(ccx.tcx.sess, span, E0040, "explicit use of destructor method")
-            .span_label(span, &format!("call to destructor method"))
+            .span_label(span, &format!("explicit destructor calls not allowed"))
             .emit();
     }
 }
index fb78d3a37ca236404c5706916566637f1d3be83c..54e63497e6202debd71f51d8392dda6c2e4613d6 100644 (file)
@@ -161,6 +161,7 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, e: CastError) {
             }
             CastError::CastToBool => {
                 struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`")
+                    .span_label(self.span, &format!("unsupported cast"))
                     .help("compare with zero instead")
                     .emit();
             }
index 377ca5eaebe302745e97093c011a20cb5ae1571f..8980cb9076027aa5d7cf3693f3c313d12d7649ee 100644 (file)
@@ -74,6 +74,8 @@ fn check_closure(&self,
 
         let fn_sig = self.tcx.liberate_late_bound_regions(
             self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig);
+        let fn_sig =
+            (**self).normalize_associated_types_in(body.span, body.id, &fn_sig);
 
         check_fn(self, hir::Unsafety::Normal, expr.id, &fn_sig, decl, expr.id, &body);
 
@@ -165,7 +167,6 @@ fn deduce_expectations_from_obligations(&self, expected_vid: ty::TyVid)
                     ty::Predicate::TypeOutlives(..) => None,
                     ty::Predicate::WellFormed(..) => None,
                     ty::Predicate::ObjectSafe(..) => None,
-                    ty::Predicate::Rfc1592(..) => None,
 
                     // NB: This predicate is created by breaking down a
                     // `ClosureType: FnFoo()` predicate, where
@@ -203,7 +204,7 @@ fn deduce_sig_from_projection(&self,
             return None;
         }
 
-        let arg_param_ty = trait_ref.substs().types[1];
+        let arg_param_ty = trait_ref.substs().type_at(1);
         let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
         debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty);
 
index 4a0d529812891f48049e128824b5cec7cf8b1ece..365c18d5e666123481616e32034108c9d051dfd0 100644 (file)
@@ -336,7 +336,7 @@ fn coerce_borrowed_pointer<'a, E, I>(&self,
                 if r_borrow_var.is_none() { // create var lazilly, at most once
                     let coercion = Coercion(span);
                     let r = self.next_region_var(coercion);
-                    r_borrow_var = Some(self.tcx.mk_region(r)); // [4] above
+                    r_borrow_var = Some(r); // [4] above
                 }
                 r_borrow_var.unwrap()
             };
@@ -436,8 +436,7 @@ fn coerce_unsized(&self,
 
                 let coercion = Coercion(self.origin.span());
                 let r_borrow = self.next_region_var(coercion);
-                let region = self.tcx.mk_region(r_borrow);
-                (mt_a.ty, Some(AutoPtr(region, mt_b.mutbl)))
+                (mt_a.ty, Some(AutoPtr(r_borrow, mt_b.mutbl)))
             }
             (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
                 coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
@@ -459,7 +458,7 @@ fn coerce_unsized(&self,
                                                          coerce_unsized_did,
                                                          0,
                                                          source,
-                                                         vec![target]));
+                                                         &[target]));
 
         // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
         // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
@@ -485,7 +484,7 @@ fn coerce_unsized(&self,
 
                 // Object safety violations or miscellaneous.
                 Err(err) => {
-                    self.report_selection_error(&obligation, &err, None);
+                    self.report_selection_error(&obligation, &err);
                     // Treat this like an obligation and follow through
                     // with the unsizing - the lack of a coercion should
                     // be silent, as it causes a type mismatch later.
index 6bcf21563cb98c919e907e2e4f431660f6cb7b86..1604f34d575528209544e2eb2a52aa2890e67d01 100644 (file)
 use rustc::infer::{self, InferOk, TypeOrigin};
 use rustc::ty;
 use rustc::traits::{self, Reveal};
-use rustc::ty::error::ExpectedFound;
+use rustc::ty::error::{ExpectedFound, TypeError};
 use rustc::ty::subst::{Subst, Substs};
-use rustc::hir::map::Node;
-use rustc::hir::{ImplItemKind, TraitItem_};
+use rustc::hir::{ImplItemKind, TraitItem_, Ty_};
 
 use syntax::ast;
 use syntax_pos::Span;
@@ -303,7 +302,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
             unsafety: impl_m.fty.unsafety,
             abi: impl_m.fty.abi,
-            sig: ty::Binder(impl_sig)
+            sig: ty::Binder(impl_sig.clone())
         }));
         debug!("compare_impl_method: impl_fty={:?}", impl_fty);
 
@@ -321,7 +320,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
             unsafety: trait_m.fty.unsafety,
             abi: trait_m.fty.abi,
-            sig: ty::Binder(trait_sig)
+            sig: ty::Binder(trait_sig.clone())
         }));
 
         debug!("compare_impl_method: trait_fty={:?}", trait_fty);
@@ -331,16 +330,26 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                    impl_fty,
                    trait_fty);
 
+            let (impl_err_span, trait_err_span) =
+                extract_spans_for_error_reporting(&infcx, &terr, origin, impl_m,
+                    impl_sig, trait_m, trait_sig);
+
+            let origin = TypeOrigin::MethodCompatCheck(impl_err_span);
+
             let mut diag = struct_span_err!(
                 tcx.sess, origin.span(), E0053,
                 "method `{}` has an incompatible type for trait", trait_m.name
             );
+
             infcx.note_type_err(
-                &mut diag, origin,
+                &mut diag,
+                origin,
+                trait_err_span.map(|sp| (sp, format!("type in trait"))),
                 Some(infer::ValuePairs::Types(ExpectedFound {
-                    expected: trait_fty,
-                    found: impl_fty
-                })), &terr
+                     expected: trait_fty,
+                     found: impl_fty
+                })),
+                &terr
             );
             diag.emit();
             return
@@ -402,15 +411,96 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         // are zero. Since I don't quite know how to phrase things at
         // the moment, give a kind of vague error message.
         if trait_params.len() != impl_params.len() {
-            span_err!(ccx.tcx.sess, span, E0195,
+            struct_span_err!(ccx.tcx.sess, span, E0195,
                 "lifetime parameters or bounds on method `{}` do \
-                         not match the trait declaration",
-                         impl_m.name);
+                 not match the trait declaration",impl_m.name)
+                .span_label(span, &format!("lifetimes do not match trait"))
+                .emit();
             return false;
         }
 
         return true;
     }
+
+    fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
+                                                         terr: &TypeError,
+                                                         origin: TypeOrigin,
+                                                         impl_m: &ty::Method,
+                                                         impl_sig: ty::FnSig<'tcx>,
+                                                         trait_m: &ty::Method,
+                                                         trait_sig: ty::FnSig<'tcx>)
+                                                        -> (Span, Option<Span>) {
+        let tcx = infcx.tcx;
+        let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
+        let (impl_m_output, impl_m_iter) = match tcx.map.expect_impl_item(impl_m_node_id).node {
+            ImplItemKind::Method(ref impl_m_sig, _) =>
+                (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter()),
+            _ => bug!("{:?} is not a method", impl_m)
+        };
+
+        match *terr {
+            TypeError::Mutability => {
+                if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
+                    let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
+                        TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
+                            trait_m_sig.decl.inputs.iter(),
+                        _ => bug!("{:?} is not a MethodTraitItem", trait_m)
+                    };
+
+                    impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
+                        match (&impl_arg.ty.node, &trait_arg.ty.node) {
+                            (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
+                            (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) =>
+                                impl_mt.mutbl != trait_mt.mutbl,
+                            _ => false
+                        }
+                    }).map(|(ref impl_arg, ref trait_arg)| {
+                        match (impl_arg.to_self(), trait_arg.to_self()) {
+                            (Some(impl_self), Some(trait_self)) =>
+                                (impl_self.span, Some(trait_self.span)),
+                            (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
+                            _ => bug!("impl and trait fns have different first args, \
+                                       impl: {:?}, trait: {:?}", impl_arg, trait_arg)
+                        }
+                    }).unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
+                } else {
+                    (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+                }
+            }
+            TypeError::Sorts(ExpectedFound { .. }) => {
+                if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
+                    let (trait_m_output, trait_m_iter) =
+                    match tcx.map.expect_trait_item(trait_m_node_id).node {
+                        TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
+                            (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter()),
+                        _ => bug!("{:?} is not a MethodTraitItem", trait_m)
+                    };
+
+                    let impl_iter = impl_sig.inputs.iter();
+                    let trait_iter = trait_sig.inputs.iter();
+                    impl_iter.zip(trait_iter).zip(impl_m_iter).zip(trait_m_iter)
+                        .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
+                            match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) {
+                                Ok(_) => None,
+                                Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span)))
+                            }
+                        })
+                        .next()
+                        .unwrap_or_else(|| {
+                            if infcx.sub_types(false, origin, impl_sig.output,
+                                               trait_sig.output).is_err() {
+                                (impl_m_output.span(), Some(trait_m_output.span()))
+                            } else {
+                                (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+                            }
+                        })
+                } else {
+                    (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+                }
+            }
+            _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+        }
+    }
 }
 
 pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
@@ -487,12 +577,9 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                    trait_ty);
 
             // Locate the Span containing just the type of the offending impl
-            if let Some(impl_trait_node) = tcx.map.get_if_local(impl_c.def_id) {
-                if let Node::NodeImplItem(impl_trait_item) = impl_trait_node {
-                    if let ImplItemKind::Const(ref ty, _) = impl_trait_item.node {
-                        origin = TypeOrigin::Misc(ty.span);
-                    }
-                }
+            match tcx.map.expect_impl_item(impl_c_node_id).node {
+                ImplItemKind::Const(ref ty, _) => origin = TypeOrigin::Misc(ty.span),
+                _ => bug!("{:?} is not a impl const", impl_c)
             }
 
             let mut diag = struct_span_err!(
@@ -502,16 +589,16 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             );
 
             // Add a label to the Span containing just the type of the item
-            if let Some(orig_trait_node) = tcx.map.get_if_local(trait_c.def_id) {
-                if let Node::NodeTraitItem(orig_trait_item) = orig_trait_node {
-                    if let TraitItem_::ConstTraitItem(ref ty, _) = orig_trait_item.node {
-                        diag.span_label(ty.span, &format!("original trait requirement"));
-                    }
-                }
-            }
+            let trait_c_node_id = tcx.map.as_local_node_id(trait_c.def_id).unwrap();
+            let trait_c_span = match tcx.map.expect_trait_item(trait_c_node_id).node {
+                TraitItem_::ConstTraitItem(ref ty, _) => ty.span,
+                _ => bug!("{:?} is not a trait const", trait_c)
+            };
 
             infcx.note_type_err(
-                &mut diag, origin,
+                &mut diag,
+                origin,
+                Some((trait_c_span, format!("type in trait"))),
                 Some(infer::ValuePairs::Types(ExpectedFound {
                     expected: trait_ty,
                     found: impl_ty
index 82545d564a20c807f69fd91e3e7b82d4f877cf2b..3a6076774330dcd26fad834b0fd871d402493478 100644 (file)
@@ -111,10 +111,6 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
             return Err(());
         }
 
-    if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) {
-        infcx.report_fulfillment_errors_as_warnings(errors, drop_impl_node_id);
-    }
-
         let free_regions = FreeRegionMap::new();
         infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_node_id);
         Ok(())
@@ -412,7 +408,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
                ty);
 
         cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span),
-                                 ty, ty::ReScope(cx.parent_scope));
+                                 ty, tcx.mk_region(ty::ReScope(cx.parent_scope)));
 
         return Ok(());
     }
@@ -438,7 +434,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
 
         ty::TyStruct(def, substs) if def.is_phantom_data() => {
             // PhantomData<T> - behaves identically to T
-            let ity = substs.types[0];
+            let ity = substs.type_at(0);
             iterate_over_potentially_unsafe_regions_in_type(
                 cx, context, ity, depth+1)
         }
index b2873bf686578bed51c985eafd2d4a125a7fdab0..bde7f20f5e6e6e385a3155db980451f5bae52430 100644 (file)
@@ -16,9 +16,9 @@
 use rustc::ty::subst::Substs;
 use rustc::ty::FnSig;
 use rustc::ty::{self, Ty};
+use rustc::util::nodemap::FnvHashMap;
 use {CrateCtxt, require_same_types};
 
-use std::collections::{HashMap};
 use syntax::abi::Abi;
 use syntax::ast;
 use syntax::parse::token;
@@ -37,7 +37,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let i_ty = tcx.lookup_item_type(def_id);
 
     let substs = Substs::for_item(tcx, def_id,
-                                  |_, _| ty::ReErased,
+                                  |_, _| tcx.mk_region(ty::ReErased),
                                   |def, _| tcx.mk_param_from_def(def));
 
     let fty = tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy {
@@ -51,12 +51,17 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }));
     let i_n_tps = i_ty.generics.types.len();
     if i_n_tps != n_tps {
-        struct_span_err!(tcx.sess, it.span, E0094,
-            "intrinsic has wrong number of type \
-             parameters: found {}, expected {}",
-             i_n_tps, n_tps)
-             .span_label(it.span, &format!("expected {} type parameter", n_tps))
-             .emit();
+        let span = match it.node {
+            hir::ForeignItemFn(_, ref generics) => generics.span,
+            hir::ForeignItemStatic(_, _) => it.span
+        };
+
+        struct_span_err!(tcx.sess, span, E0094,
+                        "intrinsic has wrong number of type \
+                        parameters: found {}, expected {}",
+                        i_n_tps, n_tps)
+            .span_label(span, &format!("expected {} type parameter", n_tps))
+            .emit();
     } else {
         require_same_types(ccx,
                            TypeOrigin::IntrinsicType(it.span),
@@ -122,7 +127,7 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
                  ], ccx.tcx.types.usize)
             }
             "rustc_peek" => (1, vec![param(ccx, 0)], param(ccx, 0)),
-            "init" | "init_dropped" => (1, Vec::new(), param(ccx, 0)),
+            "init" => (1, Vec::new(), param(ccx, 0)),
             "uninit" => (1, Vec::new(), param(ccx, 0)),
             "forget" => (1, vec!( param(ccx, 0) ), tcx.mk_nil()),
             "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)),
@@ -301,8 +306,11 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
             }
 
             ref other => {
-                span_err!(tcx.sess, it.span, E0093,
-                          "unrecognized intrinsic function: `{}`", *other);
+                struct_span_err!(tcx.sess, it.span, E0093,
+                                "unrecognized intrinsic function: `{}`",
+                                *other)
+                                .span_label(it.span, &format!("unrecognized intrinsic"))
+                                .emit();
                 return;
             }
         };
@@ -362,7 +370,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
                         return
                     }
 
-                    let mut structural_to_nomimal = HashMap::new();
+                    let mut structural_to_nomimal = FnvHashMap();
 
                     let sig = tcx.no_late_bound_regions(i_ty.ty.fn_sig()).unwrap();
                     if intr.inputs.len() != sig.inputs.len() {
@@ -402,7 +410,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
         ccx: &CrateCtxt<'a, 'tcx>,
         position: &str,
         span: Span,
-        structural_to_nominal: &mut HashMap<&'a intrinsics::Type, ty::Ty<'tcx>>,
+        structural_to_nominal: &mut FnvHashMap<&'a intrinsics::Type, ty::Ty<'tcx>>,
         expected: &'a intrinsics::Type, t: ty::Ty<'tcx>)
 {
     use intrinsics::Type::*;
index 9e0b38fd9fe517a163c9cffcdfce403b394f8b31..be77ca435a18c8f27e580abf1c6c94709c52d599 100644 (file)
@@ -145,7 +145,7 @@ fn adjust_self_ty(&mut self,
     {
         let (autoref, unsize) = if let Some(mutbl) = pick.autoref {
             let region = self.next_region_var(infer::Autoref(self.span));
-            let autoref = AutoPtr(self.tcx.mk_region(region), mutbl);
+            let autoref = AutoPtr(region, mutbl);
             (Some(autoref), pick.unsize.map(|target| {
                 target.adjust_for_autoref(self.tcx, Some(autoref))
             }))
@@ -327,19 +327,22 @@ fn instantiate_method_substs(&mut self,
         // parameters from the type and those from the method.
         //
         // FIXME -- permit users to manually specify lifetimes
+        let supplied_start = substs.params().len() + method.generics.regions.len();
         Substs::for_item(self.tcx, method.def_id, |def, _| {
-            if let Some(&r) = substs.regions.get(def.index as usize) {
-                r
+            let i = def.index as usize;
+            if i < substs.params().len() {
+                substs.region_at(i)
             } else {
                 self.region_var_for_def(self.span, def)
             }
         }, |def, cur_substs| {
-            if let Some(&ty) = substs.types.get(def.index as usize) {
-                ty
+            let i = def.index as usize;
+            if i < substs.params().len() {
+                substs.type_at(i)
             } else if supplied_method_types.is_empty() {
                 self.type_var_for_def(self.span, def, cur_substs)
             } else {
-                supplied_method_types[def.index as usize - substs.types.len()]
+                supplied_method_types[i - supplied_start]
             }
         })
     }
index c306463ec1de0795b7352e6a01cf89a90462543c..2e2cb2765d93de6493105de55f2945865cb7a6b5 100644 (file)
 use rustc::traits;
 use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable};
 use rustc::infer::{InferOk, TypeOrigin};
+use rustc::util::nodemap::FnvHashSet;
 use syntax::ast;
 use syntax_pos::{Span, DUMMY_SP};
 use rustc::hir;
-use std::collections::HashSet;
 use std::mem;
 use std::ops::Deref;
 use std::rc::Rc;
@@ -40,7 +40,7 @@ struct ProbeContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     opt_simplified_steps: Option<Vec<ty::fast_reject::SimplifiedType>>,
     inherent_candidates: Vec<Candidate<'tcx>>,
     extension_candidates: Vec<Candidate<'tcx>>,
-    impl_dups: HashSet<DefId>,
+    impl_dups: FnvHashSet<DefId>,
     import_id: Option<ast::NodeId>,
 
     /// Collects near misses when the candidate functions are missing a `self` keyword and is only
@@ -255,7 +255,7 @@ fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
             item_name: item_name,
             inherent_candidates: Vec::new(),
             extension_candidates: Vec::new(),
-            impl_dups: HashSet::new(),
+            impl_dups: FnvHashSet(),
             import_id: None,
             steps: Rc::new(steps),
             opt_simplified_steps: opt_simplified_steps,
@@ -496,7 +496,6 @@ fn assemble_inherent_candidates_from_param(&mut self,
                     ty::Predicate::WellFormed(..) |
                     ty::Predicate::ObjectSafe(..) |
                     ty::Predicate::ClosureKind(..) |
-                    ty::Predicate::Rfc1592(..) |
                     ty::Predicate::TypeOutlives(..) => {
                         None
                     }
@@ -519,9 +518,9 @@ fn assemble_inherent_candidates_from_param(&mut self,
                        trait_ref.substs,
                        m);
                 assert_eq!(m.generics.parent_types as usize,
-                           trait_ref.substs.types.len());
+                           trait_ref.substs.types().count());
                 assert_eq!(m.generics.parent_regions as usize,
-                           trait_ref.substs.regions.len());
+                           trait_ref.substs.regions().count());
             }
 
             // Because this trait derives from a where-clause, it
@@ -529,7 +528,7 @@ fn assemble_inherent_candidates_from_param(&mut self,
             // artifacts. This means it is safe to put into the
             // `WhereClauseCandidate` and (eventually) into the
             // `WhereClausePick`.
-            assert!(!trait_ref.substs.types.needs_infer());
+            assert!(!trait_ref.substs.needs_infer());
 
             this.inherent_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
@@ -574,7 +573,7 @@ fn assemble_extension_candidates_for_traits_in_scope(&mut self,
                                                          expr_id: ast::NodeId)
                                                          -> Result<(), MethodError<'tcx>>
     {
-        let mut duplicates = HashSet::new();
+        let mut duplicates = FnvHashSet();
         let opt_applicable_traits = self.tcx.trait_map.get(&expr_id);
         if let Some(applicable_traits) = opt_applicable_traits {
             for trait_candidate in applicable_traits {
@@ -591,7 +590,7 @@ fn assemble_extension_candidates_for_traits_in_scope(&mut self,
     }
 
     fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(), MethodError<'tcx>> {
-        let mut duplicates = HashSet::new();
+        let mut duplicates = FnvHashSet();
         for trait_info in suggest::all_traits(self.ccx) {
             if duplicates.insert(trait_info.def_id) {
                 self.assemble_extension_candidates_for_trait(trait_info.def_id)?;
@@ -1220,8 +1219,8 @@ fn xform_method_self_ty(&self,
         // are given do not include type/lifetime parameters for the
         // method yet. So create fresh variables here for those too,
         // if there are any.
-        assert_eq!(substs.types.len(), method.generics.parent_types as usize);
-        assert_eq!(substs.regions.len(), method.generics.parent_regions as usize);
+        assert_eq!(substs.types().count(), method.generics.parent_types as usize);
+        assert_eq!(substs.regions().count(), method.generics.parent_regions as usize);
 
         if self.mode == Mode::Path {
             return impl_ty;
@@ -1236,16 +1235,18 @@ fn xform_method_self_ty(&self,
             xform_self_ty.subst(self.tcx, substs)
         } else {
             let substs = Substs::for_item(self.tcx, method.def_id, |def, _| {
-                if let Some(&r) = substs.regions.get(def.index as usize) {
-                    r
+                let i = def.index as usize;
+                if i < substs.params().len() {
+                    substs.region_at(i)
                 } else {
                     // In general, during probe we erase regions. See
                     // `impl_self_ty()` for an explanation.
-                    ty::ReErased
+                    self.tcx.mk_region(ty::ReErased)
                 }
             }, |def, cur_substs| {
-                if let Some(&ty) = substs.types.get(def.index as usize) {
-                    ty
+                let i = def.index as usize;
+                if i < substs.params().len() {
+                    substs.type_at(i)
                 } else {
                     self.type_var_for_def(self.span, def, cur_substs)
                 }
@@ -1262,7 +1263,7 @@ fn impl_ty_and_substs(&self,
         let impl_ty = self.tcx.lookup_item_type(impl_def_id).ty;
 
         let substs = Substs::for_item(self.tcx, impl_def_id,
-                                      |_, _| ty::ReErased,
+                                      |_, _| self.tcx.mk_region(ty::ReErased),
                                       |_, _| self.next_ty_var());
 
         (impl_ty, substs)
@@ -1324,7 +1325,7 @@ fn to_unadjusted_pick(&self) -> Pick<'tcx> {
                     // inference variables or other artifacts. This
                     // means they are safe to put into the
                     // `WhereClausePick`.
-                    assert!(!trait_ref.substs().types.needs_infer());
+                    assert!(!trait_ref.substs().needs_infer());
 
                     WhereClausePick(trait_ref.clone())
                 }
index 573dae46456baa2f3b78146e3bab014e63112671..46b3f503b6e763e954207eeef065f12850ec2004 100644 (file)
@@ -54,7 +54,7 @@ fn is_fn_ty(&self, ty: &Ty<'tcx>, span: Span) -> bool {
 
                 self.autoderef(span, ty).any(|(ty, _)| self.probe(|_| {
                     let fn_once_substs =
-                        Substs::new_trait(tcx, vec![self.next_ty_var()], vec![], ty);
+                        Substs::new_trait(tcx, ty, &[self.next_ty_var()]);
                     let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
                     let poly_trait_ref = trait_ref.to_poly_trait_ref();
                     let obligation = Obligation::misc(span,
@@ -242,6 +242,7 @@ macro_rules! report_function {
             MethodError::Ambiguity(sources) => {
                 let mut err = struct_span_err!(self.sess(), span, E0034,
                                                "multiple applicable items in scope");
+                err.span_label(span, &format!("multiple `{}` found", item_name));
 
                 report_candidates(&mut err, sources);
                 err.emit();
index e573655b8c9847ffd045a7e07110e0e7109c1130..90a9d9bffe7dc2420a055b4494e39af654b4637a 100644 (file)
 use TypeAndSubsts;
 use lint;
 use util::common::{block_query, ErrorReported, indenter, loop_query};
-use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
+use util::nodemap::{DefIdMap, FnvHashMap, FnvHashSet, NodeMap};
 
 use std::cell::{Cell, Ref, RefCell};
-use std::collections::{HashSet};
 use std::mem::replace;
 use std::ops::Deref;
 use syntax::abi::Abi;
 use syntax::ast;
 use syntax::attr;
-use syntax::attr::AttrMetaMethods;
 use syntax::codemap::{self, Spanned};
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::parse::token::{self, InternedString, keywords};
@@ -507,10 +505,6 @@ pub fn check_item_bodies(ccx: &CrateCtxt) -> CompileResult {
                 if let Err(errors) = fulfillment_cx.select_all_or_error(&infcx) {
                     infcx.report_fulfillment_errors(&errors);
                 }
-
-                if let Err(errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) {
-                    infcx.report_fulfillment_errors_as_warnings(&errors, item_id);
-                }
             });
         }
     })
@@ -708,7 +702,13 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
 
     inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
 
-    fcx.check_block_with_expected(body, ExpectHasType(fcx.ret_ty));
+    // FIXME(aburka) do we need this special case? and should it be is_uninhabited?
+    let expected = if fcx.ret_ty.is_never() {
+        NoExpectation
+    } else {
+        ExpectHasType(fcx.ret_ty)
+    };
+    fcx.check_block_with_expected(body, expected);
 
     fcx
 }
@@ -764,7 +764,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
       }
       hir::ItemTy(_, ref generics) => {
         let pty_ty = ccx.tcx.node_id_to_type(it.id);
-        check_bounds_are_used(ccx, &generics.ty_params, pty_ty);
+        check_bounds_are_used(ccx, generics, pty_ty);
       }
       hir::ItemForeignMod(ref m) => {
         if m.abi == Abi::RustIntrinsic {
@@ -830,13 +830,9 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
                     check_const(ccx, &expr, trait_item.id)
                 }
                 hir::MethodTraitItem(ref sig, Some(ref body)) => {
-                    check_trait_fn_not_const(ccx, trait_item.span, sig.constness);
-
                     check_bare_fn(ccx, &sig.decl, body, trait_item.id);
                 }
-                hir::MethodTraitItem(ref sig, None) => {
-                    check_trait_fn_not_const(ccx, trait_item.span, sig.constness);
-                }
+                hir::MethodTraitItem(_, None) |
                 hir::ConstTraitItem(_, None) |
                 hir::TypeTraitItem(..) => {
                     // Nothing to do.
@@ -848,22 +844,6 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
     }
 }
 
-fn check_trait_fn_not_const<'a,'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                     span: Span,
-                                     constness: hir::Constness)
-{
-    match constness {
-        hir::Constness::NotConst => {
-            // good
-        }
-        hir::Constness::Const => {
-            struct_span_err!(ccx.tcx.sess, span, E0379, "trait fns cannot be declared const")
-                .span_label(span, &format!("trait fns cannot be const"))
-                .emit()
-        }
-    }
-}
-
 fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                     def_id: DefId,
                                     item: &hir::Item) {
@@ -903,9 +883,12 @@ fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 }
             }
         } else {
-            span_err!(ccx.tcx.sess, attr.span, E0232,
-                                  "this attribute must have a value, \
-                                   eg `#[rustc_on_unimplemented = \"foo\"]`")
+            struct_span_err!(
+                ccx.tcx.sess, attr.span, E0232,
+                "this attribute must have a value")
+                .span_label(attr.span, &format!("attribute requires a value"))
+                .note(&format!("eg `#[rustc_on_unimplemented = \"foo\"]`"))
+                .emit();
         }
     }
 }
@@ -916,14 +899,18 @@ fn report_forbidden_specialization<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 {
     let mut err = struct_span_err!(
         tcx.sess, impl_item.span, E0520,
-        "item `{}` is provided by an `impl` that specializes \
-         another, but the item in the parent `impl` is not \
-         marked `default` and so it cannot be specialized.",
+        "`{}` specializes an item from a parent `impl`, but \
+         neither that item nor the `impl` are marked `default`",
         impl_item.name);
+    err.span_label(impl_item.span, &format!("cannot specialize default item `{}`",
+                                            impl_item.name));
 
     match tcx.span_of_impl(parent_impl) {
         Ok(span) => {
-            err.span_note(span, "parent implementation is here:");
+            err.span_label(span, &"parent `impl` is here");
+            err.note(&format!("to specialize, either the parent `impl` or `{}` \
+                               in the parent `impl` must be marked `default`",
+                              impl_item.name));
         }
         Err(cname) => {
             err.note(&format!("parent implementation is in crate `{}`", cname));
@@ -1013,14 +1000,12 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                          // We can only get the spans from local trait definition
                          // Same for E0324 and E0325
                          if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) {
-                            err.span_label(trait_span, &format!("original trait requirement"));
+                            err.span_label(trait_span, &format!("item in trait"));
                          }
                          err.emit()
                     }
                 }
-                hir::ImplItemKind::Method(ref sig, ref body) => {
-                    check_trait_fn_not_const(ccx, impl_item.span, sig.constness);
-
+                hir::ImplItemKind::Method(_, ref body) => {
                     let impl_method = match ty_impl_item {
                         ty::MethodTraitItem(ref mti) => mti,
                         _ => span_bug!(impl_item.span, "non-method impl-item for method")
@@ -1041,7 +1026,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                   impl_trait_ref);
                          err.span_label(impl_item.span, &format!("does not match trait"));
                          if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) {
-                            err.span_label(trait_span, &format!("original trait requirement"));
+                            err.span_label(trait_span, &format!("item in trait"));
                          }
                          err.emit()
                     }
@@ -1064,7 +1049,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                   impl_trait_ref);
                          err.span_label(impl_item.span, &format!("does not match trait"));
                          if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) {
-                            err.span_label(trait_span, &format!("original trait requirement"));
+                            err.span_label(trait_span, &format!("item in trait"));
                          }
                          err.emit()
                     }
@@ -1219,7 +1204,9 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, id: ast::Node
             }
             let e = fields[0].ty(tcx, substs);
             if !fields.iter().all(|f| f.ty(tcx, substs) == e) {
-                span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous");
+                struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous")
+                                .span_label(sp, &format!("SIMD elements must have the same type"))
+                                .emit();
                 return;
             }
             match e.sty {
@@ -1245,8 +1232,11 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
     let hint = *ccx.tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny);
 
     if hint != attr::ReprAny && vs.is_empty() {
-        span_err!(ccx.tcx.sess, sp, E0084,
-            "unsupported representation for zero-variant enum");
+        struct_span_err!(
+            ccx.tcx.sess, sp, E0084,
+            "unsupported representation for zero-variant enum")
+            .span_label(sp, &format!("unsupported enum representation"))
+            .emit();
     }
 
     let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx);
@@ -1410,13 +1400,13 @@ fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
         // (and anyway, within a fn body the right region may not even
         // be something the user can write explicitly, since it might
         // be some expression).
-        self.next_region_var(infer::MiscVariable(span))
+        *self.next_region_var(infer::MiscVariable(span))
     }
 
     fn anon_regions(&self, span: Span, count: usize)
                     -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
         Ok((0..count).map(|_| {
-            self.next_region_var(infer::MiscVariable(span))
+            *self.next_region_var(infer::MiscVariable(span))
         }).collect())
     }
 }
@@ -1850,7 +1840,7 @@ pub fn opt_node_ty_substs<F>(&self,
     /// outlive the region `r`.
     pub fn register_region_obligation(&self,
                                       ty: Ty<'tcx>,
-                                      region: ty::Region,
+                                      region: &'tcx ty::Region,
                                       cause: traits::ObligationCause<'tcx>)
     {
         let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
@@ -1881,13 +1871,13 @@ pub fn register_old_wf_obligation(&self,
         //
         // FIXME(#27579) all uses of this should be migrated to register_wf_obligation eventually
         let cause = traits::ObligationCause::new(span, self.body_id, code);
-        self.register_region_obligation(ty, ty::ReEmpty, cause);
+        self.register_region_obligation(ty, self.tcx.mk_region(ty::ReEmpty), cause);
     }
 
     /// Registers obligations that all types appearing in `substs` are well-formed.
     pub fn add_wf_bounds(&self, substs: &Substs<'tcx>, expr: &hir::Expr)
     {
-        for &ty in &substs.types {
+        for ty in substs.types() {
             self.register_wf_obligation(ty, expr.span, traits::MiscObligation);
         }
     }
@@ -2033,7 +2023,7 @@ fn new_select_all_obligations_and_apply_defaults(&self) {
                     .filter_map(|t| self.default(t).map(|d| (t, d)))
                     .collect();
 
-            let mut unbound_tyvars = HashSet::new();
+            let mut unbound_tyvars = FnvHashSet();
 
             debug!("select_all_obligations_and_apply_defaults: defaults={:?}", default_map);
 
@@ -2180,7 +2170,7 @@ fn new_select_all_obligations_and_apply_defaults(&self) {
     // table then apply defaults until we find a conflict. That default must be the one
     // that caused conflict earlier.
     fn find_conflicting_default(&self,
-                                unbound_vars: &HashSet<Ty<'tcx>>,
+                                unbound_vars: &FnvHashSet<Ty<'tcx>>,
                                 default_map: &FnvHashMap<&Ty<'tcx>, type_variable::Default<'tcx>>,
                                 conflict: Ty<'tcx>)
                                 -> Option<type_variable::Default<'tcx>> {
@@ -2251,10 +2241,6 @@ fn select_all_obligations_or_error(&self) {
             Ok(()) => { }
             Err(errors) => { self.report_fulfillment_errors(&errors); }
         }
-
-        if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(self) {
-            self.report_fulfillment_errors_as_warnings(errors, self.body_id);
-        }
     }
 
     /// Select as many obligations as we can at present.
@@ -3000,6 +2986,10 @@ fn check_field(&self,
                          but no field with that name was found",
                         field.node, actual)
             }, expr_t);
+            if let ty::TyRawPtr(..) = expr_t.sty {
+                err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \
+                                  `(*{0}).{1}`", pprust::expr_to_string(base), field.node));
+            }
             if let ty::TyStruct(def, _) = expr_t.sty {
                 Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
             }
@@ -3438,7 +3428,7 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
                 // value whose address was taken can actually be made to live
                 // as long as it needs to live.
                 let region = self.next_region_var(infer::AddrOfRegion(expr.span));
-                tcx.mk_ref(tcx.mk_region(region), tm)
+                tcx.mk_ref(region, tm)
             };
             self.write_ty(id, oprnd_t);
           }
@@ -4226,18 +4216,23 @@ pub fn instantiate_value_path(&self,
         self.check_path_parameter_count(span, !require_type_space, &mut type_segment);
         self.check_path_parameter_count(span, true, &mut fn_segment);
 
+        let (fn_start, has_self) = match (type_segment, fn_segment) {
+            (_, Some((_, generics))) => {
+                (generics.parent_count(), generics.has_self)
+            }
+            (Some((_, generics)), None) => {
+                (generics.own_count(), generics.has_self)
+            }
+            (None, None) => (0, false)
+        };
         let substs = Substs::for_item(self.tcx, def.def_id(), |def, _| {
             let mut i = def.index as usize;
-            let type_regions = match (type_segment, fn_segment) {
-                (_, Some((_, generics))) => generics.parent_regions as usize,
-                (Some((_, generics)), None) => generics.regions.len(),
-                (None, None) => 0
-            };
 
-            let segment = if i < type_regions {
+            let segment = if i < fn_start {
+                i -= has_self as usize;
                 type_segment
             } else {
-                i -= type_regions;
+                i -= fn_start;
                 fn_segment
             };
             let lifetimes = match segment.map(|(s, _)| &s.parameters) {
@@ -4253,18 +4248,9 @@ pub fn instantiate_value_path(&self,
             }
         }, |def, substs| {
             let mut i = def.index as usize;
-            let (type_types, has_self) = match (type_segment, fn_segment) {
-                (_, Some((_, generics))) => {
-                    (generics.parent_types as usize, generics.has_self)
-                }
-                (Some((_, generics)), None) => {
-                    (generics.types.len(), generics.has_self)
-                }
-                (None, None) => (0, false)
-            };
 
-            let can_omit = i >= type_types || !require_type_space;
-            let segment = if i < type_types {
+            let can_omit = i >= fn_start || !require_type_space;
+            let segment = if i < fn_start {
                 // Handle Self first, so we can adjust the index to match the AST.
                 if has_self && i == 0 {
                     return opt_self_ty.unwrap_or_else(|| {
@@ -4274,7 +4260,7 @@ pub fn instantiate_value_path(&self,
                 i -= has_self as usize;
                 type_segment
             } else {
-                i -= type_types;
+                i -= fn_start;
                 fn_segment
             };
             let types = match segment.map(|(s, _)| &s.parameters) {
@@ -4283,6 +4269,11 @@ pub fn instantiate_value_path(&self,
                 None => &[]
             };
 
+            // Skip over the lifetimes in the same segment.
+            if let Some((_, generics)) = segment {
+                i -= generics.regions.len();
+            }
+
             let omitted = can_omit && types.is_empty();
             if let Some(ast_ty) = types.get(i) {
                 // A provided type parameter.
@@ -4404,22 +4395,25 @@ fn check_path_parameter_count(&self,
                               expected at most {}, found {}",
                              count(type_defs.len()),
                              count(types.len()))
-                .span_label(span, &format!("expected {}",
-                            count(type_defs.len()))).emit();
+                .span_label(span, &format!("too many type parameters")).emit();
 
             // To prevent derived errors to accumulate due to extra
             // type parameters, we force instantiate_value_path to
             // use inference variables instead of the provided types.
             *segment = None;
         } else if !(can_omit && types.len() == 0) && types.len() < required_len {
-            let qualifier =
-                if type_defs.len() != required_len { "at least " } else { "" };
-            span_err!(self.tcx.sess, span, E0089,
-                      "too few type parameters provided: \
-                       expected {}{}, found {}",
-                      qualifier,
-                      count(required_len),
-                      count(types.len()));
+            let adjust = |len| if len > 1 { "parameters" } else { "parameter" };
+            let required_param_str = adjust(required_len);
+            let actual_param_str = adjust(types.len());
+            struct_span_err!(self.tcx.sess, span, E0089,
+                             "too few type parameters provided: \
+                              expected {} {}, found {} {}",
+                             count(required_len),
+                             required_param_str,
+                             count(types.len()),
+                             actual_param_str)
+                .span_label(span, &format!("expected {} type {}", required_len, required_param_str))
+                .emit();
         }
 
         if !bindings.is_empty() {
@@ -4487,28 +4481,28 @@ pub fn may_break(tcx: TyCtxt, id: ast::NodeId, b: &hir::Block) -> bool {
 }
 
 pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                       tps: &[hir::TyParam],
+                                       generics: &hir::Generics,
                                        ty: Ty<'tcx>) {
     debug!("check_bounds_are_used(n_tps={}, ty={:?})",
-           tps.len(),  ty);
+           generics.ty_params.len(),  ty);
 
     // make a vector of booleans initially false, set to true when used
-    if tps.is_empty() { return; }
-    let mut tps_used = vec![false; tps.len()];
+    if generics.ty_params.is_empty() { return; }
+    let mut tps_used = vec![false; generics.ty_params.len()];
 
     for leaf_ty in ty.walk() {
         if let ty::TyParam(ParamTy {idx, ..}) = leaf_ty.sty {
             debug!("Found use of ty param num {}", idx);
-            tps_used[idx as usize] = true;
+            tps_used[idx as usize - generics.lifetimes.len()] = true;
         }
     }
 
-    for (i, b) in tps_used.iter().enumerate() {
-        if !*b {
-            struct_span_err!(ccx.tcx.sess, tps[i].span, E0091,
+    for (&used, param) in tps_used.iter().zip(&generics.ty_params) {
+        if !used {
+            struct_span_err!(ccx.tcx.sess, param.span, E0091,
                 "type parameter `{}` is unused",
-                tps[i].name)
-                .span_label(tps[i].span, &format!("unused type parameter"))
+                param.name)
+                .span_label(param.span, &format!("unused type parameter"))
                 .emit();
         }
     }
index 859d5ff0543d01bcf6f56d0c55bd60c0ad7ea620..cef2bb07e35ca065991bf0dd4f2f8ee08b0d9358 100644 (file)
@@ -169,7 +169,7 @@ pub fn regionck_fn(&self,
 pub struct RegionCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     pub fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
 
-    region_bound_pairs: Vec<(ty::Region, GenericKind<'tcx>)>,
+    region_bound_pairs: Vec<(&'tcx ty::Region, GenericKind<'tcx>)>,
 
     free_region_map: FreeRegionMap,
 
@@ -324,9 +324,10 @@ fn visit_fn_body(&mut self,
         let call_site_scope = self.call_site_scope.unwrap();
         debug!("visit_fn_body body.id {} call_site_scope: {:?}",
                body.id, call_site_scope);
+        let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope));
         self.type_of_node_must_outlive(infer::CallReturn(span),
                                        body.id,
-                                       ty::ReScope(call_site_scope));
+                                       call_site_region);
 
         self.region_bound_pairs.truncate(old_region_bounds_pairs_len);
 
@@ -407,8 +408,8 @@ fn relate_free_regions(&mut self,
             for implication in implied_bounds {
                 debug!("implication: {:?}", implication);
                 match implication {
-                    ImpliedBound::RegionSubRegion(ty::ReFree(free_a),
-                                                  ty::ReVar(vid_b)) => {
+                    ImpliedBound::RegionSubRegion(&ty::ReFree(free_a),
+                                                  &ty::ReVar(vid_b)) => {
                         self.add_given(free_a, vid_b);
                     }
                     ImpliedBound::RegionSubParam(r_a, param_b) => {
@@ -476,9 +477,10 @@ fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) {
             // variable's type enclose at least the variable's scope.
 
             let var_scope = tcx.region_maps.var_scope(id);
+            let var_region = self.tcx.mk_region(ty::ReScope(var_scope));
 
             let origin = infer::BindingTypeIsNotValidAtDecl(span);
-            self.type_of_node_must_outlive(origin, id, ty::ReScope(var_scope));
+            self.type_of_node_must_outlive(origin, id, var_region);
 
             let typ = self.resolve_node_type(id);
             dropck::check_safety_of_destructor_if_necessary(self, typ, span, var_scope);
@@ -525,7 +527,7 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
         // scope of that expression. This also guarantees basic WF.
         let expr_ty = self.resolve_node_type(expr.id);
         // the region corresponding to this expression
-        let expr_region = ty::ReScope(self.tcx.region_maps.node_extent(expr.id));
+        let expr_region = self.tcx.node_scope_region(expr.id);
         self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span),
                                expr_ty, expr_region);
 
@@ -713,7 +715,7 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
                     None => self.resolve_node_type(base.id)
                 };
                 if let ty::TyRef(r_ptr, _) = base_ty.sty {
-                    self.mk_subregion_due_to_dereference(expr.span, expr_region, *r_ptr);
+                    self.mk_subregion_due_to_dereference(expr.span, expr_region, r_ptr);
                 }
 
                 intravisit::walk_expr(self, expr);
@@ -780,9 +782,10 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
                 let call_site_scope = self.call_site_scope;
                 debug!("visit_expr ExprRet ret_expr.id {} call_site_scope: {:?}",
                        ret_expr.id, call_site_scope);
+                let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope.unwrap()));
                 self.type_of_node_must_outlive(infer::CallReturn(ret_expr.span),
                                                ret_expr.id,
-                                               ty::ReScope(call_site_scope.unwrap()));
+                                               call_site_region);
                 intravisit::walk_expr(self, expr);
             }
 
@@ -819,7 +822,7 @@ fn walk_cast(&mut self,
             /*From:*/ (&ty::TyRef(from_r, ref from_mt),
             /*To:  */  &ty::TyRef(to_r, ref to_mt)) => {
                 // Target cannot outlive source, naturally.
-                self.sub_regions(infer::Reborrow(cast_expr.span), *to_r, *from_r);
+                self.sub_regions(infer::Reborrow(cast_expr.span), to_r, from_r);
                 self.walk_cast(cast_expr, from_mt.ty, to_mt.ty);
             }
 
@@ -889,7 +892,7 @@ fn constrain_call<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self,
         //
         // FIXME(#6268) to support nested method calls, should be callee_id
         let callee_scope = self.tcx.region_maps.node_extent(call_expr.id);
-        let callee_region = ty::ReScope(callee_scope);
+        let callee_region = self.tcx.mk_region(ty::ReScope(callee_scope));
 
         debug!("callee_region={:?}", callee_region);
 
@@ -933,8 +936,7 @@ fn constrain_autoderefs(&mut self,
                derefs,
                derefd_ty);
 
-        let s_deref_expr = self.tcx.region_maps.node_extent(deref_expr.id);
-        let r_deref_expr = ty::ReScope(s_deref_expr);
+        let r_deref_expr = self.tcx.node_scope_region(deref_expr.id);
         for i in 0..derefs {
             let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
             debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs);
@@ -989,7 +991,7 @@ fn constrain_autoderefs(&mut self,
 
             if let ty::TyRef(r_ptr, _) =  derefd_ty.sty {
                 self.mk_subregion_due_to_dereference(deref_expr.span,
-                                                     r_deref_expr, *r_ptr);
+                                                     r_deref_expr, r_ptr);
             }
 
             match derefd_ty.builtin_deref(true, ty::NoPreference) {
@@ -1003,8 +1005,8 @@ fn constrain_autoderefs(&mut self,
 
     pub fn mk_subregion_due_to_dereference(&mut self,
                                            deref_span: Span,
-                                           minimum_lifetime: ty::Region,
-                                           maximum_lifetime: ty::Region) {
+                                           minimum_lifetime: &'tcx ty::Region,
+                                           maximum_lifetime: &'tcx ty::Region) {
         self.sub_regions(infer::DerefPointer(deref_span),
                          minimum_lifetime, maximum_lifetime)
     }
@@ -1014,7 +1016,7 @@ fn check_safety_of_rvalue_destructor_if_necessary(&mut self,
                                                      span: Span) {
         match cmt.cat {
             Categorization::Rvalue(region) => {
-                match region {
+                match *region {
                     ty::ReScope(rvalue_scope) => {
                         let typ = self.resolve_type(cmt.ty);
                         dropck::check_safety_of_destructor_if_necessary(self,
@@ -1023,7 +1025,7 @@ fn check_safety_of_rvalue_destructor_if_necessary(&mut self,
                                                                         rvalue_scope);
                     }
                     ty::ReStatic => {}
-                    region => {
+                    _ => {
                         span_bug!(span,
                                   "unexpected rvalue region in rvalue \
                                    destructor safety checking: `{:?}`",
@@ -1049,7 +1051,7 @@ fn constrain_index(&mut self,
             match mt.ty.sty {
                 ty::TySlice(_) | ty::TyStr => {
                     self.sub_regions(infer::IndexSlice(index_expr.span),
-                                     r_index_expr, *r_ptr);
+                                     self.tcx.mk_region(r_index_expr), r_ptr);
                 }
                 _ => {}
             }
@@ -1061,7 +1063,7 @@ fn constrain_index(&mut self,
     fn type_of_node_must_outlive(&mut self,
         origin: infer::SubregionOrigin<'tcx>,
         id: ast::NodeId,
-        minimum_lifetime: ty::Region)
+        minimum_lifetime: &'tcx ty::Region)
     {
         let tcx = self.tcx;
 
@@ -1132,7 +1134,7 @@ fn link_fn_args(&self, body_scope: CodeExtent, args: &[hir::Arg]) {
         let mc = mc::MemCategorizationContext::new(self);
         for arg in args {
             let arg_ty = self.node_ty(arg.id);
-            let re_scope = ty::ReScope(body_scope);
+            let re_scope = self.tcx.mk_region(ty::ReScope(body_scope));
             let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty);
             debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
                    arg_ty,
@@ -1168,7 +1170,7 @@ fn link_pattern<'t>(&self,
     fn link_autoref(&self,
                     expr: &hir::Expr,
                     autoderefs: usize,
-                    autoref: &adjustment::AutoRef)
+                    autoref: &adjustment::AutoRef<'tcx>)
     {
         debug!("link_autoref(autoref={:?})", autoref);
         let mc = mc::MemCategorizationContext::new(self);
@@ -1182,8 +1184,8 @@ fn link_autoref(&self,
             }
 
             adjustment::AutoUnsafe(m) => {
-                let r = ty::ReScope(self.tcx.region_maps.node_extent(expr.id));
-                self.link_region(expr.span, &r, ty::BorrowKind::from_mutbl(m), expr_cmt);
+                let r = self.tcx.node_scope_region(expr.id);
+                self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt);
             }
         }
     }
@@ -1197,8 +1199,8 @@ fn link_by_ref(&self,
                expr, callee_scope);
         let mc = mc::MemCategorizationContext::new(self);
         let expr_cmt = ignore_err!(mc.cat_expr(expr));
-        let borrow_region = ty::ReScope(callee_scope);
-        self.link_region(expr.span, &borrow_region, ty::ImmBorrow, expr_cmt);
+        let borrow_region = self.tcx.mk_region(ty::ReScope(callee_scope));
+        self.link_region(expr.span, borrow_region, ty::ImmBorrow, expr_cmt);
     }
 
     /// Like `link_region()`, except that the region is extracted from the type of `id`,
@@ -1212,9 +1214,9 @@ fn link_region_from_node_type(&self,
                id, mutbl, cmt_borrowed);
 
         let rptr_ty = self.resolve_node_type(id);
-        if let ty::TyRef(&r, _) = rptr_ty.sty {
+        if let ty::TyRef(r, _) = rptr_ty.sty {
             debug!("rptr_ty={}",  rptr_ty);
-            self.link_region(span, &r, ty::BorrowKind::from_mutbl(mutbl),
+            self.link_region(span, r, ty::BorrowKind::from_mutbl(mutbl),
                              cmt_borrowed);
         }
     }
@@ -1225,14 +1227,14 @@ fn link_region_from_node_type(&self,
     /// between regions, as explained in `link_reborrowed_region()`.
     fn link_region(&self,
                    span: Span,
-                   borrow_region: &ty::Region,
+                   borrow_region: &'tcx ty::Region,
                    borrow_kind: ty::BorrowKind,
                    borrow_cmt: mc::cmt<'tcx>) {
         let mut borrow_cmt = borrow_cmt;
         let mut borrow_kind = borrow_kind;
 
         let origin = infer::DataBorrowed(borrow_cmt.ty, span);
-        self.type_must_outlive(origin, borrow_cmt.ty, *borrow_region);
+        self.type_must_outlive(origin, borrow_cmt.ty, borrow_region);
 
         loop {
             debug!("link_region(borrow_region={:?}, borrow_kind={:?}, borrow_cmt={:?})",
@@ -1322,10 +1324,10 @@ fn link_region(&self,
     /// recurse and process `ref_cmt` (see case 2 above).
     fn link_reborrowed_region(&self,
                               span: Span,
-                              borrow_region: &ty::Region,
+                              borrow_region: &'tcx ty::Region,
                               borrow_kind: ty::BorrowKind,
                               ref_cmt: mc::cmt<'tcx>,
-                              ref_region: ty::Region,
+                              ref_region: &'tcx ty::Region,
                               mut ref_kind: ty::BorrowKind,
                               note: mc::Note)
                               -> Option<(mc::cmt<'tcx>, ty::BorrowKind)>
@@ -1364,7 +1366,7 @@ fn link_reborrowed_region(&self,
         debug!("link_reborrowed_region: {:?} <= {:?}",
                borrow_region,
                ref_region);
-        self.sub_regions(cause, *borrow_region, ref_region);
+        self.sub_regions(cause, borrow_region, ref_region);
 
         // If we end up needing to recurse and establish a region link
         // with `ref_cmt`, calculate what borrow kind we will end up
@@ -1436,7 +1438,7 @@ fn substs_wf_in_scope(&mut self,
                           origin: infer::ParameterOrigin,
                           substs: &Substs<'tcx>,
                           expr_span: Span,
-                          expr_region: ty::Region) {
+                          expr_region: &'tcx ty::Region) {
         debug!("substs_wf_in_scope(substs={:?}, \
                 expr_region={:?}, \
                 origin={:?}, \
@@ -1445,11 +1447,11 @@ fn substs_wf_in_scope(&mut self,
 
         let origin = infer::ParameterInScope(origin, expr_span);
 
-        for &region in &substs.regions {
+        for region in substs.regions() {
             self.sub_regions(origin.clone(), expr_region, region);
         }
 
-        for &ty in &substs.types {
+        for ty in substs.types() {
             let ty = self.resolve_type(ty);
             self.type_must_outlive(origin.clone(), ty, expr_region);
         }
@@ -1461,7 +1463,7 @@ fn substs_wf_in_scope(&mut self,
     pub fn type_must_outlive(&self,
                              origin: infer::SubregionOrigin<'tcx>,
                              ty: Ty<'tcx>,
-                             region: ty::Region)
+                             region: &'tcx ty::Region)
     {
         let ty = self.resolve_type(ty);
 
@@ -1479,7 +1481,7 @@ pub fn type_must_outlive(&self,
     fn components_must_outlive(&self,
                                origin: infer::SubregionOrigin<'tcx>,
                                components: Vec<ty::outlives::Component<'tcx>>,
-                               region: ty::Region)
+                               region: &'tcx ty::Region)
     {
         for component in components {
             let origin = origin.clone();
@@ -1510,7 +1512,7 @@ fn components_must_outlive(&self,
 
     fn param_ty_must_outlive(&self,
                              origin: infer::SubregionOrigin<'tcx>,
-                             region: ty::Region,
+                             region: &'tcx ty::Region,
                              param_ty: ty::ParamTy) {
         debug!("param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})",
                region, param_ty, origin);
@@ -1522,7 +1524,7 @@ fn param_ty_must_outlive(&self,
 
     fn projection_must_outlive(&self,
                                origin: infer::SubregionOrigin<'tcx>,
-                               region: ty::Region,
+                               region: &'tcx ty::Region,
                                projection_ty: ty::ProjectionTy<'tcx>)
     {
         debug!("projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})",
@@ -1552,7 +1554,7 @@ fn projection_must_outlive(&self,
 
         // If we know that the projection outlives 'static, then we're
         // done here.
-        if env_bounds.contains(&ty::ReStatic) {
+        if env_bounds.contains(&&ty::ReStatic) {
             debug!("projection_must_outlive: 'static as declared bound");
             return;
         }
@@ -1575,11 +1577,11 @@ fn projection_must_outlive(&self,
         if env_bounds.is_empty() && needs_infer {
             debug!("projection_must_outlive: no declared bounds");
 
-            for &component_ty in &projection_ty.trait_ref.substs.types {
+            for component_ty in projection_ty.trait_ref.substs.types() {
                 self.type_must_outlive(origin.clone(), component_ty, region);
             }
 
-            for &r in &projection_ty.trait_ref.substs.regions {
+            for r in projection_ty.trait_ref.substs.regions() {
                 self.sub_regions(origin.clone(), region, r);
             }
 
@@ -1597,10 +1599,7 @@ fn projection_must_outlive(&self,
         if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) {
             let unique_bound = env_bounds[0];
             debug!("projection_must_outlive: unique declared bound = {:?}", unique_bound);
-            if projection_ty.trait_ref.substs.regions
-                                             .iter()
-                                             .any(|r| env_bounds.contains(r))
-            {
+            if projection_ty.trait_ref.substs.regions().any(|r| env_bounds.contains(&r)) {
                 debug!("projection_must_outlive: unique declared bound appears in trait ref");
                 self.sub_regions(origin.clone(), region, unique_bound);
                 return;
@@ -1617,7 +1616,7 @@ fn projection_must_outlive(&self,
         self.verify_generic_bound(origin, generic.clone(), region, verify_bound);
     }
 
-    fn type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound {
+    fn type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
         match ty.sty {
             ty::TyParam(p) => {
                 self.param_bound(p)
@@ -1632,7 +1631,7 @@ fn type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound {
         }
     }
 
-    fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound {
+    fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
         let param_env = &self.parameter_environment;
 
         debug!("param_bound(param_ty={:?})",
@@ -1650,7 +1649,7 @@ fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound {
     fn projection_declared_bounds(&self,
                                   span: Span,
                                   projection_ty: ty::ProjectionTy<'tcx>)
-                                  -> Vec<ty::Region>
+                                  -> Vec<&'tcx ty::Region>
     {
         // First assemble bounds from where clauses and traits.
 
@@ -1665,9 +1664,9 @@ fn projection_declared_bounds(&self,
 
     fn projection_bound(&self,
                         span: Span,
-                        declared_bounds: Vec<ty::Region>,
+                        declared_bounds: Vec<&'tcx ty::Region>,
                         projection_ty: ty::ProjectionTy<'tcx>)
-                        -> VerifyBound {
+                        -> VerifyBound<'tcx> {
         debug!("projection_bound(declared_bounds={:?}, projection_ty={:?})",
                declared_bounds, projection_ty);
 
@@ -1679,7 +1678,7 @@ fn projection_bound(&self,
         VerifyBound::AnyRegion(declared_bounds).or(recursive_bound)
     }
 
-    fn recursive_type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound {
+    fn recursive_type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
         let mut bounds = vec![];
 
         for subty in ty.walk_shallow() {
@@ -1701,7 +1700,7 @@ fn recursive_type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound {
     }
 
     fn declared_generic_bounds_from_env(&self, generic: GenericKind<'tcx>)
-                                        -> Vec<ty::Region>
+                                        -> Vec<&'tcx ty::Region>
     {
         let param_env = &self.parameter_environment;
 
@@ -1735,7 +1734,7 @@ fn declared_generic_bounds_from_env(&self, generic: GenericKind<'tcx>)
     fn declared_projection_bounds_from_trait(&self,
                                              span: Span,
                                              projection_ty: ty::ProjectionTy<'tcx>)
-                                             -> Vec<ty::Region>
+                                             -> Vec<&'tcx ty::Region>
     {
         debug!("projection_bounds(projection_ty={:?})",
                projection_ty);
index 030491b521d95679e38b0f72cfdc975a7ba468ae..a85e295784e977e5eeab71761fd11ca348ffb7fb 100644 (file)
@@ -252,7 +252,7 @@ fn final_upvar_tys(&mut self, closure_id: ast::NodeId) -> Vec<Ty<'tcx>> {
                         match capture {
                             ty::UpvarCapture::ByValue => freevar_ty,
                             ty::UpvarCapture::ByRef(borrow) =>
-                                tcx.mk_ref(tcx.mk_region(borrow.region),
+                                tcx.mk_ref(borrow.region,
                                            ty::TypeAndMut {
                                                ty: freevar_ty,
                                                mutbl: borrow.kind.to_mutbl_lossy(),
@@ -536,7 +536,7 @@ fn borrow(&mut self,
               borrow_id: ast::NodeId,
               _borrow_span: Span,
               cmt: mc::cmt<'tcx>,
-              _loan_region: ty::Region,
+              _loan_region: &'tcx ty::Region,
               bk: ty::BorrowKind,
               _loan_cause: euv::LoanCause)
     {
index bcad7dd3bd0fa78ef03e7a729b3c95f1fdfc7ee1..435442bd30a651f1fac36df30e2f18e08da62ad9 100644 (file)
@@ -16,8 +16,8 @@
 use rustc::infer::TypeOrigin;
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::util::nodemap::{FnvHashSet, FnvHashMap};
 
-use std::collections::HashSet;
 use syntax::ast;
 use syntax_pos::Span;
 use errors::DiagnosticBuilder;
@@ -416,7 +416,7 @@ fn check_method_receiver<'fcx, 'tcx>(&mut self,
             ty::ExplicitSelfCategory::Static => return,
             ty::ExplicitSelfCategory::ByValue => self_ty,
             ty::ExplicitSelfCategory::ByReference(region, mutability) => {
-                fcx.tcx.mk_ref(fcx.tcx.mk_region(region), ty::TypeAndMut {
+                fcx.tcx.mk_ref(region, ty::TypeAndMut {
                     ty: self_ty,
                     mutbl: mutability
                 })
@@ -456,8 +456,8 @@ fn check_variances_for_type_defn(&self,
         assert_eq!(ty_predicates.parent, None);
         let variances = self.tcx().item_variances(item_def_id);
 
-        let mut constrained_parameters: HashSet<_> =
-            variances.types
+        let mut constrained_parameters: FnvHashSet<_> =
+            variances[ast_generics.lifetimes.len()..]
                      .iter().enumerate()
                      .filter(|&(_, &variance)| variance != ty::Bivariant)
                      .map(|(index, _)| self.param_ty(ast_generics, index))
@@ -468,22 +468,22 @@ fn check_variances_for_type_defn(&self,
                                          None,
                                          &mut constrained_parameters);
 
-        for (index, _) in variances.types.iter().enumerate() {
-            let param_ty = self.param_ty(ast_generics, index);
-            if constrained_parameters.contains(&Parameter::Type(param_ty)) {
-                continue;
-            }
-            let span = ast_generics.ty_params[index].span;
-            self.report_bivariance(span, param_ty.name);
-        }
-
-        for (index, &variance) in variances.regions.iter().enumerate() {
-            if variance != ty::Bivariant {
-                continue;
-            }
+        for (index, &variance) in variances.iter().enumerate() {
+            let (span, name) = if index < ast_generics.lifetimes.len() {
+                if variance != ty::Bivariant {
+                    continue;
+                }
 
-            let span = ast_generics.lifetimes[index].lifetime.span;
-            let name = ast_generics.lifetimes[index].lifetime.name;
+                (ast_generics.lifetimes[index].lifetime.span,
+                 ast_generics.lifetimes[index].lifetime.name)
+            } else {
+                let index = index - ast_generics.lifetimes.len();
+                let param_ty = self.param_ty(ast_generics, index);
+                if constrained_parameters.contains(&Parameter::Type(param_ty)) {
+                    continue;
+                }
+                (ast_generics.ty_params[index].span, param_ty.name)
+            };
             self.report_bivariance(span, name);
         }
     }
@@ -519,11 +519,26 @@ fn report_bivariance(&self,
 
 fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, generics: &ty::Generics) {
     let parent = tcx.lookup_generics(generics.parent.unwrap());
-    let impl_params: HashSet<_> = parent.types.iter().map(|tp| tp.name).collect();
+    let impl_params: FnvHashMap<_, _> = parent.types
+                                        .iter()
+                                        .map(|tp| (tp.name, tp.def_id))
+                                        .collect();
 
     for method_param in &generics.types {
-        if impl_params.contains(&method_param.name) {
-            error_194(tcx, span, method_param.name);
+        if impl_params.contains_key(&method_param.name) {
+            // Tighten up the span to focus on only the shadowing type
+            let shadow_node_id = tcx.map.as_local_node_id(method_param.def_id).unwrap();
+            let type_span = match tcx.map.opt_span(shadow_node_id) {
+                Some(osp) => osp,
+                None => span
+            };
+
+            // The expectation here is that the original trait declaration is
+            // local so it should be okay to just unwrap everything.
+            let trait_def_id = impl_params.get(&method_param.name).unwrap();
+            let trait_node_id = tcx.map.as_local_node_id(*trait_def_id).unwrap();
+            let trait_decl_span = tcx.map.opt_span(trait_node_id).unwrap();
+            error_194(tcx, type_span, trait_decl_span, method_param.name);
         }
     }
 }
@@ -597,7 +612,7 @@ fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> {
                 // Trait impl: take implied bounds from all types that
                 // appear in the trait reference.
                 let trait_ref = self.instantiate_type_scheme(span, free_substs, trait_ref);
-                trait_ref.substs.types.to_vec()
+                trait_ref.substs.types().collect()
             }
 
             None => {
@@ -630,8 +645,11 @@ fn error_392<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, param_name: ast::N
     err
 }
 
-fn error_194(tcx: TyCtxt, span: Span, name: ast::Name) {
-    span_err!(tcx.sess, span, E0194,
+fn error_194(tcx: TyCtxt, span: Span, trait_decl_span: Span, name: ast::Name) {
+    struct_span_err!(tcx.sess, span, E0194,
               "type parameter `{}` shadows another type parameter of the same name",
-              name);
+              name)
+        .span_label(span, &format!("shadows another type parameter"))
+        .span_label(trait_decl_span, &format!("first `{}` declared here", name))
+        .emit();
 }
index cfc1292c34b78af0275585300c5acb9bd5f36d1e..3bd0e890bb8119fd4e8bf5196145d9185f1c47a6 100644 (file)
@@ -87,7 +87,7 @@ struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
     // early-bound versions of them, visible from the
     // outside of the function. This is needed by, and
     // only populated if there are any `impl Trait`.
-    free_to_bound_regions: DefIdMap<ty::Region>
+    free_to_bound_regions: DefIdMap<&'gcx ty::Region>
 }
 
 impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
@@ -102,16 +102,22 @@ fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>) -> WritebackCx<'cx, 'gcx, 'tcx> {
             return wbcx;
         }
 
+        let gcx = fcx.tcx.global_tcx();
         let free_substs = fcx.parameter_environment.free_substs;
-        for (i, r) in free_substs.regions.iter().enumerate() {
+        for (i, k) in free_substs.params().iter().enumerate() {
+            let r = if let Some(r) = k.as_region() {
+                r
+            } else {
+                continue;
+            };
             match *r {
                 ty::ReFree(ty::FreeRegion {
                     bound_region: ty::BoundRegion::BrNamed(def_id, name, _), ..
                 }) => {
-                    let bound_region = ty::ReEarlyBound(ty::EarlyBoundRegion {
+                    let bound_region = gcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
                         index: i as u32,
                         name: name,
-                    });
+                    }));
                     wbcx.free_to_bound_regions.insert(def_id, bound_region);
                 }
                 _ => {
@@ -311,9 +317,9 @@ fn visit_anon_types(&self, item_id: ast::NodeId) {
             // Convert the type from the function into a type valid outside
             // the function, by replacing free regions with early-bound ones.
             let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| {
-                match r {
+                match *r {
                     // 'static is valid everywhere.
-                    ty::ReStatic => ty::ReStatic,
+                    ty::ReStatic => gcx.mk_region(ty::ReStatic),
 
                     // Free regions that come from early-bound regions are valid.
                     ty::ReFree(ty::FreeRegion {
@@ -331,7 +337,7 @@ fn visit_anon_types(&self, item_id: ast::NodeId) {
                         span_err!(self.tcx().sess, span, E0564,
                                   "only named lifetimes are allowed in `impl Trait`, \
                                    but `{}` was found in the type `{}`", r, inside_ty);
-                        ty::ReStatic
+                        gcx.mk_region(ty::ReStatic)
                     }
 
                     ty::ReVar(_) |
@@ -626,12 +632,12 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
 
-    fn fold_region(&mut self, r: ty::Region) -> ty::Region {
+    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
         match self.infcx.fully_resolve(&r) {
             Ok(r) => r,
             Err(e) => {
                 self.report_error(e);
-                ty::ReStatic
+                self.tcx.mk_region(ty::ReStatic)
             }
         }
     }
index 2ee0927f3c8ea44e5d8d945aab7fabf0a1c0bff5..f66f15b238e73fd8eba05395546d54cad68b8cd3 100644 (file)
@@ -49,7 +49,7 @@ fn visit_item(&mut self, item: &hir::Item) {
                 }
                 hir::ViewPathList(_, ref path_list) => {
                     for path_item in path_list {
-                        self.check_import(path_item.node.id(), path_item.span);
+                        self.check_import(path_item.node.id, path_item.span);
                     }
                 }
             }
index d00cbf0221e0e76dbc53c8e0606c71f74f65ecfa..f743ef21875611434fb9de7de52911f2f8bf2d49 100644 (file)
@@ -348,9 +348,11 @@ fn check_implementations_of_copy(&self) {
                         .emit();
                 }
                 Err(CopyImplementationError::HasDestructor) => {
-                    span_err!(tcx.sess, span, E0184,
+                    struct_span_err!(tcx.sess, span, E0184,
                               "the trait `Copy` may not be implemented for this type; \
-                               the type has a destructor");
+                               the type has a destructor")
+                        .span_label(span, &format!("Copy not allowed on types with destructors"))
+                        .emit();
                 }
             }
         });
@@ -386,7 +388,7 @@ fn check_implementations_of_coerce_unsized(&self) {
 
             let source = tcx.lookup_item_type(impl_did).ty;
             let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap();
-            let target = trait_ref.substs.types[1];
+            let target = trait_ref.substs.type_at(1);
             debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
                    source, target);
 
@@ -413,7 +415,7 @@ fn check_implementations_of_coerce_unsized(&self) {
                     (&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None),
 
                     (&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => {
-                        infcx.sub_regions(infer::RelateObjectBound(span), *r_b, *r_a);
+                        infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
                         check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
                     }
 
@@ -498,7 +500,7 @@ 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, vec![target]);
+                                                            source, &[target]);
                 fulfill_cx.register_predicate_obligation(&infcx, predicate);
 
                 // Check that all transitive obligations are satisfied.
index 7578ec3d813c16bc98ae7c980efe4731048a542f..bcce64cb110c671df7ad9180babcdc047c561b3c 100644 (file)
@@ -37,7 +37,7 @@ fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
                       "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."))
-                .span_note(item.span, &format!("define and implement a trait or new type instead"))
+                .note("define and implement a trait or new type instead")
                 .emit();
         }
     }
@@ -347,15 +347,19 @@ fn check_item(&self, item: &hir::Item) {
                     return;
                 }
             }
-            hir::ItemDefaultImpl(..) => {
+            hir::ItemDefaultImpl(_, ref item_trait_ref) => {
                 // "Trait" impl
                 debug!("coherence2::orphan check: default trait impl {}",
                        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 {
-                    span_err!(self.tcx.sess, item.span, E0318,
+                    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");
+                               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))
+                        .emit();
                     return;
                 }
             }
index 7e1fb32881d6fa203e8568e1b00bff76499ec8f1..2b62e513ab27abb77c396f23a02e534baf415f15 100644 (file)
 use rscope::*;
 use rustc::dep_graph::DepNode;
 use util::common::{ErrorReported, MemoizationMap};
-use util::nodemap::{NodeMap, FnvHashMap};
+use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet};
 use {CrateCtxt, write_ty_to_tcx};
 
 use rustc_const_math::ConstInt;
 
 use std::cell::RefCell;
-use std::collections::HashSet;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::rc::Rc;
 
@@ -478,7 +477,6 @@ fn get_type_parameter_bounds(&self,
                 ty::Predicate::TypeOutlives(ref data) => {
                     data.skip_binder().0.is_param(def.index)
                 }
-                ty::Predicate::Rfc1592(..) |
                 ty::Predicate::Equate(..) |
                 ty::Predicate::RegionOutlives(..) |
                 ty::Predicate::WellFormed(..) |
@@ -1486,6 +1484,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
         let has_self = opt_self.is_some();
         let mut parent_has_self = false;
+        let mut own_start = has_self as u32;
         let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| {
             let generics = generics_of_def_id(ccx, def_id);
             assert_eq!(generics.parent, None);
@@ -1493,6 +1492,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             assert_eq!(generics.parent_types, 0);
             assert_eq!(has_self, false);
             parent_has_self = generics.has_self;
+            own_start = generics.count() as u32;
             (generics.regions.len() as u32, generics.types.len() as u32)
         });
 
@@ -1500,17 +1500,18 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         let regions = early_lifetimes.iter().enumerate().map(|(i, l)| {
             ty::RegionParameterDef {
                 name: l.lifetime.name,
-                index: parent_regions + i as u32,
+                index: own_start + i as u32,
                 def_id: tcx.map.local_def_id(l.lifetime.id),
                 bounds: l.bounds.iter().map(|l| {
                     ast_region_to_region(tcx, l)
                 }).collect()
             }
-        }).collect();
+        }).collect::<Vec<_>>();
 
         // Now create the real type parameters.
+        let type_start = own_start + regions.len() as u32;
         let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| {
-            let i = parent_types + has_self as u32 + i as u32;
+            let i = type_start + i as u32;
             get_or_create_type_parameter_def(ccx, ast_generics, i, p, allow_defaults)
         });
         let types: Vec<_> = opt_self.into_iter().chain(types).collect();
@@ -1529,8 +1530,8 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
         tcx.alloc_generics(ty::Generics {
             parent: parent_def_id,
-            parent_regions: parent_regions as u32,
-            parent_types: parent_types as u32,
+            parent_regions: parent_regions,
+            parent_types: parent_types,
             regions: regions,
             types: types,
             has_self: has_self || parent_has_self
@@ -1554,7 +1555,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             NodeItem(item) => {
                 match item.node {
                     ItemStatic(ref t, _, _) | ItemConst(ref t, _) => {
-                        ccx.icx(&()).to_ty(&ExplicitRscope, &t)
+                        ccx.icx(&()).to_ty(&ElidableRscope::new(ty::ReStatic), &t)
                     }
                     ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
                         let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl,
@@ -1741,12 +1742,12 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                                   -> ty::GenericPredicates<'tcx>
 {
     let tcx = ccx.tcx;
-    let (parent_regions, parent_types) = parent.map_or((0, 0), |def_id| {
+    let parent_count = parent.map_or(0, |def_id| {
         let generics = generics_of_def_id(ccx, def_id);
         assert_eq!(generics.parent, None);
         assert_eq!(generics.parent_regions, 0);
         assert_eq!(generics.parent_types, 0);
-        (generics.regions.len() as u32, generics.types.len() as u32)
+        generics.count() as u32
     });
     let ref base_predicates = match parent {
         Some(def_id) => {
@@ -1762,10 +1763,29 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
     };
     let mut predicates = super_predicates;
 
+    // Collect the region predicates that were declared inline as
+    // well. In the case of parameters declared on a fn or method, we
+    // have to be careful to only iterate over early-bound regions.
+    let own_start = parent_count + has_self as u32;
+    let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics);
+    for (index, param) in early_lifetimes.iter().enumerate() {
+        let index = own_start + index as u32;
+        let region = ccx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
+            index: index,
+            name: param.lifetime.name
+        }));
+        for bound in &param.bounds {
+            let bound_region = ast_region_to_region(ccx.tcx, bound);
+            let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region));
+            predicates.push(outlives.to_predicate());
+        }
+    }
+
     // Collect the predicates that were written inline by the user on each
     // type parameter (e.g., `<T:Foo>`).
+    let type_start = own_start + early_lifetimes.len() as u32;
     for (index, param) in ast_generics.ty_params.iter().enumerate() {
-        let index = parent_types + has_self as u32 + index as u32;
+        let index = type_start + index as u32;
         let param_ty = ty::ParamTy::new(index, param.name).to_ty(ccx.tcx);
         let bounds = compute_bounds(&ccx.icx(&(base_predicates, ast_generics)),
                                     param_ty,
@@ -1776,24 +1796,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         predicates.extend(bounds.predicates(ccx.tcx, param_ty));
     }
 
-    // Collect the region predicates that were declared inline as
-    // well. In the case of parameters declared on a fn or method, we
-    // have to be careful to only iterate over early-bound regions.
-    let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics);
-    for (index, param) in early_lifetimes.iter().enumerate() {
-        let index = parent_regions + index as u32;
-        let region =
-            ty::ReEarlyBound(ty::EarlyBoundRegion {
-                index: index,
-                name: param.lifetime.name
-            });
-        for bound in &param.bounds {
-            let bound_region = ast_region_to_region(ccx.tcx, bound);
-            let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region));
-            predicates.push(outlives.to_predicate());
-        }
-    }
-
     // Add in the bounds that appear in the where-clause
     let where_clause = &ast_generics.where_clause;
     for predicate in &where_clause.predicates {
@@ -1919,13 +1921,13 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                                             param_id: ast::NodeId,
                                             param_bounds: &[hir::TyParamBound],
                                             where_clause: &hir::WhereClause)
-                                            -> ty::ObjectLifetimeDefault
+                                            -> ty::ObjectLifetimeDefault<'tcx>
 {
     let inline_bounds = from_bounds(ccx, param_bounds);
     let where_bounds = from_predicates(ccx, param_id, &where_clause.predicates);
-    let all_bounds: HashSet<_> = inline_bounds.into_iter()
-                                              .chain(where_bounds)
-                                              .collect();
+    let all_bounds: FnvHashSet<_> = inline_bounds.into_iter()
+                                                 .chain(where_bounds)
+                                                 .collect();
     return if all_bounds.len() > 1 {
         ty::ObjectLifetimeDefault::Ambiguous
     } else if all_bounds.len() == 0 {
@@ -1937,7 +1939,7 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 
     fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                             bounds: &[hir::TyParamBound])
-                            -> Vec<ty::Region>
+                            -> Vec<&'tcx ty::Region>
     {
         bounds.iter()
               .filter_map(|bound| {
@@ -1954,7 +1956,7 @@ fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
     fn from_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                                 param_id: ast::NodeId,
                                 predicates: &[hir::WherePredicate])
-                                -> Vec<ty::Region>
+                                -> Vec<&'tcx ty::Region>
     {
         predicates.iter()
                   .flat_map(|predicate| {
@@ -2126,7 +2128,7 @@ pub fn mk_item_substs<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
     }
 
     Substs::for_item(tcx, def_id,
-                     |def, _| def.to_early_bound_region(),
+                     |def, _| tcx.mk_region(def.to_early_bound_region()),
                      |def, _| tcx.mk_param_from_def(def))
 }
 
@@ -2142,7 +2144,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     // The trait reference is an input, so find all type parameters
     // reachable from there, to start (if this is an inherent impl,
     // then just examine the self type).
-    let mut input_parameters: HashSet<_> =
+    let mut input_parameters: FnvHashSet<_> =
         ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect();
     if let Some(ref trait_ref) = impl_trait_ref {
         input_parameters.extend(ctp::parameters_for(trait_ref, false));
@@ -2171,7 +2173,7 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let impl_predicates = ccx.tcx.lookup_predicates(impl_def_id);
     let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id);
 
-    let mut input_parameters: HashSet<_> =
+    let mut input_parameters: FnvHashSet<_> =
         ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect();
     if let Some(ref trait_ref) = impl_trait_ref {
         input_parameters.extend(ctp::parameters_for(trait_ref, false));
@@ -2179,7 +2181,7 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     ctp::identify_constrained_type_params(
         &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
 
-    let lifetimes_in_associated_types: HashSet<_> = impl_items.iter()
+    let lifetimes_in_associated_types: FnvHashSet<_> = impl_items.iter()
         .map(|item| ccx.tcx.impl_or_trait_item(ccx.tcx.map.local_def_id(item.id)))
         .filter_map(|item| match item {
             ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty,
index 7d3bd095a3a888c930b813f17654334ae4e92ded..9e5c3a5d575bff6988c30b44ee6b1a0aaea11717 100644 (file)
@@ -10,7 +10,7 @@
 
 use rustc::ty::{self, Ty};
 use rustc::ty::fold::{TypeFoldable, TypeVisitor};
-use std::collections::HashSet;
+use rustc::util::nodemap::FnvHashSet;
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub enum Parameter {
@@ -58,8 +58,8 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
         t.super_visit_with(self)
     }
 
-    fn visit_region(&mut self, r: ty::Region) -> bool {
-        match r {
+    fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
+        match *r {
             ty::ReEarlyBound(data) => {
                 self.parameters.push(Parameter::Region(data));
             }
@@ -71,7 +71,7 @@ fn visit_region(&mut self, r: ty::Region) -> bool {
 
 pub fn identify_constrained_type_params<'tcx>(predicates: &[ty::Predicate<'tcx>],
                                               impl_trait_ref: Option<ty::TraitRef<'tcx>>,
-                                              input_parameters: &mut HashSet<Parameter>)
+                                              input_parameters: &mut FnvHashSet<Parameter>)
 {
     let mut predicates = predicates.to_owned();
     setup_constraining_predicates(&mut predicates, impl_trait_ref, input_parameters);
@@ -120,7 +120,7 @@ pub fn identify_constrained_type_params<'tcx>(predicates: &[ty::Predicate<'tcx>]
 /// think of any.
 pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx>],
                                            impl_trait_ref: Option<ty::TraitRef<'tcx>>,
-                                           input_parameters: &mut HashSet<Parameter>)
+                                           input_parameters: &mut FnvHashSet<Parameter>)
 {
     // The canonical way of doing the needed topological sort
     // would be a DFS, but getting the graph and its ownership
index fe1cb3d6badcd06dc97ba5f9f834ed5fa73d02ee..3f1374db36936093418193e6b326429b41a4e6b8 100644 (file)
@@ -572,7 +572,7 @@ impl Foo for Bar {
     // error, expected u16, found i16
     fn foo(x: i16) { }
 
-    // error, values differ in mutability
+    // error, types differ in mutability
     fn bar(&mut self) { }
 }
 ```
@@ -3422,13 +3422,6 @@ impl<T, U> CoerceUnsized<Foo<U>> for Foo<T> where T: CoerceUnsized<U> {}
 struct.
 "##,
 
-E0379: r##"
-Trait methods cannot be declared `const` by design. For more information, see
-[RFC 911].
-
-[RFC 911]: https://github.com/rust-lang/rfcs/pull/911
-"##,
-
 E0380: r##"
 Default impls are only allowed for traits with no methods or associated items.
 For more information see the [opt-in builtin traits RFC](https://github.com/rust
index 8a8232535c77592ae9936d6545899bc1e257ad58..a5445b18e77f849108a9f2947a6fc4a1bf41c9ab 100644 (file)
@@ -172,7 +172,7 @@ fn write_substs_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                node_id,
                item_substs);
 
-        assert!(!item_substs.substs.types.needs_infer());
+        assert!(!item_substs.substs.needs_infer());
 
         ccx.tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs);
     }
@@ -216,10 +216,10 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                 Some(hir_map::NodeItem(it)) => {
                     match it.node {
                         hir::ItemFn(_, _, _, _, ref generics, _) => {
-                            if let Some(gen_span) = generics.span() {
-                                struct_span_err!(ccx.tcx.sess, gen_span, E0131,
+                            if generics.is_parameterized() {
+                                struct_span_err!(ccx.tcx.sess, generics.span, E0131,
                                          "main function is not allowed to have type parameters")
-                                    .span_label(gen_span,
+                                    .span_label(generics.span,
                                                 &format!("main cannot have type parameters"))
                                     .emit();
                                 return;
@@ -269,10 +269,9 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
                     match it.node {
                         hir::ItemFn(_,_,_,_,ref ps,_)
                         if ps.is_parameterized() => {
-                            let sp = if let Some(sp) = ps.span() { sp } else { start_span };
-                            struct_span_err!(tcx.sess, sp, E0132,
+                            struct_span_err!(tcx.sess, ps.span, E0132,
                                 "start function is not allowed to have type parameters")
-                                .span_label(sp,
+                                .span_label(ps.span,
                                             &format!("start function cannot have type parameters"))
                                 .emit();
                             return;
index 9aca779dd89c4f7ee01758eee09ae012eefff077..f5b13c4207d905aaec9066559b8dc0b100140ae8 100644 (file)
@@ -257,12 +257,12 @@ fn anon_regions(&self,
 /// A scope which overrides the default object lifetime but has no other effect.
 pub struct ObjectLifetimeDefaultRscope<'r> {
     base_scope: &'r (RegionScope+'r),
-    default: ty::ObjectLifetimeDefault,
+    default: ty::ObjectLifetimeDefault<'r>,
 }
 
 impl<'r> ObjectLifetimeDefaultRscope<'r> {
     pub fn new(base_scope: &'r (RegionScope+'r),
-               default: ty::ObjectLifetimeDefault)
+               default: ty::ObjectLifetimeDefault<'r>)
                -> ObjectLifetimeDefaultRscope<'r>
     {
         ObjectLifetimeDefaultRscope {
@@ -283,7 +283,7 @@ fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
                 Some(self.base_object_lifetime_default(span)),
 
             ty::ObjectLifetimeDefault::Specific(r) =>
-                Some(r),
+                Some(*r),
         }
     }
 
index 536fa629fd611837154ddb733c386f7a09da7af2..2cf84b5745af4a0ec0c2e25fd4a84794a473407e 100644 (file)
@@ -26,7 +26,6 @@
 
 use super::terms::*;
 use super::terms::VarianceTerm::*;
-use super::terms::ParamKind::*;
 use super::xform::*;
 
 pub struct ConstraintContext<'a, 'tcx: 'a> {
@@ -209,7 +208,6 @@ macro_rules! cannot_happen { () => { {
     fn declared_variance(&self,
                          param_def_id: DefId,
                          item_def_id: DefId,
-                         kind: ParamKind,
                          index: usize)
                          -> VarianceTermPtr<'a> {
         assert_eq!(param_def_id.krate, item_def_id.krate);
@@ -224,11 +222,7 @@ fn declared_variance(&self,
             // Parameter on an item defined within another crate:
             // variance already inferred, just look it up.
             let variances = self.tcx().item_variances(item_def_id);
-            let variance = match kind {
-                TypeParam => variances.types[index],
-                RegionParam => variances.regions[index],
-            };
-            self.constant_term(variance)
+            self.constant_term(variances[index])
         }
     }
 
@@ -330,7 +324,7 @@ fn add_constraints_from_ty(&mut self,
 
             ty::TyRef(region, ref mt) => {
                 let contra = self.contravariant(variance);
-                self.add_constraints_from_region(generics, *region, contra);
+                self.add_constraints_from_region(generics, region, contra);
                 self.add_constraints_from_mt(generics, mt, variance);
             }
 
@@ -401,8 +395,11 @@ fn add_constraints_from_ty(&mut self,
 
             ty::TyParam(ref data) => {
                 assert_eq!(generics.parent, None);
-                assert!((data.idx as usize) < generics.types.len());
-                let def_id = generics.types[data.idx as usize].def_id;
+                let mut i = data.idx as usize;
+                if !generics.has_self || i > 0 {
+                    i -= generics.regions.len();
+                }
+                let def_id = generics.types[i].def_id;
                 let node_id = self.tcx().map.as_local_node_id(def_id).unwrap();
                 match self.terms_cx.inferred_map.get(&node_id) {
                     Some(&index) => {
@@ -449,7 +446,7 @@ fn add_constraints_from_substs(&mut self,
 
         for p in type_param_defs {
             let variance_decl =
-                self.declared_variance(p.def_id, def_id, TypeParam, p.index as usize);
+                self.declared_variance(p.def_id, def_id, p.index as usize);
             let variance_i = self.xform(variance, variance_decl);
             let substs_ty = substs.type_for_def(p);
             debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
@@ -459,7 +456,7 @@ fn add_constraints_from_substs(&mut self,
 
         for p in region_param_defs {
             let variance_decl =
-                self.declared_variance(p.def_id, def_id, RegionParam, p.index as usize);
+                self.declared_variance(p.def_id, def_id, p.index as usize);
             let variance_i = self.xform(variance, variance_decl);
             let substs_r = substs.region_for_def(p);
             self.add_constraints_from_region(generics, substs_r, variance_i);
@@ -483,13 +480,13 @@ fn add_constraints_from_sig(&mut self,
     /// context with ambient variance `variance`
     fn add_constraints_from_region(&mut self,
                                    generics: &ty::Generics<'tcx>,
-                                   region: ty::Region,
+                                   region: &'tcx ty::Region,
                                    variance: VarianceTermPtr<'a>) {
-        match region {
+        match *region {
             ty::ReEarlyBound(ref data) => {
                 assert_eq!(generics.parent, None);
-                assert!((data.index as usize) < generics.regions.len());
-                let def_id = generics.regions[data.index as usize].def_id;
+                let i = data.index as usize - generics.has_self as usize;
+                let def_id = generics.regions[i].def_id;
                 let node_id = self.tcx().map.as_local_node_id(def_id).unwrap();
                 if self.is_to_be_inferred(node_id) {
                     let index = self.inferred_index(node_id);
index d3b63119bcb324fad45016f1ea72e4b2ea98eae7..82b63d0cc09377fd015c9bbeb9d6a755ed4689b6 100644 (file)
@@ -21,7 +21,6 @@
 use super::constraints::*;
 use super::terms::*;
 use super::terms::VarianceTerm::*;
-use super::terms::ParamKind::*;
 use super::xform::*;
 
 struct SolveContext<'a, 'tcx: 'a> {
@@ -109,24 +108,16 @@ fn write(&self) {
         while index < num_inferred {
             let item_id = inferred_infos[index].item_id;
 
-            let mut item_variances = ty::ItemVariances::empty();
+            let mut item_variances = vec![];
 
             while index < num_inferred && inferred_infos[index].item_id == item_id {
                 let info = &inferred_infos[index];
                 let variance = solutions[index];
-                debug!("Index {} Info {} / {:?} Variance {:?}",
-                       index, info.index, info.kind, variance);
-                match info.kind {
-                    TypeParam => {
-                        assert_eq!(item_variances.types.len(), info.index);
-                        item_variances.types.push(variance);
-                    }
-                    RegionParam => {
-                        assert_eq!(item_variances.regions.len(), info.index);
-                        item_variances.regions.push(variance);
-                    }
-                }
+                debug!("Index {} Info {} Variance {:?}",
+                       index, info.index, variance);
 
+                assert_eq!(item_variances.len(), info.index);
+                item_variances.push(variance);
                 index += 1;
             }
 
index d30cbc8f117cf03c98668f4409789aad0e660e91..c0b53787177d5ff9e0e175506de66d525aa3f93d 100644 (file)
@@ -31,7 +31,6 @@
 use util::nodemap::NodeMap;
 
 use self::VarianceTerm::*;
-use self::ParamKind::*;
 
 pub type VarianceTermPtr<'a> = &'a VarianceTerm<'a>;
 
@@ -61,7 +60,7 @@ pub struct TermsContext<'a, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
     pub arena: &'a TypedArena<VarianceTerm<'a>>,
 
-    pub empty_variances: Rc<ty::ItemVariances>,
+    pub empty_variances: Rc<Vec<ty::Variance>>,
 
     // For marker types, UnsafeCell, and other lang items where
     // variance is hardcoded, records the item-id and the hardcoded
@@ -76,15 +75,8 @@ pub struct TermsContext<'a, 'tcx: 'a> {
     pub inferred_infos: Vec<InferredInfo<'a>> ,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum ParamKind {
-    TypeParam,
-    RegionParam,
-}
-
 pub struct InferredInfo<'a> {
     pub item_id: ast::NodeId,
-    pub kind: ParamKind,
     pub index: usize,
     pub param_id: ast::NodeId,
     pub term: VarianceTermPtr<'a>,
@@ -110,7 +102,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(
 
         // cache and share the variance struct used for items with
         // no type/region parameters
-        empty_variances: Rc::new(ty::ItemVariances::empty())
+        empty_variances: Rc::new(vec![])
     };
 
     // See README.md for a discussion on dep-graph management.
@@ -162,17 +154,19 @@ fn add_inferreds_for_item(&mut self,
 
         let inferreds_on_entry = self.num_inferred();
 
+        if has_self {
+            self.add_inferred(item_id, 0, item_id);
+        }
+
         for (i, p) in generics.lifetimes.iter().enumerate() {
             let id = p.lifetime.id;
-            self.add_inferred(item_id, RegionParam, i, id);
+            let i = has_self as usize + i;
+            self.add_inferred(item_id, i, id);
         }
 
-        if has_self {
-            self.add_inferred(item_id, TypeParam, 0, item_id);
-        }
         for (i, p) in generics.ty_params.iter().enumerate() {
-            let i = has_self as usize + i;
-            self.add_inferred(item_id, TypeParam, i, p.id);
+            let i = has_self as usize + generics.lifetimes.len() + i;
+            self.add_inferred(item_id, i, p.id);
         }
 
         // If this item has no type or lifetime parameters,
@@ -194,14 +188,12 @@ fn add_inferreds_for_item(&mut self,
 
     fn add_inferred(&mut self,
                     item_id: ast::NodeId,
-                    kind: ParamKind,
                     index: usize,
                     param_id: ast::NodeId) {
         let inf_index = InferredIndex(self.inferred_infos.len());
         let term = self.arena.alloc(InferredTerm(inf_index));
         let initial_variance = self.pick_initial_variance(item_id, index);
         self.inferred_infos.push(InferredInfo { item_id: item_id,
-                                                kind: kind,
                                                 index: index,
                                                 param_id: param_id,
                                                 term: term,
@@ -211,13 +203,12 @@ fn add_inferred(&mut self,
 
         debug!("add_inferred(item_path={}, \
                 item_id={}, \
-                kind={:?}, \
                 index={}, \
                 param_id={}, \
                 inf_index={:?}, \
                 initial_variance={:?})",
                self.tcx.item_path_str(self.tcx.map.local_def_id(item_id)),
-               item_id, kind, index, param_id, inf_index,
+               item_id, index, param_id, inf_index,
                initial_variance);
     }
 
index 81856cb87c7c40cdb1debe42f633caaec0ad43f9..5a0c27d9c609f4cc5b0b09e4081a0707669d0c21 100644 (file)
@@ -29,6 +29,7 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use core::char::CharExt as C;
+use core::iter::FusedIterator;
 use core::fmt;
 use tables::{conversions, derived_property, general_category, property};
 
@@ -39,6 +40,8 @@
 pub use core::char::{EncodeUtf16, EncodeUtf8, EscapeDebug, EscapeDefault, EscapeUnicode};
 
 // unstable reexports
+#[unstable(feature = "try_from", issue = "33417")]
+pub use core::char::CharTryFromError;
 #[unstable(feature = "decode_utf8", issue = "33906")]
 pub use core::char::{DecodeUtf8, decode_utf8};
 #[unstable(feature = "unicode", issue = "27783")]
@@ -62,6 +65,9 @@ fn next(&mut self) -> Option<char> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl FusedIterator for ToLowercase {}
+
 /// Returns an iterator that yields the uppercase equivalent of a `char`.
 ///
 /// This `struct` is created by the [`to_uppercase()`] method on [`char`]. See
@@ -80,6 +86,8 @@ fn next(&mut self) -> Option<char> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl FusedIterator for ToUppercase {}
 
 enum CaseMappingIter {
     Three(char, char, char),
index 3ae905eba279b7f3c1cce0607a0d75190f51094f..65bd717e01a8232df3ff044f1d41ecafc37107f9 100644 (file)
 #![feature(char_escape_debug)]
 #![feature(core_char_ext)]
 #![feature(decode_utf8)]
+#![feature(fused)]
 #![feature(lang_items)]
 #![feature(staged_api)]
+#![feature(try_from)]
 #![feature(unicode)]
 
 mod tables;
index 0bac44b837ff247dc80743994b5fe58daff5d3d9..eb5b6feeb7ec4893e9655ec3095769a005c7c064 100644 (file)
@@ -14,7 +14,7 @@
 //! methods provided by the unicode parts of the CharExt trait.
 
 use core::char;
-use core::iter::Filter;
+use core::iter::{Filter, FusedIterator};
 use core::str::Split;
 
 /// An iterator over the non-whitespace substrings of a string,
@@ -177,6 +177,10 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> FusedIterator for Utf16Encoder<I>
+    where I: FusedIterator<Item = char> {}
+
 impl<'a> Iterator for SplitWhitespace<'a> {
     type Item = &'a str;
 
@@ -189,3 +193,6 @@ fn next_back(&mut self) -> Option<&'a str> {
         self.inner.next_back()
     }
 }
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for SplitWhitespace<'a> {}
index 3e510bdc9002e2cbbc5b0089a1c53386a205d439..d66d2001f2304d626ef79277f3116d44c1702873 100644 (file)
@@ -16,6 +16,7 @@ rustc_back = { path = "../librustc_back" }
 rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_const_math = { path = "../librustc_const_math" }
 rustc_driver = { path = "../librustc_driver" }
+rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_lint = { path = "../librustc_lint" }
 rustc_metadata = { path = "../librustc_metadata" }
index 013433336a1d5396e08f90bf0e37d3c2d2f4e9f9..20d4c417655401024c9c9cb110837c53d08bc5eb 100644 (file)
@@ -10,7 +10,6 @@
 
 //! Support for inlining external documentation into the current AST.
 
-use std::collections::HashSet;
 use std::iter::once;
 
 use syntax::ast;
@@ -21,6 +20,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::hir::print as pprust;
 use rustc::ty::{self, TyCtxt};
+use rustc::util::nodemap::FnvHashSet;
 
 use rustc_const_eval::lookup_const_by_id;
 
@@ -425,7 +425,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
                 .into_iter()
                 .map(|meth| meth.name.to_string())
                 .collect()
-    }).unwrap_or(HashSet::new());
+    }).unwrap_or(FnvHashSet());
 
     ret.push(clean::Item {
         inner: clean::ImplItem(clean::Impl {
@@ -461,7 +461,7 @@ fn fill_in<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // If we're reexporting a reexport it may actually reexport something in
         // two namespaces, so the target may be listed twice. Make sure we only
         // visit each node at most once.
-        let mut visited = HashSet::new();
+        let mut visited = FnvHashSet();
         for item in tcx.sess.cstore.item_children(did) {
             match item.def {
                 cstore::DlDef(Def::ForeignMod(did)) => {
index 75d21399f05e69d28f59a2aa35b0d9d6fb12c8e8..e4b6a30d5bcb3b35c3f55954ee9cb09545b561e5 100644 (file)
@@ -12,7 +12,6 @@
 //! that clean them.
 
 pub use self::Type::*;
-pub use self::PrimitiveType::*;
 pub use self::TypeKind::*;
 pub use self::VariantKind::*;
 pub use self::Mutability::*;
 use syntax::abi::Abi;
 use syntax::ast;
 use syntax::attr;
-use syntax::attr::{AttributeMethods, AttrMetaMethods};
 use syntax::codemap::Spanned;
-use syntax::parse::token::{self, InternedString, keywords};
+use syntax::parse::token::keywords;
 use syntax::ptr::P;
+use syntax::print::pprust as syntax_pprust;
 use syntax_pos::{self, DUMMY_SP, Pos};
 
 use rustc_trans::back::link;
 use rustc::ty::subst::Substs;
 use rustc::ty;
 use rustc::middle::stability;
+use rustc::util::nodemap::{FnvHashMap, FnvHashSet};
 
 use rustc::hir;
 
-use std::collections::{HashMap, HashSet};
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::sync::Arc;
@@ -122,7 +121,7 @@ pub struct Crate {
     pub access_levels: Arc<AccessLevels<DefId>>,
     // These are later on moved into `CACHEKEY`, leaving the map empty.
     // Only here so that they can be filtered through the rustdoc passes.
-    pub external_traits: HashMap<DefId, Trait>,
+    pub external_traits: FnvHashMap<DefId, Trait>,
 }
 
 struct CrateNum(ast::CrateNum);
@@ -287,34 +286,34 @@ pub fn is_crate(&self) -> bool {
         }
     }
     pub fn is_mod(&self) -> bool {
-        ItemType::from_item(self) == ItemType::Module
+        ItemType::from(self) == ItemType::Module
     }
     pub fn is_trait(&self) -> bool {
-        ItemType::from_item(self) == ItemType::Trait
+        ItemType::from(self) == ItemType::Trait
     }
     pub fn is_struct(&self) -> bool {
-        ItemType::from_item(self) == ItemType::Struct
+        ItemType::from(self) == ItemType::Struct
     }
     pub fn is_enum(&self) -> bool {
-        ItemType::from_item(self) == ItemType::Module
+        ItemType::from(self) == ItemType::Module
     }
     pub fn is_fn(&self) -> bool {
-        ItemType::from_item(self) == ItemType::Function
+        ItemType::from(self) == ItemType::Function
     }
     pub fn is_associated_type(&self) -> bool {
-        ItemType::from_item(self) == ItemType::AssociatedType
+        ItemType::from(self) == ItemType::AssociatedType
     }
     pub fn is_associated_const(&self) -> bool {
-        ItemType::from_item(self) == ItemType::AssociatedConst
+        ItemType::from(self) == ItemType::AssociatedConst
     }
     pub fn is_method(&self) -> bool {
-        ItemType::from_item(self) == ItemType::Method
+        ItemType::from(self) == ItemType::Method
     }
     pub fn is_ty_method(&self) -> bool {
-        ItemType::from_item(self) == ItemType::TyMethod
+        ItemType::from(self) == ItemType::TyMethod
     }
     pub fn is_primitive(&self) -> bool {
-        ItemType::from_item(self) == ItemType::Primitive
+        ItemType::from(self) == ItemType::Primitive
     }
     pub fn is_stripped(&self) -> bool {
         match self.inner { StrippedItem(..) => true, _ => false }
@@ -380,6 +379,23 @@ pub enum ItemEnum {
     StrippedItem(Box<ItemEnum>),
 }
 
+impl ItemEnum {
+    pub fn generics(&self) -> Option<&Generics> {
+        Some(match *self {
+            ItemEnum::StructItem(ref s) => &s.generics,
+            ItemEnum::EnumItem(ref e) => &e.generics,
+            ItemEnum::FunctionItem(ref f) => &f.generics,
+            ItemEnum::TypedefItem(ref t, _) => &t.generics,
+            ItemEnum::TraitItem(ref t) => &t.generics,
+            ItemEnum::ImplItem(ref i) => &i.generics,
+            ItemEnum::TyMethodItem(ref i) => &i.generics,
+            ItemEnum::MethodItem(ref i) => &i.generics,
+            ItemEnum::ForeignFunctionItem(ref f) => &f.generics,
+            _ => return None,
+        })
+    }
+}
+
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Module {
     pub items: Vec<Item>,
@@ -485,11 +501,24 @@ fn list<'a>(&'a self, name: &str) -> &'a [Attribute] {
     }
 }
 
+/// This is a flattened version of the AST's Attribute + MetaItem.
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
 pub enum Attribute {
     Word(String),
     List(String, Vec<Attribute>),
-    NameValue(String, String)
+    NameValue(String, String),
+    Literal(String),
+}
+
+impl Clean<Attribute> for ast::NestedMetaItem {
+    fn clean(&self, cx: &DocContext) -> Attribute {
+        if let Some(mi) = self.meta_item() {
+            mi.clean(cx)
+        } else { // must be a literal
+            let lit = self.literal().unwrap();
+            Literal(syntax_pprust::lit_to_string(lit))
+        }
+    }
 }
 
 impl Clean<Attribute> for ast::MetaItem {
@@ -511,50 +540,6 @@ fn clean(&self, cx: &DocContext) -> Attribute {
     }
 }
 
-// This is a rough approximation that gets us what we want.
-impl attr::AttrMetaMethods for Attribute {
-    fn name(&self) -> InternedString {
-        match *self {
-            Word(ref n) | List(ref n, _) | NameValue(ref n, _) => {
-                token::intern_and_get_ident(n)
-            }
-        }
-    }
-
-    fn value_str(&self) -> Option<InternedString> {
-        match *self {
-            NameValue(_, ref v) => {
-                Some(token::intern_and_get_ident(v))
-            }
-            _ => None,
-        }
-    }
-    fn meta_item_list<'a>(&'a self) -> Option<&'a [P<ast::MetaItem>]> { None }
-
-    fn is_word(&self) -> bool {
-      match *self {
-        Word(_) => true,
-        _ => false,
-      }
-    }
-
-    fn is_value_str(&self) -> bool {
-      match *self {
-        NameValue(..) => true,
-        _ => false,
-      }
-    }
-
-    fn is_meta_item_list(&self) -> bool {
-      match *self {
-        List(..) => true,
-        _ => false,
-      }
-    }
-
-    fn span(&self) -> syntax_pos::Span { unimplemented!() }
-}
-
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
 pub struct TyParam {
     pub name: String,
@@ -626,8 +611,8 @@ fn clean(&self, cx: &DocContext) -> TyParamBound {
 
 fn external_path_params(cx: &DocContext, trait_did: Option<DefId>, has_self: bool,
                         bindings: Vec<TypeBinding>, substs: &Substs) -> PathParameters {
-    let lifetimes = substs.regions.iter().filter_map(|v| v.clean(cx)).collect();
-    let types = substs.types[has_self as usize..].to_vec();
+    let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect();
+    let types = substs.types().skip(has_self as usize).collect::<Vec<_>>();
 
     match (trait_did, cx.tcx_opt()) {
         // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
@@ -721,12 +706,11 @@ fn clean(&self, cx: &DocContext) -> TyParamBound {
         let path = external_path(cx, &tcx.item_name(self.def_id).as_str(),
                                  Some(self.def_id), true, vec![], self.substs);
 
-        debug!("ty::TraitRef\n  substs.types: {:?}\n",
-               &self.input_types()[1..]);
+        debug!("ty::TraitRef\n  subst: {:?}\n", self.substs);
 
         // collect any late bound regions
         let mut late_bounds = vec![];
-        for &ty_s in &self.input_types()[1..] {
+        for ty_s in self.input_types().skip(1) {
             if let ty::TyTuple(ts) = ty_s.sty {
                 for &ty_s in ts {
                     if let ty::TyRef(ref reg, _) = ty_s.sty {
@@ -759,9 +743,9 @@ fn clean(&self, cx: &DocContext) -> TyParamBound {
 impl<'tcx> Clean<Option<Vec<TyParamBound>>> for Substs<'tcx> {
     fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
         let mut v = Vec::new();
-        v.extend(self.regions.iter().filter_map(|r| r.clean(cx))
+        v.extend(self.regions().filter_map(|r| r.clean(cx))
                      .map(RegionBound));
-        v.extend(self.types.iter().map(|t| TraitBound(PolyTrait {
+        v.extend(self.types().map(|t| TraitBound(PolyTrait {
             trait_: t.clean(cx),
             lifetimes: vec![]
         }, hir::TraitBoundModifier::None)));
@@ -806,7 +790,7 @@ fn clean(&self, _: &DocContext) -> Lifetime {
     }
 }
 
-impl Clean<Lifetime> for ty::RegionParameterDef {
+impl<'tcx> Clean<Lifetime> for ty::RegionParameterDef<'tcx> {
     fn clean(&self, _: &DocContext) -> Lifetime {
         Lifetime(self.name.to_string())
     }
@@ -874,7 +858,6 @@ fn clean(&self, cx: &DocContext) -> WherePredicate {
             Predicate::WellFormed(_) => panic!("not user writable"),
             Predicate::ObjectSafe(_) => panic!("not user writable"),
             Predicate::ClosureKind(..) => panic!("not user writable"),
-            Predicate::Rfc1592(..) => panic!("not user writable"),
         }
     }
 }
@@ -898,7 +881,7 @@ fn clean(&self, cx: &DocContext) -> WherePredicate {
     }
 }
 
-impl Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region, ty::Region> {
+impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<&'tcx ty::Region, &'tcx ty::Region> {
     fn clean(&self, cx: &DocContext) -> WherePredicate {
         let ty::OutlivesPredicate(ref a, ref b) = *self;
         WherePredicate::RegionPredicate {
@@ -908,7 +891,7 @@ fn clean(&self, cx: &DocContext) -> WherePredicate {
     }
 }
 
-impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, ty::Region> {
+impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, &'tcx ty::Region> {
     fn clean(&self, cx: &DocContext) -> WherePredicate {
         let ty::OutlivesPredicate(ref ty, ref lt) = *self;
 
@@ -995,7 +978,7 @@ fn clean(&self, cx: &DocContext) -> Generics {
         // Note that associated types also have a sized bound by default, but we
         // don't actually know the set of associated types right here so that's
         // handled in cleaning associated types
-        let mut sized_params = HashSet::new();
+        let mut sized_params = FnvHashSet();
         where_predicates.retain(|pred| {
             match *pred {
                 WP::BoundPredicate { ty: Generic(ref g), ref bounds } => {
@@ -1469,8 +1452,8 @@ pub enum PrimitiveType {
     Str,
     Slice,
     Array,
-    PrimitiveTuple,
-    PrimitiveRawPointer,
+    Tuple,
+    RawPointer,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)]
@@ -1500,12 +1483,12 @@ impl Type {
     pub fn primitive_type(&self) -> Option<PrimitiveType> {
         match *self {
             Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
-            Vector(..) | BorrowedRef{ type_: box Vector(..), ..  } => Some(Slice),
+            Vector(..) | BorrowedRef{ type_: box Vector(..), ..  } => Some(PrimitiveType::Slice),
             FixedVector(..) | BorrowedRef { type_: box FixedVector(..), .. } => {
-                Some(Array)
+                Some(PrimitiveType::Array)
             }
-            Tuple(..) => Some(PrimitiveTuple),
-            RawPointer(..) => Some(PrimitiveRawPointer),
+            Tuple(..) => Some(PrimitiveType::Tuple),
+            RawPointer(..) => Some(PrimitiveType::RawPointer),
             _ => None,
         }
     }
@@ -1530,25 +1513,25 @@ fn def_id(&self) -> Option<DefId> {
 impl PrimitiveType {
     fn from_str(s: &str) -> Option<PrimitiveType> {
         match s {
-            "isize" => Some(Isize),
-            "i8" => Some(I8),
-            "i16" => Some(I16),
-            "i32" => Some(I32),
-            "i64" => Some(I64),
-            "usize" => Some(Usize),
-            "u8" => Some(U8),
-            "u16" => Some(U16),
-            "u32" => Some(U32),
-            "u64" => Some(U64),
-            "bool" => Some(Bool),
-            "char" => Some(Char),
-            "str" => Some(Str),
-            "f32" => Some(F32),
-            "f64" => Some(F64),
-            "array" => Some(Array),
-            "slice" => Some(Slice),
-            "tuple" => Some(PrimitiveTuple),
-            "pointer" => Some(PrimitiveRawPointer),
+            "isize" => Some(PrimitiveType::Isize),
+            "i8" => Some(PrimitiveType::I8),
+            "i16" => Some(PrimitiveType::I16),
+            "i32" => Some(PrimitiveType::I32),
+            "i64" => Some(PrimitiveType::I64),
+            "usize" => Some(PrimitiveType::Usize),
+            "u8" => Some(PrimitiveType::U8),
+            "u16" => Some(PrimitiveType::U16),
+            "u32" => Some(PrimitiveType::U32),
+            "u64" => Some(PrimitiveType::U64),
+            "bool" => Some(PrimitiveType::Bool),
+            "char" => Some(PrimitiveType::Char),
+            "str" => Some(PrimitiveType::Str),
+            "f32" => Some(PrimitiveType::F32),
+            "f64" => Some(PrimitiveType::F64),
+            "array" => Some(PrimitiveType::Array),
+            "slice" => Some(PrimitiveType::Slice),
+            "tuple" => Some(PrimitiveType::Tuple),
+            "pointer" => Some(PrimitiveType::RawPointer),
             _ => None,
         }
     }
@@ -1568,25 +1551,25 @@ fn find(attrs: &[Attribute]) -> Option<PrimitiveType> {
 
     pub fn to_string(&self) -> &'static str {
         match *self {
-            Isize => "isize",
-            I8 => "i8",
-            I16 => "i16",
-            I32 => "i32",
-            I64 => "i64",
-            Usize => "usize",
-            U8 => "u8",
-            U16 => "u16",
-            U32 => "u32",
-            U64 => "u64",
-            F32 => "f32",
-            F64 => "f64",
-            Str => "str",
-            Bool => "bool",
-            Char => "char",
-            Array => "array",
-            Slice => "slice",
-            PrimitiveTuple => "tuple",
-            PrimitiveRawPointer => "pointer",
+            PrimitiveType::Isize => "isize",
+            PrimitiveType::I8 => "i8",
+            PrimitiveType::I16 => "i16",
+            PrimitiveType::I32 => "i32",
+            PrimitiveType::I64 => "i64",
+            PrimitiveType::Usize => "usize",
+            PrimitiveType::U8 => "u8",
+            PrimitiveType::U16 => "u16",
+            PrimitiveType::U32 => "u32",
+            PrimitiveType::U64 => "u64",
+            PrimitiveType::F32 => "f32",
+            PrimitiveType::F64 => "f64",
+            PrimitiveType::Str => "str",
+            PrimitiveType::Bool => "bool",
+            PrimitiveType::Char => "char",
+            PrimitiveType::Array => "array",
+            PrimitiveType::Slice => "slice",
+            PrimitiveType::Tuple => "tuple",
+            PrimitiveType::RawPointer => "pointer",
         }
     }
 
@@ -1603,15 +1586,47 @@ pub fn to_def_index(&self) -> DefIndex {
     }
 }
 
+impl From<ast::IntTy> for PrimitiveType {
+    fn from(int_ty: ast::IntTy) -> PrimitiveType {
+        match int_ty {
+            ast::IntTy::Is => PrimitiveType::Isize,
+            ast::IntTy::I8 => PrimitiveType::I8,
+            ast::IntTy::I16 => PrimitiveType::I16,
+            ast::IntTy::I32 => PrimitiveType::I32,
+            ast::IntTy::I64 => PrimitiveType::I64,
+        }
+    }
+}
+
+impl From<ast::UintTy> for PrimitiveType {
+    fn from(uint_ty: ast::UintTy) -> PrimitiveType {
+        match uint_ty {
+            ast::UintTy::Us => PrimitiveType::Usize,
+            ast::UintTy::U8 => PrimitiveType::U8,
+            ast::UintTy::U16 => PrimitiveType::U16,
+            ast::UintTy::U32 => PrimitiveType::U32,
+            ast::UintTy::U64 => PrimitiveType::U64,
+        }
+    }
+}
+
+impl From<ast::FloatTy> for PrimitiveType {
+    fn from(float_ty: ast::FloatTy) -> PrimitiveType {
+        match float_ty {
+            ast::FloatTy::F32 => PrimitiveType::F32,
+            ast::FloatTy::F64 => PrimitiveType::F64,
+        }
+    }
+}
 
 // Poor man's type parameter substitution at HIR level.
 // Used to replace private type aliases in public signatures with their aliased types.
 struct SubstAlias<'a, 'tcx: 'a> {
     tcx: &'a ty::TyCtxt<'a, 'tcx, 'tcx>,
     // Table type parameter definition -> substituted type
-    ty_substs: HashMap<Def, hir::Ty>,
+    ty_substs: FnvHashMap<Def, hir::Ty>,
     // Table node id of lifetime parameter definition -> substituted lifetime
-    lt_substs: HashMap<ast::NodeId, hir::Lifetime>,
+    lt_substs: FnvHashMap<ast::NodeId, hir::Lifetime>,
 }
 
 impl<'a, 'tcx: 'a, 'b: 'tcx> Folder for SubstAlias<'a, 'tcx> {
@@ -1680,8 +1695,8 @@ fn clean(&self, cx: &DocContext) -> Type {
                                 let item = tcx.map.expect_item(node_id);
                                 if let hir::ItemTy(ref ty, ref generics) = item.node {
                                     let provided_params = &path.segments.last().unwrap().parameters;
-                                    let mut ty_substs = HashMap::new();
-                                    let mut lt_substs = HashMap::new();
+                                    let mut ty_substs = FnvHashMap();
+                                    let mut lt_substs = FnvHashMap();
                                     for (i, ty_param) in generics.ty_params.iter().enumerate() {
                                         let ty_param_def = tcx.expect_def(ty_param.id);
                                         if let Some(ty) = provided_params.types().get(i).cloned()
@@ -1754,21 +1769,12 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
     fn clean(&self, cx: &DocContext) -> Type {
         match self.sty {
             ty::TyNever => Never,
-            ty::TyBool => Primitive(Bool),
-            ty::TyChar => Primitive(Char),
-            ty::TyInt(ast::IntTy::Is) => Primitive(Isize),
-            ty::TyInt(ast::IntTy::I8) => Primitive(I8),
-            ty::TyInt(ast::IntTy::I16) => Primitive(I16),
-            ty::TyInt(ast::IntTy::I32) => Primitive(I32),
-            ty::TyInt(ast::IntTy::I64) => Primitive(I64),
-            ty::TyUint(ast::UintTy::Us) => Primitive(Usize),
-            ty::TyUint(ast::UintTy::U8) => Primitive(U8),
-            ty::TyUint(ast::UintTy::U16) => Primitive(U16),
-            ty::TyUint(ast::UintTy::U32) => Primitive(U32),
-            ty::TyUint(ast::UintTy::U64) => Primitive(U64),
-            ty::TyFloat(ast::FloatTy::F32) => Primitive(F32),
-            ty::TyFloat(ast::FloatTy::F64) => Primitive(F64),
-            ty::TyStr => Primitive(Str),
+            ty::TyBool => Primitive(PrimitiveType::Bool),
+            ty::TyChar => Primitive(PrimitiveType::Char),
+            ty::TyInt(int_ty) => Primitive(int_ty.into()),
+            ty::TyUint(uint_ty) => Primitive(uint_ty.into()),
+            ty::TyFloat(float_ty) => Primitive(float_ty.into()),
+            ty::TyStr => Primitive(PrimitiveType::Str),
             ty::TyBox(t) => {
                 let box_did = cx.tcx_opt().and_then(|tcx| {
                     tcx.lang_items.owned_box()
@@ -2346,7 +2352,7 @@ fn clean(&self, _: &DocContext) -> ImplPolarity {
 pub struct Impl {
     pub unsafety: hir::Unsafety,
     pub generics: Generics,
-    pub provided_trait_methods: HashSet<String>,
+    pub provided_trait_methods: FnvHashSet<String>,
     pub trait_: Option<Type>,
     pub for_: Type,
     pub items: Vec<Item>,
@@ -2372,7 +2378,7 @@ fn clean(&self, cx: &DocContext) -> Vec<Item> {
                    .map(|meth| meth.name.to_string())
                    .collect()
             })
-        }).unwrap_or(HashSet::new());
+        }).unwrap_or(FnvHashSet());
 
         ret.push(Item {
             name: None,
@@ -2421,25 +2427,25 @@ fn build_deref_target_impls(cx: &DocContext,
             }
         };
         let did = match primitive {
-            Isize => tcx.lang_items.isize_impl(),
-            I8 => tcx.lang_items.i8_impl(),
-            I16 => tcx.lang_items.i16_impl(),
-            I32 => tcx.lang_items.i32_impl(),
-            I64 => tcx.lang_items.i64_impl(),
-            Usize => tcx.lang_items.usize_impl(),
-            U8 => tcx.lang_items.u8_impl(),
-            U16 => tcx.lang_items.u16_impl(),
-            U32 => tcx.lang_items.u32_impl(),
-            U64 => tcx.lang_items.u64_impl(),
-            F32 => tcx.lang_items.f32_impl(),
-            F64 => tcx.lang_items.f64_impl(),
-            Char => tcx.lang_items.char_impl(),
-            Bool => None,
-            Str => tcx.lang_items.str_impl(),
-            Slice => tcx.lang_items.slice_impl(),
-            Array => tcx.lang_items.slice_impl(),
-            PrimitiveTuple => None,
-            PrimitiveRawPointer => tcx.lang_items.const_ptr_impl(),
+            PrimitiveType::Isize => tcx.lang_items.isize_impl(),
+            PrimitiveType::I8 => tcx.lang_items.i8_impl(),
+            PrimitiveType::I16 => tcx.lang_items.i16_impl(),
+            PrimitiveType::I32 => tcx.lang_items.i32_impl(),
+            PrimitiveType::I64 => tcx.lang_items.i64_impl(),
+            PrimitiveType::Usize => tcx.lang_items.usize_impl(),
+            PrimitiveType::U8 => tcx.lang_items.u8_impl(),
+            PrimitiveType::U16 => tcx.lang_items.u16_impl(),
+            PrimitiveType::U32 => tcx.lang_items.u32_impl(),
+            PrimitiveType::U64 => tcx.lang_items.u64_impl(),
+            PrimitiveType::F32 => tcx.lang_items.f32_impl(),
+            PrimitiveType::F64 => tcx.lang_items.f64_impl(),
+            PrimitiveType::Char => tcx.lang_items.char_impl(),
+            PrimitiveType::Bool => None,
+            PrimitiveType::Str => tcx.lang_items.str_impl(),
+            PrimitiveType::Slice => tcx.lang_items.slice_impl(),
+            PrimitiveType::Array => tcx.lang_items.slice_impl(),
+            PrimitiveType::Tuple => None,
+            PrimitiveType::RawPointer => tcx.lang_items.const_ptr_impl(),
         };
         if let Some(did) = did {
             if !did.is_local() {
@@ -2496,8 +2502,8 @@ fn clean(&self, cx: &DocContext) -> Vec<Item> {
         // Don't inline doc(hidden) imports so they can be stripped at a later stage.
         let denied = self.vis != hir::Public || self.attrs.iter().any(|a| {
             &a.name()[..] == "doc" && match a.meta_item_list() {
-                Some(l) => attr::contains_name(l, "no_inline") ||
-                           attr::contains_name(l, "hidden"),
+                Some(l) => attr::list_contains_name(l, "no_inline") ||
+                           attr::list_contains_name(l, "hidden"),
                 None => false,
             }
         });
@@ -2513,7 +2519,7 @@ fn clean(&self, cx: &DocContext) -> Vec<Item> {
                 let remaining = if !denied {
                     let mut remaining = vec![];
                     for path in list {
-                        match inline::try_inline(cx, path.node.id(), path.node.rename()) {
+                        match inline::try_inline(cx, path.node.id, path.node.rename) {
                             Some(items) => {
                                 ret.extend(items);
                             }
@@ -2581,17 +2587,10 @@ pub struct ViewListIdent {
 
 impl Clean<ViewListIdent> for hir::PathListItem {
     fn clean(&self, cx: &DocContext) -> ViewListIdent {
-        match self.node {
-            hir::PathListIdent { id, name, rename } => ViewListIdent {
-                name: name.clean(cx),
-                rename: rename.map(|r| r.clean(cx)),
-                source: resolve_def(cx, id)
-            },
-            hir::PathListMod { id, rename } => ViewListIdent {
-                name: "self".to_string(),
-                rename: rename.map(|r| r.clean(cx)),
-                source: resolve_def(cx, id)
-            }
+        ViewListIdent {
+            name: self.node.name.clean(cx),
+            rename: self.node.rename.map(|r| r.clean(cx)),
+            source: resolve_def(cx, self.node.id)
         }
     }
 }
@@ -2722,21 +2721,12 @@ fn resolve_type(cx: &DocContext,
 
     let is_generic = match def {
         Def::PrimTy(p) => match p {
-            hir::TyStr => return Primitive(Str),
-            hir::TyBool => return Primitive(Bool),
-            hir::TyChar => return Primitive(Char),
-            hir::TyInt(ast::IntTy::Is) => return Primitive(Isize),
-            hir::TyInt(ast::IntTy::I8) => return Primitive(I8),
-            hir::TyInt(ast::IntTy::I16) => return Primitive(I16),
-            hir::TyInt(ast::IntTy::I32) => return Primitive(I32),
-            hir::TyInt(ast::IntTy::I64) => return Primitive(I64),
-            hir::TyUint(ast::UintTy::Us) => return Primitive(Usize),
-            hir::TyUint(ast::UintTy::U8) => return Primitive(U8),
-            hir::TyUint(ast::UintTy::U16) => return Primitive(U16),
-            hir::TyUint(ast::UintTy::U32) => return Primitive(U32),
-            hir::TyUint(ast::UintTy::U64) => return Primitive(U64),
-            hir::TyFloat(ast::FloatTy::F32) => return Primitive(F32),
-            hir::TyFloat(ast::FloatTy::F64) => return Primitive(F64),
+            hir::TyStr => return Primitive(PrimitiveType::Str),
+            hir::TyBool => return Primitive(PrimitiveType::Bool),
+            hir::TyChar => return Primitive(PrimitiveType::Char),
+            hir::TyInt(int_ty) => return Primitive(int_ty.into()),
+            hir::TyUint(uint_ty) => return Primitive(uint_ty.into()),
+            hir::TyFloat(float_ty) => return Primitive(float_ty.into()),
         },
         Def::SelfTy(..) if path.segments.len() == 1 => {
             return Generic(keywords::SelfType.name().to_string());
@@ -2803,7 +2793,7 @@ pub struct Macro {
 
 impl Clean<Item> for doctree::Macro {
     fn clean(&self, cx: &DocContext) -> Item {
-        let name = format!("{}!", self.name.clean(cx));
+        let name = self.name.clean(cx);
         Item {
             name: Some(name.clone()),
             attrs: self.attrs.clean(cx),
@@ -2814,8 +2804,10 @@ fn clean(&self, cx: &DocContext) -> Item {
             def_id: cx.map.local_def_id(self.id),
             inner: MacroItem(Macro {
                 source: format!("macro_rules! {} {{\n{}}}",
-                    name.trim_right_matches('!'), self.matchers.iter().map(|span|
-                        format!("    {} => {{ ... }};\n", span.to_src(cx))).collect::<String>()),
+                                name,
+                                self.matchers.iter().map(|span| {
+                                    format!("    {} => {{ ... }};\n", span.to_src(cx))
+                                }).collect::<String>()),
                 imported_from: self.imported_from.clean(cx),
             }),
         }
index 10736d2c827cdf8f59a207156332bd1a0e81886f..26f792a1fdf99c14e249952d67f522929ae208b4 100644 (file)
@@ -18,6 +18,7 @@
 use rustc::ty::{self, TyCtxt};
 use rustc::hir::map as hir_map;
 use rustc::lint;
+use rustc::util::nodemap::{FnvHashMap, FnvHashSet};
 use rustc_trans::back::link;
 use rustc_resolve as resolve;
 use rustc_metadata::cstore::CStore;
@@ -28,7 +29,6 @@
 use errors::emitter::ColorConfig;
 
 use std::cell::{RefCell, Cell};
-use std::collections::{HashMap, HashSet};
 use std::rc::Rc;
 
 use visit_ast::RustdocVisitor;
@@ -45,13 +45,13 @@ pub enum MaybeTyped<'a, 'tcx: 'a> {
     NotTyped(&'a session::Session)
 }
 
-pub type ExternalPaths = HashMap<DefId, (Vec<String>, clean::TypeKind)>;
+pub type ExternalPaths = FnvHashMap<DefId, (Vec<String>, clean::TypeKind)>;
 
 pub struct DocContext<'a, 'tcx: 'a> {
     pub map: &'a hir_map::Map<'tcx>,
     pub maybe_typed: MaybeTyped<'a, 'tcx>,
     pub input: Input,
-    pub populated_crate_impls: RefCell<HashSet<ast::CrateNum>>,
+    pub populated_crate_impls: RefCell<FnvHashSet<ast::CrateNum>>,
     pub deref_trait_did: Cell<Option<DefId>>,
     // Note that external items for which `doc(hidden)` applies to are shown as
     // non-reachable while local items aren't. This is because we're reusing
@@ -61,7 +61,7 @@ pub struct DocContext<'a, 'tcx: 'a> {
     /// Later on moved into `html::render::CACHE_KEY`
     pub renderinfo: RefCell<RenderInfo>,
     /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY`
-    pub external_traits: RefCell<HashMap<DefId, clean::Trait>>,
+    pub external_traits: RefCell<FnvHashMap<DefId, clean::Trait>>,
 }
 
 impl<'b, 'tcx> DocContext<'b, 'tcx> {
@@ -159,7 +159,7 @@ pub fn run_core(search_paths: SearchPaths,
                                                      resolutions,
                                                      &arenas,
                                                      &name,
-                                                     |tcx, _, analysis, result| {
+                                                     |tcx, _, analysis, _, result| {
         if let Err(_) = result {
             sess.fatal("Compilation failed, aborting rustdoc");
         }
@@ -178,10 +178,10 @@ pub fn run_core(search_paths: SearchPaths,
             map: &tcx.map,
             maybe_typed: Typed(tcx),
             input: input,
-            populated_crate_impls: RefCell::new(HashSet::new()),
+            populated_crate_impls: RefCell::new(FnvHashSet()),
             deref_trait_did: Cell::new(None),
             access_levels: RefCell::new(access_levels),
-            external_traits: RefCell::new(HashMap::new()),
+            external_traits: RefCell::new(FnvHashMap()),
             renderinfo: RefCell::new(Default::default()),
         };
         debug!("crate: {:?}", ctxt.map.krate());
diff --git a/src/librustdoc/flock.rs b/src/librustdoc/flock.rs
deleted file mode 100644 (file)
index 41bcfdb..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-// 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.
-
-//! Simple file-locking apis for each OS.
-//!
-//! This is not meant to be in the standard library, it does nothing with
-//! green/native threading. This is just a bare-bones enough solution for
-//! librustdoc, it is not production quality at all.
-
-#![allow(non_camel_case_types)]
-
-pub use self::imp::Lock;
-
-#[cfg(unix)]
-mod imp {
-    use std::ffi::{CString, OsStr};
-    use std::os::unix::prelude::*;
-    use std::path::Path;
-    use std::io;
-    use libc;
-
-    #[cfg(target_os = "linux")]
-    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_WRLCK: libc::c_short = 1;
-        pub const F_UNLCK: libc::c_short = 2;
-        pub const F_SETLK: libc::c_int = 6;
-        pub const F_SETLKW: libc::c_int = 7;
-    }
-
-    #[cfg(target_os = "freebsd")]
-    mod os {
-        use libc;
-
-        pub struct flock {
-            pub l_start: libc::off_t,
-            pub l_len: libc::off_t,
-            pub l_pid: libc::pid_t,
-            pub l_type: libc::c_short,
-            pub l_whence: libc::c_short,
-            pub l_sysid: libc::c_int,
-        }
-
-        pub const F_UNLCK: libc::c_short = 2;
-        pub const F_WRLCK: libc::c_short = 3;
-        pub const F_SETLK: libc::c_int = 12;
-        pub const F_SETLKW: libc::c_int = 13;
-    }
-
-    #[cfg(any(target_os = "dragonfly",
-              target_os = "bitrig",
-              target_os = "netbsd",
-              target_os = "openbsd"))]
-    mod os {
-        use libc;
-
-        pub struct flock {
-            pub l_start: libc::off_t,
-            pub l_len: libc::off_t,
-            pub l_pid: libc::pid_t,
-            pub l_type: libc::c_short,
-            pub l_whence: libc::c_short,
-
-            // not actually here, but brings in line with freebsd
-            pub l_sysid: libc::c_int,
-        }
-
-        pub const F_UNLCK: libc::c_short = 2;
-        pub const F_WRLCK: libc::c_short = 3;
-        pub const F_SETLK: libc::c_int = 8;
-        pub const F_SETLKW: libc::c_int = 9;
-    }
-
-    #[cfg(any(target_os = "macos", target_os = "ios"))]
-    mod os {
-        use libc;
-
-        pub struct flock {
-            pub l_start: libc::off_t,
-            pub l_len: libc::off_t,
-            pub l_pid: libc::pid_t,
-            pub l_type: libc::c_short,
-            pub l_whence: libc::c_short,
-
-            // not actually here, but brings in line with freebsd
-            pub l_sysid: libc::c_int,
-        }
-
-        pub const F_UNLCK: libc::c_short = 2;
-        pub const F_WRLCK: libc::c_short = 3;
-        pub const F_SETLK: libc::c_int = 8;
-        pub const F_SETLKW: libc::c_int = 9;
-    }
-
-    #[cfg(target_os = "solaris")]
-    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_sysid: libc::c_int,
-            pub l_pid: libc::pid_t,
-        }
-
-        pub const F_WRLCK: libc::c_short = 2;
-        pub const F_UNLCK: libc::c_short = 3;
-        pub const F_SETLK: libc::c_int = 6;
-        pub const F_SETLKW: libc::c_int = 7;
-    }
-
-    pub struct Lock {
-        fd: libc::c_int,
-    }
-
-    impl Lock {
-        pub fn new(p: &Path) -> Lock {
-            let os: &OsStr = p.as_ref();
-            let buf = CString::new(os.as_bytes()).unwrap();
-            let fd = unsafe {
-                libc::open(buf.as_ptr(), libc::O_RDWR | libc::O_CREAT,
-                           libc::S_IRWXU as libc::c_int)
-            };
-            assert!(fd > 0, "failed to open lockfile: {}",
-                    io::Error::last_os_error());
-            let flock = os::flock {
-                l_start: 0,
-                l_len: 0,
-                l_pid: 0,
-                l_whence: libc::SEEK_SET as libc::c_short,
-                l_type: os::F_WRLCK,
-                l_sysid: 0,
-            };
-            let ret = unsafe {
-                libc::fcntl(fd, os::F_SETLKW, &flock)
-            };
-            if ret == -1 {
-                let err = io::Error::last_os_error();
-                unsafe { libc::close(fd); }
-                panic!("could not lock `{}`: {}", p.display(), err);
-            }
-            Lock { fd: fd }
-        }
-    }
-
-    impl Drop for Lock {
-        fn drop(&mut self) {
-            let flock = os::flock {
-                l_start: 0,
-                l_len: 0,
-                l_pid: 0,
-                l_whence: libc::SEEK_SET as libc::c_short,
-                l_type: os::F_UNLCK,
-                l_sysid: 0,
-            };
-            unsafe {
-                libc::fcntl(self.fd, os::F_SETLK, &flock);
-                libc::close(self.fd);
-            }
-        }
-    }
-}
-
-#[cfg(windows)]
-#[allow(bad_style)]
-mod imp {
-    use std::io;
-    use std::mem;
-    use std::os::windows::prelude::*;
-    use std::os::windows::raw::HANDLE;
-    use std::path::Path;
-    use std::fs::{File, OpenOptions};
-
-    type DWORD = u32;
-    type LPOVERLAPPED = *mut OVERLAPPED;
-    type BOOL = i32;
-    const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x00000002;
-
-    #[repr(C)]
-    struct OVERLAPPED {
-        Internal: usize,
-        InternalHigh: usize,
-        Pointer: *mut u8,
-        hEvent: *mut u8,
-    }
-
-    extern "system" {
-        fn LockFileEx(hFile: HANDLE,
-                      dwFlags: DWORD,
-                      dwReserved: DWORD,
-                      nNumberOfBytesToLockLow: DWORD,
-                      nNumberOfBytesToLockHigh: DWORD,
-                      lpOverlapped: LPOVERLAPPED) -> BOOL;
-    }
-
-    pub struct Lock {
-        _file: File,
-    }
-
-    impl Lock {
-        pub fn new(p: &Path) -> Lock {
-            let f = OpenOptions::new().read(true).write(true).create(true)
-                                      .open(p).unwrap();
-            let ret = unsafe {
-                let mut overlapped: OVERLAPPED = mem::zeroed();
-                LockFileEx(f.as_raw_handle(), LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0,
-                           &mut overlapped)
-            };
-            if ret == 0 {
-                let err = io::Error::last_os_error();
-                panic!("could not lock `{}`: {}", p.display(), err);
-            }
-            Lock { _file: f }
-        }
-    }
-}
index f8b852074dd2b1a3180107e1c8523de9cb7eb6db..65992798ab0995382ef32a4457c53e42347c00a6 100644 (file)
@@ -23,7 +23,7 @@
 use syntax::abi::Abi;
 use rustc::hir;
 
-use clean;
+use clean::{self, PrimitiveType};
 use core::DocAccessLevels;
 use html::item_type::ItemType;
 use html::escape::Escape;
@@ -468,39 +468,39 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             }
             clean::Tuple(ref typs) => {
                 match &typs[..] {
-                    &[] => primitive_link(f, clean::PrimitiveTuple, "()"),
+                    &[] => primitive_link(f, PrimitiveType::Tuple, "()"),
                     &[ref one] => {
-                        primitive_link(f, clean::PrimitiveTuple, "(")?;
+                        primitive_link(f, PrimitiveType::Tuple, "(")?;
                         write!(f, "{},", one)?;
-                        primitive_link(f, clean::PrimitiveTuple, ")")
+                        primitive_link(f, PrimitiveType::Tuple, ")")
                     }
                     many => {
-                        primitive_link(f, clean::PrimitiveTuple, "(")?;
+                        primitive_link(f, PrimitiveType::Tuple, "(")?;
                         write!(f, "{}", CommaSep(&many))?;
-                        primitive_link(f, clean::PrimitiveTuple, ")")
+                        primitive_link(f, PrimitiveType::Tuple, ")")
                     }
                 }
             }
             clean::Vector(ref t) => {
-                primitive_link(f, clean::Slice, &format!("["))?;
+                primitive_link(f, PrimitiveType::Slice, &format!("["))?;
                 write!(f, "{}", t)?;
-                primitive_link(f, clean::Slice, &format!("]"))
+                primitive_link(f, PrimitiveType::Slice, &format!("]"))
             }
             clean::FixedVector(ref t, ref s) => {
-                primitive_link(f, clean::PrimitiveType::Array, "[")?;
+                primitive_link(f, PrimitiveType::Array, "[")?;
                 write!(f, "{}", t)?;
-                primitive_link(f, clean::PrimitiveType::Array,
+                primitive_link(f, PrimitiveType::Array,
                                &format!("; {}]", Escape(s)))
             }
             clean::Never => f.write_str("!"),
             clean::RawPointer(m, ref t) => {
                 match **t {
                     clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
-                        primitive_link(f, clean::PrimitiveType::PrimitiveRawPointer,
+                        primitive_link(f, clean::PrimitiveType::RawPointer,
                                        &format!("*{}{}", RawMutableSpace(m), t))
                     }
                     _ => {
-                        primitive_link(f, clean::PrimitiveType::PrimitiveRawPointer,
+                        primitive_link(f, clean::PrimitiveType::RawPointer,
                                        &format!("*{}", RawMutableSpace(m)))?;
                         write!(f, "{}", t)
                     }
@@ -516,12 +516,13 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                     clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
                         match **bt {
                             clean::Generic(_) =>
-                                primitive_link(f, clean::Slice,
+                                primitive_link(f, PrimitiveType::Slice,
                                     &format!("&amp;{}{}[{}]", lt, m, **bt)),
                             _ => {
-                                primitive_link(f, clean::Slice, &format!("&amp;{}{}[", lt, m))?;
+                                primitive_link(f, PrimitiveType::Slice,
+                                               &format!("&amp;{}{}[", lt, m))?;
                                 write!(f, "{}", **bt)?;
-                                primitive_link(f, clean::Slice, "]")
+                                primitive_link(f, PrimitiveType::Slice, "]")
                             }
                         }
                     }
index 6b462a76f04ed4a7dc03a31622b1ea02cf0d68eb..be192179284676b9b76fa40162cf22c4ef8ffc31 100644 (file)
@@ -50,8 +50,8 @@ pub enum NameSpace {
     Macro,
 }
 
-impl ItemType {
-    pub fn from_item(item: &clean::Item) -> ItemType {
+impl<'a> From<&'a clean::Item> for ItemType {
+    fn from(item: &'a clean::Item) -> ItemType {
         let inner = match item.inner {
             clean::StrippedItem(box ref item) => item,
             ref inner@_ => inner,
@@ -83,8 +83,10 @@ pub fn from_item(item: &clean::Item) -> ItemType {
             clean::StrippedItem(..)        => unreachable!(),
         }
     }
+}
 
-    pub fn from_type_kind(kind: clean::TypeKind) -> ItemType {
+impl From<clean::TypeKind> for ItemType {
+    fn from(kind: clean::TypeKind) -> ItemType {
         match kind {
             clean::TypeStruct   => ItemType::Struct,
             clean::TypeEnum     => ItemType::Enum,
@@ -97,7 +99,9 @@ pub fn from_type_kind(kind: clean::TypeKind) -> ItemType {
             clean::TypeTypedef  => ItemType::Typedef,
         }
     }
+}
 
+impl ItemType {
     pub fn css_class(&self) -> &'static str {
         match *self {
             ItemType::Module          => "mod",
index d654429146d83738d9a39888cbe785f0592c84d0..6d523ff381556799d5715fdbcdaa18eb45fdf98b 100644 (file)
@@ -37,7 +37,7 @@
 use std::ascii::AsciiExt;
 use std::cell::RefCell;
 use std::cmp::Ordering;
-use std::collections::{BTreeMap, HashMap, HashSet};
+use std::collections::BTreeMap;
 use std::default::Default;
 use std::error;
 use std::fmt::{self, Display, Formatter};
@@ -61,6 +61,8 @@
 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;
 
 use clean::{self, Attributes, GetDefId};
 use doctree;
@@ -114,9 +116,9 @@ pub struct SharedContext {
     /// `true`.
     pub include_sources: bool,
     /// The local file sources we've emitted and their respective url-paths.
-    pub local_sources: HashMap<PathBuf, String>,
+    pub local_sources: FnvHashMap<PathBuf, String>,
     /// All the passes that were run on this crate.
-    pub passes: HashSet<String>,
+    pub passes: FnvHashSet<String>,
     /// The base-URL of the issue tracker for when an item has been tagged with
     /// an issue number.
     pub issue_tracker_base_url: Option<String>,
@@ -211,7 +213,7 @@ pub struct Cache {
     /// Mapping of typaram ids to the name of the type parameter. This is used
     /// when pretty-printing a type (so pretty printing doesn't have to
     /// painfully maintain a context like this)
-    pub typarams: HashMap<DefId, String>,
+    pub typarams: FnvHashMap<DefId, String>,
 
     /// Maps a type id to all known implementations for that type. This is only
     /// recognized for intra-crate `ResolvedPath` types, and is used to print
@@ -219,35 +221,35 @@ pub struct Cache {
     ///
     /// The values of the map are a list of implementations and documentation
     /// found on that implementation.
-    pub impls: HashMap<DefId, Vec<Impl>>,
+    pub impls: FnvHashMap<DefId, Vec<Impl>>,
 
     /// Maintains a mapping of local crate node ids to the fully qualified name
     /// and "short type description" of that node. This is used when generating
     /// URLs when a type is being linked to. External paths are not located in
     /// this map because the `External` type itself has all the information
     /// necessary.
-    pub paths: HashMap<DefId, (Vec<String>, ItemType)>,
+    pub paths: FnvHashMap<DefId, (Vec<String>, ItemType)>,
 
     /// Similar to `paths`, but only holds external paths. This is only used for
     /// generating explicit hyperlinks to other crates.
-    pub external_paths: HashMap<DefId, (Vec<String>, ItemType)>,
+    pub external_paths: FnvHashMap<DefId, (Vec<String>, ItemType)>,
 
     /// This map contains information about all known traits of this crate.
     /// Implementations of a crate should inherit the documentation of the
     /// parent trait if no extra documentation is specified, and default methods
     /// should show up in documentation about trait implementations.
-    pub traits: HashMap<DefId, clean::Trait>,
+    pub traits: FnvHashMap<DefId, clean::Trait>,
 
     /// When rendering traits, it's often useful to be able to list all
     /// implementors of the trait, and this mapping is exactly, that: a mapping
     /// of trait ids to the list of known implementors of the trait
-    pub implementors: HashMap<DefId, Vec<Implementor>>,
+    pub implementors: FnvHashMap<DefId, Vec<Implementor>>,
 
     /// Cache of where external crate documentation can be found.
-    pub extern_locations: HashMap<ast::CrateNum, (String, ExternalLocation)>,
+    pub extern_locations: FnvHashMap<ast::CrateNum, (String, ExternalLocation)>,
 
     /// Cache of where documentation for primitives can be found.
-    pub primitive_locations: HashMap<clean::PrimitiveType, ast::CrateNum>,
+    pub primitive_locations: FnvHashMap<clean::PrimitiveType, ast::CrateNum>,
 
     // Note that external items for which `doc(hidden)` applies to are shown as
     // non-reachable while local items aren't. This is because we're reusing
@@ -260,7 +262,7 @@ pub struct Cache {
     parent_stack: Vec<DefId>,
     parent_is_trait_impl: bool,
     search_index: Vec<IndexItem>,
-    seen_modules: HashSet<DefId>,
+    seen_modules: FnvHashSet<DefId>,
     seen_mod: bool,
     stripped_mod: bool,
     deref_trait_did: Option<DefId>,
@@ -277,9 +279,9 @@ pub struct Cache {
 /// Later on moved into `CACHE_KEY`.
 #[derive(Default)]
 pub struct RenderInfo {
-    pub inlined: HashSet<DefId>,
+    pub inlined: FnvHashSet<DefId>,
     pub external_paths: ::core::ExternalPaths,
-    pub external_typarams: HashMap<DefId, String>,
+    pub external_typarams: FnvHashMap<DefId, String>,
     pub deref_trait_did: Option<DefId>,
 }
 
@@ -377,10 +379,10 @@ fn to_json(&self) -> Json {
 thread_local!(static CACHE_KEY: RefCell<Arc<Cache>> = Default::default());
 thread_local!(pub static CURRENT_LOCATION_KEY: RefCell<Vec<String>> =
                     RefCell::new(Vec::new()));
-thread_local!(static USED_ID_MAP: RefCell<HashMap<String, usize>> =
+thread_local!(static USED_ID_MAP: RefCell<FnvHashMap<String, usize>> =
                     RefCell::new(init_ids()));
 
-fn init_ids() -> HashMap<String, usize> {
+fn init_ids() -> FnvHashMap<String, usize> {
     [
      "main",
      "search",
@@ -407,7 +409,7 @@ pub fn reset_ids(embedded: bool) {
         *s.borrow_mut() = if embedded {
             init_ids()
         } else {
-            HashMap::new()
+            FnvHashMap()
         };
     });
 }
@@ -432,7 +434,7 @@ pub fn derive_id(candidate: String) -> String {
 pub fn run(mut krate: clean::Crate,
            external_html: &ExternalHtml,
            dst: PathBuf,
-           passes: HashSet<String>,
+           passes: FnvHashSet<String>,
            css_file_extension: Option<PathBuf>,
            renderinfo: RenderInfo) -> Result<(), Error> {
     let src_root = match krate.src.parent() {
@@ -443,7 +445,7 @@ pub fn run(mut krate: clean::Crate,
         src_root: src_root,
         passes: passes,
         include_sources: true,
-        local_sources: HashMap::new(),
+        local_sources: FnvHashMap(),
         issue_tracker_base_url: None,
         layout: layout::Layout {
             logo: "".to_string(),
@@ -509,26 +511,26 @@ pub fn run(mut krate: clean::Crate,
     } = renderinfo;
 
     let external_paths = external_paths.into_iter()
-        .map(|(k, (v, t))| (k, (v, ItemType::from_type_kind(t))))
+        .map(|(k, (v, t))| (k, (v, ItemType::from(t))))
         .collect();
 
     let mut cache = Cache {
-        impls: HashMap::new(),
+        impls: FnvHashMap(),
         external_paths: external_paths,
-        paths: HashMap::new(),
-        implementors: HashMap::new(),
+        paths: FnvHashMap(),
+        implementors: FnvHashMap(),
         stack: Vec::new(),
         parent_stack: Vec::new(),
         search_index: Vec::new(),
         parent_is_trait_impl: false,
-        extern_locations: HashMap::new(),
-        primitive_locations: HashMap::new(),
-        seen_modules: HashSet::new(),
+        extern_locations: FnvHashMap(),
+        primitive_locations: FnvHashMap(),
+        seen_modules: FnvHashSet(),
         seen_mod: false,
         stripped_mod: false,
         access_levels: krate.access_levels.clone(),
         orphan_methods: Vec::new(),
-        traits: mem::replace(&mut krate.external_traits, HashMap::new()),
+        traits: mem::replace(&mut krate.external_traits, FnvHashMap()),
         deref_trait_did: deref_trait_did,
         typarams: external_typarams,
     };
@@ -574,7 +576,7 @@ pub fn run(mut krate: clean::Crate,
 
 /// Build the search index from the collected metadata
 fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
-    let mut nodeid_to_pathid = HashMap::new();
+    let mut nodeid_to_pathid = FnvHashMap();
     let mut crate_items = Vec::with_capacity(cache.search_index.len());
     let mut crate_paths = Vec::<Json>::new();
 
@@ -650,7 +652,7 @@ fn write_shared(cx: &Context,
     // docs placed in the output directory, so this needs to be a synchronized
     // operation with respect to all other rustdocs running around.
     try_err!(mkdir(&cx.dst), &cx.dst);
-    let _lock = ::flock::Lock::new(&cx.dst.join(".lock"));
+    let _lock = flock::Lock::panicking_new(&cx.dst.join(".lock"), true, true, true);
 
     // Add all the static files. These may already exist, but we just
     // overwrite them anyway to make sure that they're fresh and up-to-date.
@@ -833,7 +835,7 @@ 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(item)
+    ItemType::from(item)
 }
 
 /// Takes a path to a source file and cleans the path to it. This canonicalizes
@@ -997,17 +999,8 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
 
         // Register any generics to their corresponding string. This is used
         // when pretty-printing types
-        match item.inner {
-            clean::StructItem(ref s)          => self.generics(&s.generics),
-            clean::EnumItem(ref e)            => self.generics(&e.generics),
-            clean::FunctionItem(ref f)        => self.generics(&f.generics),
-            clean::TypedefItem(ref t, _)      => self.generics(&t.generics),
-            clean::TraitItem(ref t)           => self.generics(&t.generics),
-            clean::ImplItem(ref i)            => self.generics(&i.generics),
-            clean::TyMethodItem(ref i)        => self.generics(&i.generics),
-            clean::MethodItem(ref i)          => self.generics(&i.generics),
-            clean::ForeignFunctionItem(ref f) => self.generics(&f.generics),
-            _ => {}
+        if let Some(generics) = item.inner.generics() {
+            self.generics(generics);
         }
 
         if !self.seen_mod {
@@ -1362,7 +1355,7 @@ fn item<F>(&mut self, item: clean::Item, mut f: F) -> Result<(), Error> where
         // these modules are recursed into, but not rendered normally
         // (a flag on the context).
         if !self.render_redirect_pages {
-            self.render_redirect_pages = self.maybe_ignore_item(&item);
+            self.render_redirect_pages = maybe_ignore_item(&item);
         }
 
         if item.is_mod() {
@@ -1426,6 +1419,16 @@ fn item<F>(&mut self, item: clean::Item, mut f: F) -> Result<(), Error> where
                                                                 .open(&redir_dst) {
                     try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst);
                 }
+
+                // If the item is a macro, redirect from the old macro URL (with !)
+                // to the new one (without).
+                // FIXME(#35705) remove this redirect.
+                if item_type == ItemType::Macro {
+                    let redir_name = format!("{}.{}!.html", item_type, name);
+                    let redir_dst = self.dst.join(redir_name);
+                    let mut redirect_out = try_err!(File::create(&redir_dst), &redir_dst);
+                    try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst);
+                }
             }
         }
         Ok(())
@@ -1435,7 +1438,7 @@ fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<NameDoc
         // BTreeMap instead of HashMap to get a sorted output
         let mut map = BTreeMap::new();
         for item in &m.items {
-            if self.maybe_ignore_item(item) { continue }
+            if maybe_ignore_item(item) { continue }
 
             let short = item_type(item).css_class();
             let myname = match item.name {
@@ -1452,17 +1455,6 @@ fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<NameDoc
         }
         return map;
     }
-
-    fn maybe_ignore_item(&self, it: &clean::Item) -> bool {
-        match it.inner {
-            clean::StrippedItem(..) => true,
-            clean::ModuleItem(ref m) => {
-                it.doc_value().is_none() && m.items.is_empty()
-                                         && it.visibility != Some(clean::Public)
-            },
-            _ => false,
-        }
-    }
 }
 
 impl<'a> Item<'a> {
@@ -1705,7 +1697,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
         if let clean::DefaultImplItem(..) = items[*i].inner {
             return false;
         }
-        !cx.maybe_ignore_item(&items[*i])
+        !maybe_ignore_item(&items[*i])
     }).collect::<Vec<usize>>();
 
     // the order of item types in the listing
@@ -1853,6 +1845,17 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
     Ok(())
 }
 
+fn maybe_ignore_item(it: &clean::Item) -> bool {
+    match it.inner {
+        clean::StrippedItem(..) => true,
+        clean::ModuleItem(ref m) => {
+            it.doc_value().is_none() && m.items.is_empty()
+                                     && it.visibility != Some(clean::Public)
+        },
+        _ => false,
+    }
+}
+
 fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<String> {
     let mut stability = vec![];
 
@@ -2514,7 +2517,7 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
 #[derive(Copy, Clone)]
 enum AssocItemLink<'a> {
     Anchor(Option<&'a str>),
-    GotoSource(DefId, &'a HashSet<String>),
+    GotoSource(DefId, &'a FnvHashSet<String>),
 }
 
 impl<'a> AssocItemLink<'a> {
index 68035e5abe4c28278f908ce180aca006b0c5b41b..de7e4d2483b4336b2b95fbb7dca2225451dda601 100644 (file)
                         displayPath = item.path + '::';
                         href = rootPath + item.path.replace(/::/g, '/') + '/' +
                                name + '/index.html';
-                    } else if (type === 'static' || type === 'reexport') {
-                        displayPath = item.path + '::';
-                        href = rootPath + item.path.replace(/::/g, '/') +
-                               '/index.html';
                     } else if (type === "primitive") {
                         displayPath = "";
                         href = rootPath + item.path.replace(/::/g, '/') +
                     } else if (item.parent !== undefined) {
                         var myparent = item.parent;
                         var anchor = '#' + type + '.' + name;
-                        displayPath = item.path + '::' + myparent.name + '::';
+                        var parentType = itemTypes[myparent.ty];
+                        if (parentType === "primitive") {
+                            displayPath = myparent.name + '::';
+                        } else {
+                            displayPath = item.path + '::' + myparent.name + '::';
+                        }
                         href = rootPath + item.path.replace(/::/g, '/') +
-                               '/' + itemTypes[myparent.ty] +
+                               '/' + parentType +
                                '.' + myparent.name +
                                '.html' + anchor;
                     } else {
index 255e6b1e786dfd38f621eaee0d7d318a6519a45e..0e685f063bd7b52dfc40f5f067bebaede45f7c65 100644 (file)
@@ -35,6 +35,7 @@
 extern crate rustc;
 extern crate rustc_const_eval;
 extern crate rustc_const_math;
+extern crate rustc_data_structures;
 extern crate rustc_trans;
 extern crate rustc_driver;
 extern crate rustc_resolve;
@@ -86,7 +87,6 @@ pub mod html {
 pub mod visit_ast;
 pub mod visit_lib;
 pub mod test;
-mod flock;
 
 use clean::Attributes;
 
index 7d1dbbe5dc07d9d645656ff7cb35bf1d6165ed23..beed1dc9f9e71d14104018e47d97b11563a87291 100644 (file)
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 use std::cell::{RefCell, Cell};
-use std::collections::{HashMap, HashSet};
 use std::env;
 use std::ffi::OsString;
 use std::io::prelude::*;
@@ -29,6 +28,7 @@
 use rustc::session::config::{get_unstable_features_setting, OutputType,
                              OutputTypes, Externs};
 use rustc::session::search_paths::{SearchPaths, PathKind};
+use rustc::util::nodemap::{FnvHashMap, FnvHashSet};
 use rustc_back::dynamic_lib::DynamicLibrary;
 use rustc_back::tempdir::TempDir;
 use rustc_driver::{driver, Compilation};
@@ -107,8 +107,8 @@ pub fn run(input: &str,
         map: &map,
         maybe_typed: core::NotTyped(&sess),
         input: input,
-        external_traits: RefCell::new(HashMap::new()),
-        populated_crate_impls: RefCell::new(HashSet::new()),
+        external_traits: RefCell::new(FnvHashMap()),
+        populated_crate_impls: RefCell::new(FnvHashSet()),
         deref_trait_did: Cell::new(None),
         access_levels: Default::default(),
         renderinfo: Default::default(),
@@ -140,7 +140,6 @@ pub fn run(input: &str,
 
 // Look for #![doc(test(no_crate_inject))], used by crates in the std facade
 fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions {
-    use syntax::attr::AttrMetaMethods;
     use syntax::print::pprust;
 
     let mut opts = TestOptions {
@@ -162,7 +161,7 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions {
         if attr.check_name("attr") {
             if let Some(l) = attr.meta_item_list() {
                 for item in l {
-                    opts.attrs.push(pprust::meta_item_to_string(item));
+                    opts.attrs.push(pprust::meta_list_item_to_string(item));
                 }
             }
         }
index 0334c5ef5c4f4397120d1408d1f8aa6227c8e5f8..6af36e24d815632885c808bcb4620bd9283c18b1 100644 (file)
 //! Rust AST Visitor. Extracts useful information and massages it into a form
 //! usable for clean
 
-use std::collections::HashSet;
 use std::mem;
 
 use syntax::abi;
 use syntax::ast;
 use syntax::attr;
-use syntax::attr::AttrMetaMethods;
 use syntax_pos::Span;
 
 use rustc::hir::map as hir_map;
 use rustc::hir::def::Def;
 use rustc::middle::privacy::AccessLevel;
+use rustc::util::nodemap::FnvHashSet;
 
 use rustc::hir;
 
@@ -42,14 +41,14 @@ pub struct RustdocVisitor<'a, 'tcx: 'a> {
     pub module: Module,
     pub attrs: hir::HirVec<ast::Attribute>,
     pub cx: &'a core::DocContext<'a, 'tcx>,
-    view_item_stack: HashSet<ast::NodeId>,
+    view_item_stack: FnvHashSet<ast::NodeId>,
     inlining_from_glob: bool,
 }
 
 impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
     pub fn new(cx: &'a core::DocContext<'a, 'tcx>) -> RustdocVisitor<'a, 'tcx> {
         // If the root is reexported, terminate all recursion.
-        let mut stack = HashSet::new();
+        let mut stack = FnvHashSet();
         stack.insert(ast::CRATE_NODE_ID);
         RustdocVisitor {
             module: Module::new(None),
@@ -189,7 +188,7 @@ fn visit_view_path(&mut self, path: hir::ViewPath_,
             }
             hir::ViewPathList(p, paths) => {
                 let mine = paths.into_iter().filter(|path| {
-                    !self.maybe_inline_local(path.node.id(), path.node.rename(),
+                    !self.maybe_inline_local(path.node.id, path.node.rename,
                                              false, om, please_inline)
                 }).collect::<hir::HirVec<hir::PathListItem>>();
 
@@ -333,8 +332,8 @@ pub fn visit_item(&mut self, item: &hir::Item,
                 let node = if item.vis == hir::Public {
                     let please_inline = item.attrs.iter().any(|item| {
                         match item.meta_item_list() {
-                            Some(list) if &item.name()[..] == "doc" => {
-                                list.iter().any(|i| &i.name()[..] == "inline")
+                            Some(list) if item.check_name("doc") => {
+                                list.iter().any(|i| i.check_name("inline"))
                             }
                             _ => false,
                         }
index 5d652ba2f55bbc72775d16613171bf40c3ffbaa1..7b5092e8848e4072a40dd88f9d6712006a48706b 100644 (file)
@@ -136,7 +136,7 @@ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
         for item in self {
             bits |= item.to_usize();
         }
-        s.emit_uint(bits)
+        s.emit_usize(bits)
     }
 }
 
@@ -144,7 +144,7 @@ impl<
     T: Decodable + CLike
 > Decodable for EnumSet<T> {
     fn decode<D: Decoder>(d: &mut D) -> Result<EnumSet<T>, D::Error> {
-        let bits = d.read_uint()?;
+        let bits = d.read_usize()?;
         let mut set = EnumSet::new();
         for bit in 0..(mem::size_of::<usize>()*8) {
             if bits & (1 << bit) != 0 {
index 6c4b6c4506b814fd7d19b5575841b6703ef54f52..0782601e1796e21179de6e5a1f29503f0e08b956 100644 (file)
@@ -495,13 +495,13 @@ fn emit_nil(&mut self) -> EncodeResult {
         Ok(())
     }
 
-    fn emit_uint(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
+    fn emit_usize(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
     fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
     fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
     fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
     fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
 
-    fn emit_int(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
+    fn emit_isize(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
     fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
     fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
     fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
@@ -743,13 +743,13 @@ fn emit_nil(&mut self) -> EncodeResult {
         Ok(())
     }
 
-    fn emit_uint(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
+    fn emit_usize(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
     fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
     fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
     fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
     fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
 
-    fn emit_int(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
+    fn emit_isize(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
     fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
     fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
     fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) }
@@ -2137,12 +2137,12 @@ fn read_nil(&mut self) -> DecodeResult<()> {
         expect!(self.pop(), Null)
     }
 
-    read_primitive! { read_uint, usize }
+    read_primitive! { read_usize, usize }
     read_primitive! { read_u8, u8 }
     read_primitive! { read_u16, u16 }
     read_primitive! { read_u32, u32 }
     read_primitive! { read_u64, u64 }
-    read_primitive! { read_int, isize }
+    read_primitive! { read_isize, isize }
     read_primitive! { read_i8, i8 }
     read_primitive! { read_i16, i16 }
     read_primitive! { read_i32, i32 }
@@ -3592,7 +3592,6 @@ fn assert_stream_equal(src: &str,
         }
     }
     #[test]
-    #[cfg_attr(target_pointer_width = "32", ignore)] // FIXME(#14064)
     fn test_streaming_parser() {
         assert_stream_equal(
             r#"{ "foo":"bar", "array" : [0, 1, 2, 3, 4, 5], "idents":[null,true,false]}"#,
@@ -3631,7 +3630,6 @@ fn last_event(src: &str) -> JsonEvent {
     }
 
     #[test]
-    #[cfg_attr(target_pointer_width = "32", ignore)] // FIXME(#14064)
     fn test_read_object_streaming() {
         assert_eq!(last_event("{ "),      Error(SyntaxError(EOFWhileParsingObject, 1, 3)));
         assert_eq!(last_event("{1"),      Error(SyntaxError(KeyMustBeAString,      1, 2)));
@@ -3715,7 +3713,6 @@ fn test_read_object_streaming() {
         );
     }
     #[test]
-    #[cfg_attr(target_pointer_width = "32", ignore)] // FIXME(#14064)
     fn test_read_array_streaming() {
         assert_stream_equal(
             "[]",
index 0fcab1347d160f1cfc69bab158cbfc9672081872..b75ec5dad8ddd7088a9539288b551f886ee35c58 100644 (file)
@@ -24,12 +24,12 @@ pub trait Encoder {
 
     // Primitive types:
     fn emit_nil(&mut self) -> Result<(), Self::Error>;
-    fn emit_uint(&mut self, v: usize) -> Result<(), Self::Error>;
+    fn emit_usize(&mut self, v: usize) -> Result<(), Self::Error>;
     fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error>;
     fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error>;
     fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error>;
     fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error>;
-    fn emit_int(&mut self, v: isize) -> Result<(), Self::Error>;
+    fn emit_isize(&mut self, v: isize) -> Result<(), Self::Error>;
     fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error>;
     fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error>;
     fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error>;
@@ -108,12 +108,12 @@ pub trait Decoder {
 
     // Primitive types:
     fn read_nil(&mut self) -> Result<(), Self::Error>;
-    fn read_uint(&mut self) -> Result<usize, Self::Error>;
+    fn read_usize(&mut self) -> Result<usize, Self::Error>;
     fn read_u64(&mut self) -> Result<u64, Self::Error>;
     fn read_u32(&mut self) -> Result<u32, Self::Error>;
     fn read_u16(&mut self) -> Result<u16, Self::Error>;
     fn read_u8(&mut self) -> Result<u8, Self::Error>;
-    fn read_int(&mut self) -> Result<isize, Self::Error>;
+    fn read_isize(&mut self) -> Result<isize, Self::Error>;
     fn read_i64(&mut self) -> Result<i64, Self::Error>;
     fn read_i32(&mut self) -> Result<i32, Self::Error>;
     fn read_i16(&mut self) -> Result<i16, Self::Error>;
@@ -200,13 +200,13 @@ pub trait Decodable: Sized {
 
 impl Encodable for usize {
     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_uint(*self)
+        s.emit_usize(*self)
     }
 }
 
 impl Decodable for usize {
     fn decode<D: Decoder>(d: &mut D) -> Result<usize, D::Error> {
-        d.read_uint()
+        d.read_usize()
     }
 }
 
@@ -260,13 +260,13 @@ fn decode<D: Decoder>(d: &mut D) -> Result<u64, D::Error> {
 
 impl Encodable for isize {
     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_int(*self)
+        s.emit_isize(*self)
     }
 }
 
 impl Decodable for isize {
     fn decode<D: Decoder>(d: &mut D) -> Result<isize, D::Error> {
-        d.read_int()
+        d.read_isize()
     }
 }
 
index 0db91034eb5ac8eed231b5d28b9c3f4f9bc06347..a063b85646809f3e2c89c7b58b24bf9c0699b8c5 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use prelude::v1::*;
-
 use mem;
 use ops::Range;
+use iter::FusedIterator;
 
 /// Extension methods for ASCII-subset only operations on string slices.
 ///
@@ -368,6 +367,9 @@ fn next_back(&mut self) -> Option<u8> {
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ExactSizeIterator for EscapeDefault {}
+#[unstable(feature = "fused", issue = "35602")]
+impl FusedIterator for EscapeDefault {}
+
 
 static ASCII_LOWERCASE_MAP: [u8; 256] = [
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@@ -450,7 +452,6 @@ impl ExactSizeIterator for EscapeDefault {}
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use super::*;
     use char::from_u32;
 
index cf6f76f914a158f4cfca3f0f6c92b6c62c66e681..14da36ca4834e272dce558e8fdb2f49bbe0e44ac 100644 (file)
@@ -15,7 +15,7 @@
 use cmp::max;
 use fmt::{self, Debug};
 use hash::{Hash, Hasher, BuildHasher, SipHasher13};
-use iter::FromIterator;
+use iter::{FromIterator, FusedIterator};
 use mem::{self, replace};
 use ops::{Deref, Index};
 use rand::{self, Rng};
@@ -1484,6 +1484,9 @@ impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {
     #[inline] fn len(&self) -> usize { self.inner.len() }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Iter<'a, K, V> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> Iterator for IterMut<'a, K, V> {
     type Item = (&'a K, &'a mut V);
@@ -1495,6 +1498,8 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> {
 impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {
     #[inline] fn len(&self) -> usize { self.inner.len() }
 }
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<K, V> Iterator for IntoIter<K, V> {
@@ -1507,6 +1512,8 @@ impl<K, V> Iterator for IntoIter<K, V> {
 impl<K, V> ExactSizeIterator for IntoIter<K, V> {
     #[inline] fn len(&self) -> usize { self.inner.len() }
 }
+#[unstable(feature = "fused", issue = "35602")]
+impl<K, V> FusedIterator for IntoIter<K, V> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> Iterator for Keys<'a, K, V> {
@@ -1519,6 +1526,8 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> {
 impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> {
     #[inline] fn len(&self) -> usize { self.inner.len() }
 }
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Keys<'a, K, V> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> Iterator for Values<'a, K, V> {
@@ -1531,6 +1540,8 @@ impl<'a, K, V> Iterator for Values<'a, K, V> {
 impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {
     #[inline] fn len(&self) -> usize { self.inner.len() }
 }
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Values<'a, K, V> {}
 
 #[stable(feature = "map_values_mut", since = "1.10.0")]
 impl<'a, K, V> Iterator for ValuesMut<'a, K, V> {
@@ -1543,6 +1554,8 @@ impl<'a, K, V> Iterator for ValuesMut<'a, K, V> {
 impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> {
     #[inline] fn len(&self) -> usize { self.inner.len() }
 }
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K, V> Iterator for Drain<'a, K, V> {
@@ -1555,6 +1568,8 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> {
 impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> {
     #[inline] fn len(&self) -> usize { self.inner.len() }
 }
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Drain<'a, K, V> {}
 
 impl<'a, K, V> Entry<'a, K, V> {
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1640,13 +1655,18 @@ pub fn key(&self) -> &K {
         self.elem.read().0
     }
 
+    /// Deprecated, renamed to `remove_entry`
+    #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
+    #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")]
+    pub fn remove_pair(self) -> (K, V) {
+        self.remove_entry()
+    }
+
     /// Take the ownership of the key and value from the map.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_entry_recover_keys)]
-    ///
     /// use std::collections::HashMap;
     /// use std::collections::hash_map::Entry;
     ///
@@ -1655,13 +1675,13 @@ pub fn key(&self) -> &K {
     ///
     /// if let Entry::Occupied(o) = map.entry("poneyland") {
     ///     // We delete the entry from the map.
-    ///     o.remove_pair();
+    ///     o.remove_entry();
     /// }
     ///
     /// assert_eq!(map.contains_key("poneyland"), false);
     /// ```
-    #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
-    pub fn remove_pair(self) -> (K, V) {
+    #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")]
+    pub fn remove_entry(self) -> (K, V) {
         pop_internal(self.elem)
     }
 
@@ -1808,8 +1828,6 @@ pub fn key(&self) -> &K {
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_entry_recover_keys)]
-    ///
     /// use std::collections::HashMap;
     /// use std::collections::hash_map::Entry;
     ///
@@ -1819,7 +1837,7 @@ pub fn key(&self) -> &K {
     ///     v.into_key();
     /// }
     /// ```
-    #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
+    #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")]
     pub fn into_key(self) -> K {
         self.key
     }
@@ -2041,8 +2059,6 @@ fn drain<'new>(d: Drain<'static, &'static str, &'static str>)
 
 #[cfg(test)]
 mod test_map {
-    use prelude::v1::*;
-
     use super::HashMap;
     use super::Entry::{Occupied, Vacant};
     use cell::RefCell;
index 837c5d8b8e18cfc9fabc4a1c611dd27eacf7cfad..ca5137e957362993a3ca3adc36bf0bab3c8fb91b 100644 (file)
@@ -11,7 +11,7 @@
 use borrow::Borrow;
 use fmt;
 use hash::{Hash, BuildHasher};
-use iter::{Chain, FromIterator};
+use iter::{Chain, FromIterator, FusedIterator};
 use ops::{BitOr, BitAnd, BitXor, Sub};
 
 use super::Recover;
@@ -906,6 +906,8 @@ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
 impl<'a, K> ExactSizeIterator for Iter<'a, K> {
     fn len(&self) -> usize { self.iter.len() }
 }
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K> FusedIterator for Iter<'a, K> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<K> Iterator for IntoIter<K> {
@@ -918,6 +920,8 @@ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
 impl<K> ExactSizeIterator for IntoIter<K> {
     fn len(&self) -> usize { self.iter.len() }
 }
+#[unstable(feature = "fused", issue = "35602")]
+impl<K> FusedIterator for IntoIter<K> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, K> Iterator for Drain<'a, K> {
@@ -930,6 +934,8 @@ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
 impl<'a, K> ExactSizeIterator for Drain<'a, K> {
     fn len(&self) -> usize { self.iter.len() }
 }
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K> FusedIterator for Drain<'a, K> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Clone for Intersection<'a, T, S> {
@@ -961,6 +967,11 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T, S> FusedIterator for Intersection<'a, T, S>
+    where T: Eq + Hash, S: BuildHasher
+{}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Clone for Difference<'a, T, S> {
     fn clone(&self) -> Difference<'a, T, S> {
@@ -991,6 +1002,11 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T, S> FusedIterator for Difference<'a, T, S>
+    where T: Eq + Hash, S: BuildHasher
+{}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Clone for SymmetricDifference<'a, T, S> {
     fn clone(&self) -> SymmetricDifference<'a, T, S> {
@@ -1008,11 +1024,21 @@ fn next(&mut self) -> Option<&'a T> { self.iter.next() }
     fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S>
+    where T: Eq + Hash, S: BuildHasher
+{}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Clone for Union<'a, T, S> {
     fn clone(&self) -> Union<'a, T, S> { Union { iter: self.iter.clone() } }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T, S> FusedIterator for Union<'a, T, S>
+    where T: Eq + Hash, S: BuildHasher
+{}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T, S> Iterator for Union<'a, T, S>
     where T: Eq + Hash, S: BuildHasher
@@ -1041,8 +1067,6 @@ fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d }
 
 #[cfg(test)]
 mod test_set {
-    use prelude::v1::*;
-
     use super::HashSet;
 
     #[test]
index 02931e5e3890de5559348daaf5c4f8b814998570..8f02c9c7d3de0334ca6403101bc4fc0c525c1a26 100644 (file)
@@ -59,7 +59,7 @@
 /// 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>>`.
-#[unsafe_no_drop_flag]
+#[cfg_attr(stage0, unsafe_no_drop_flag)]
 pub struct RawTable<K, V> {
     capacity: usize,
     size: usize,
@@ -1042,7 +1042,7 @@ fn clone(&self) -> RawTable<K, V> {
 impl<K, V> Drop for RawTable<K, V> {
     #[unsafe_destructor_blind_to_params]
     fn drop(&mut self) {
-        if self.capacity == 0 || self.capacity == mem::POST_DROP_USIZE {
+        if self.capacity == 0 {
             return;
         }
 
index 753411991abeadab7cb77c8265c857a44e0891fd..9fcc3a80b98b40a6f7350c2d6dec43d41d076dc9 100644 (file)
@@ -16,8 +16,6 @@
 
 #![stable(feature = "env", since = "1.0.0")]
 
-use prelude::v1::*;
-
 use error::Error;
 use ffi::{OsStr, OsString};
 use fmt;
@@ -661,6 +659,7 @@ pub mod consts {
     /// - arm
     /// - aarch64
     /// - mips
+    /// - mips64
     /// - powerpc
     /// - powerpc64
     #[stable(feature = "env", since = "1.0.0")]
@@ -928,6 +927,11 @@ mod arch {
     pub const ARCH: &'static str = "mips";
 }
 
+#[cfg(target_arch = "mips64")]
+mod arch {
+    pub const ARCH: &'static str = "mips64";
+}
+
 #[cfg(target_arch = "powerpc")]
 mod arch {
     pub const ARCH: &'static str = "powerpc";
@@ -950,7 +954,6 @@ mod arch {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use super::*;
 
     use iter::repeat;
index 914599271aca279044667c6ff0cb572d0a7d2ce2..16290620010035f554d1f7985f0fb551b0b36de3 100644 (file)
 // reconsider what crate these items belong in.
 
 use any::TypeId;
-use boxed::Box;
 use cell;
 use char;
 use fmt::{self, Debug, Display};
-use marker::{Send, Sync, Reflect};
+use marker::Reflect;
 use mem::transmute;
 use num;
-use raw::TraitObject;
 use str;
-use string::{self, String};
+use string;
 
 /// Base functionality for all errors in Rust.
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -304,6 +302,13 @@ fn description(&self) -> &str {
     }
 }
 
+#[unstable(feature = "try_from", issue = "33417")]
+impl Error for char::CharTryFromError {
+    fn description(&self) -> &str {
+        "converted integer out of range for `char`"
+    }
+}
+
 // copied from any.rs
 impl Error + 'static {
     /// Returns true if the boxed type is the same as `T`
@@ -327,11 +332,7 @@ pub fn is<T: Error + 'static>(&self) -> bool {
     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
         if self.is::<T>() {
             unsafe {
-                // Get the raw representation of the trait object
-                let to: TraitObject = transmute(self);
-
-                // Extract the data pointer
-                Some(&*(to.data as *const T))
+                Some(&*(self as *const Error as *const T))
             }
         } else {
             None
@@ -345,11 +346,7 @@ pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
         if self.is::<T>() {
             unsafe {
-                // Get the raw representation of the trait object
-                let to: TraitObject = transmute(self);
-
-                // Extract the data pointer
-                Some(&mut *(to.data as *const T as *mut T))
+                Some(&mut *(self as *mut Error as *mut T))
             }
         } else {
             None
@@ -410,13 +407,8 @@ impl Error {
     pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Error>> {
         if self.is::<T>() {
             unsafe {
-                // Get the raw representation of the trait object
-                let raw = Box::into_raw(self);
-                let to: TraitObject =
-                    transmute::<*mut Error, TraitObject>(raw);
-
-                // Extract the data pointer
-                Ok(Box::from_raw(to.data as *mut T))
+                let raw: *mut Error = Box::into_raw(self);
+                Ok(Box::from_raw(raw as *mut T))
             }
         } else {
             Err(self)
@@ -454,7 +446,6 @@ pub fn downcast<T: Error + 'static>(self: Box<Self>)
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use super::Error;
     use fmt;
 
index 18a7c7c8457043de80004199a7f45f90322b6573..38222c014f61b165d5eec6f1f159f477a158479a 100644 (file)
@@ -9,25 +9,18 @@
 // except according to those terms.
 
 use ascii;
-use borrow::{Cow, ToOwned, Borrow};
-use boxed::Box;
-use convert::{Into, From};
-use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
+use borrow::{Cow, Borrow};
+use cmp::Ordering;
 use error::Error;
 use fmt::{self, Write};
 use io;
-use iter::Iterator;
 use libc;
 use mem;
 use memchr;
 use ops;
-use option::Option::{self, Some, None};
 use os::raw::c_char;
-use result::Result::{self, Ok, Err};
 use slice;
 use str::{self, Utf8Error};
-use string::String;
-use vec::Vec;
 
 /// A type representing an owned C-compatible string
 ///
@@ -224,6 +217,7 @@ fn _new(bytes: Vec<u8>) -> Result<CString, NulError> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString {
+        v.reserve_exact(1);
         v.push(0);
         CString { inner: v.into_boxed_slice() }
     }
@@ -699,7 +693,6 @@ fn as_ref(&self) -> &CStr {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use super::*;
     use os::raw::c_char;
     use borrow::Cow::{Borrowed, Owned};
index 0d29e62485abb8035fa3c7a404174790cc6d61c9..36cf4ef758d8e40d7d1d512d11ab7176f67d0216 100644 (file)
@@ -8,14 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use borrow::{Borrow, Cow, ToOwned};
+use borrow::{Borrow, Cow};
 use fmt::{self, Debug};
 use mem;
-use string::String;
 use ops;
 use cmp;
 use hash::{Hash, Hasher};
-use vec::Vec;
 
 use sys::os_str::{Buf, Slice};
 use sys_common::{AsInner, IntoInner, FromInner};
@@ -251,6 +249,14 @@ fn hash<H: Hasher>(&self, state: &mut H) {
 
 impl OsStr {
     /// Coerces into an `OsStr` slice.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::OsStr;
+    ///
+    /// let os_str = OsStr::new("foo");
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr {
         s.as_ref()
@@ -283,6 +289,18 @@ pub fn to_os_string(&self) -> OsString {
     }
 
     /// Checks whether the `OsStr` is empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::OsStr;
+    ///
+    /// let os_str = OsStr::new("");
+    /// assert!(os_str.is_empty());
+    ///
+    /// let os_str = OsStr::new("foo");
+    /// assert!(!os_str.is_empty());
+    /// ```
     #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
     pub fn is_empty(&self) -> bool {
         self.inner.inner.is_empty()
@@ -296,6 +314,18 @@ pub fn is_empty(&self) -> bool {
     /// other methods like `OsString::with_capacity` to avoid reallocations.
     ///
     /// See `OsStr` introduction for more information about encoding.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::OsStr;
+    ///
+    /// let os_str = OsStr::new("");
+    /// assert_eq!(os_str.len(), 0);
+    ///
+    /// let os_str = OsStr::new("foo");
+    /// assert_eq!(os_str.len(), 3);
+    /// ```
     #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
     pub fn len(&self) -> usize {
         self.inner.inner.len()
index b78db24e44b70784d202a6cff358804e88bda909..698ec4f1b7389cbc3cabddb22b34a14001400d69 100644 (file)
@@ -23,7 +23,6 @@
 use path::{Path, PathBuf};
 use sys::fs as fs_imp;
 use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner};
-use vec::Vec;
 use time::SystemTime;
 
 /// A reference to an open file on the filesystem.
@@ -1511,8 +1510,11 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
 
 /// Returns an iterator over the entries within a directory.
 ///
-/// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
-/// be encountered after an iterator is initially constructed.
+/// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`.
+/// New errors may be encountered after an iterator is initially constructed.
+///
+/// [`io::Result`]: ../io/type.Result.html
+/// [`DirEntry`]: struct.DirEntry.html
 ///
 /// # Platform-specific behavior
 ///
@@ -1677,7 +1679,6 @@ fn as_inner_mut(&mut self) -> &mut fs_imp::DirBuilder {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use io::prelude::*;
 
     use fs::{self, File, OpenOptions};
index a92ca95f4ee7ef024925b51f20879d21b14d7f96..a26a932ad2de6c076f9d3d0720ce4135802aebf1 100644 (file)
@@ -10,7 +10,6 @@
 
 //! Buffering wrappers for I/O traits
 
-use prelude::v1::*;
 use io::prelude::*;
 
 use marker::Reflect;
@@ -788,7 +787,6 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use io::prelude::*;
     use io::{self, BufReader, BufWriter, LineWriter, SeekFrom};
     use sync::atomic::{AtomicUsize, Ordering};
index 2d780559db1229b5382bdf831ec4b117f93ff43d..1b836b745372f00ed8189a6b4e2b956b1c5e5e12 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
 use io::prelude::*;
 
 use cmp;
@@ -284,7 +283,6 @@ fn flush(&mut self) -> io::Result<()> { Ok(()) }
 mod tests {
     use io::prelude::*;
     use io::{Cursor, SeekFrom};
-    use vec::Vec;
 
     #[test]
     fn test_vec_writer() {
index 5333b0a531eaebd671245e8081c71a4cb72cc028..ddf0030858eda548072670c6413dec6fdfbf5980 100644 (file)
@@ -8,12 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use boxed::Box;
-use convert::Into;
 use error;
 use fmt;
-use marker::{Send, Sync};
-use option::Option::{self, Some, None};
 use result;
 use sys;
 
@@ -83,7 +79,7 @@ struct Custom {
 /// It is used with the [`io::Error`] type.
 ///
 /// [`io::Error`]: struct.Error.html
-#[derive(Copy, PartialEq, Eq, Clone, Debug)]
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated)]
 pub enum ErrorKind {
@@ -165,7 +161,8 @@ pub enum ErrorKind {
     #[stable(feature = "read_exact", since = "1.6.0")]
     UnexpectedEof,
 
-    /// Any I/O error not part of this list.
+    /// A marker variant that tells the compiler that users of this enum cannot
+    /// match it exhaustively.
     #[unstable(feature = "io_error_internals",
                reason = "better expressed through extensible enums that this \
                          enum cannot be exhaustively matched against",
@@ -522,7 +519,6 @@ fn _is_sync_send<T: Sync+Send>() {}
 
 #[cfg(test)]
 mod test {
-    use prelude::v1::*;
     use super::{Error, ErrorKind};
     use error;
     use fmt;
index 317993815630b93fa698649c422d7ffa4eed0093..cd05e6b5de9d25262a13d6d16a943967c86bd3f5 100644 (file)
@@ -8,13 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use boxed::Box;
 use cmp;
 use io::{self, SeekFrom, Read, Write, Seek, BufRead, Error, ErrorKind};
 use fmt;
 use mem;
-use string::String;
-use vec::Vec;
 
 // =============================================================================
 // Forwarding implementations
@@ -228,7 +225,6 @@ fn flush(&mut self) -> io::Result<()> { Ok(()) }
 #[cfg(test)]
 mod tests {
     use io::prelude::*;
-    use vec::Vec;
     use test;
 
     #[bench]
index 11551601207506b331be7192d51836f5a18454a3..ce205c3b11ca5ee14542e5c208189320152d20c1 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use cell::Cell;
 use ptr;
 use sync::Arc;
index 88fd4186e0a2a73be02e98964f822de8c46c692d..1053792cd439bc4ef414f507a66973451f4ec51d 100644 (file)
 //! to read the line and print it, so we use `()`.
 //!
 //! [result]: type.Result.html
-//! [try]: ../macro.try!.html
+//! [try]: ../macro.try.html
 //!
 //! ## Platform-specific behavior
 //!
 use rustc_unicode::str as core_str;
 use error as std_error;
 use fmt;
-use iter::{Iterator};
-use marker::Sized;
-use ops::{Drop, FnOnce};
-use option::Option::{self, Some, None};
-use result::Result::{Ok, Err};
 use result;
-use string::String;
 use str;
-use vec::Vec;
 use memchr;
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -957,8 +950,8 @@ fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
     /// explicitly be called. The [`write!`][write] macro should be favored to
     /// invoke this method instead.
     ///
-    /// [formatargs]: ../macro.format_args!.html
-    /// [write]: ../macro.write!.html
+    /// [formatargs]: ../macro.format_args.html
+    /// [write]: ../macro.write.html
     ///
     /// This function internally uses the [`write_all`][writeall] method on
     /// this trait and hence will continuously write data so long as no errors
@@ -1734,7 +1727,6 @@ fn next(&mut self) -> Option<Result<String>> {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use io::prelude::*;
     use io;
     use super::Cursor;
index b8b66a58359e7013d135713767a4936c1a3d8c0d..9a782e95f6e5f994fd2cabe77cd59512a99ef90f 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
 use io::prelude::*;
 
 use cell::{RefCell, BorrowState};
index c8b52fc046769b9ca59986a6ec5e621dee8b9d6b..2c6880281b5e60088b36c6497ba747056b19fab9 100644 (file)
@@ -167,8 +167,6 @@ fn flush(&mut self) -> io::Result<()> { Ok(()) }
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
-
     use io::prelude::*;
     use io::{copy, sink, empty, repeat};
 
index c05e0c3ca68dfeea25c7ba5c56a57fd65c00fed1..44d1fbfdb70b3419ba6e7dbfcdab6b7830f58773 100644 (file)
 //! [`atomic`]: sync/atomic/index.html
 //! [`collections`]: collections/index.html
 //! [`for`]: ../book/loops.html#for
-//! [`format!`]: macro.format!.html
+//! [`format!`]: macro.format.html
 //! [`fs`]: fs/index.html
 //! [`io`]: io/index.html
 //! [`iter`]: iter/index.html
 #![feature(float_from_str_radix)]
 #![feature(fn_traits)]
 #![feature(fnbox)]
+#![feature(fused)]
 #![feature(hashmap_hasher)]
 #![feature(heap_api)]
 #![feature(inclusive_range)]
 #![feature(optin_builtin_traits)]
 #![feature(panic_unwind)]
 #![feature(placement_in_syntax)]
+#![feature(prelude_import)]
 #![feature(question_mark)]
 #![feature(rand)]
 #![feature(raw)]
 #![feature(unboxed_closures)]
 #![feature(unicode)]
 #![feature(unique)]
-#![feature(unsafe_no_drop_flag, filling_drop)]
+#![cfg_attr(stage0, feature(unsafe_no_drop_flag))]
 #![feature(unwind_attributes)]
 #![feature(vec_push_all)]
 #![feature(zero_one)]
 #![allow(unused_features)] // std may use features in a platform-specific way
 #![cfg_attr(not(stage0), deny(warnings))]
 
+#[prelude_import]
+#[allow(unused)]
+use prelude::v1::*;
+
 #[cfg(test)] extern crate test;
 
 // We want to reexport a few macros from core but libcore has already been
index a408b4378e19e6b14cdb0f68478adf628f527dc0..03f55f7ad61864cf3ed90ed794b36e41728873c0 100644 (file)
@@ -209,7 +209,7 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
         let end_align = (ptr as usize + len) & (usize_bytes - 1);
         let mut offset;
         if end_align > 0 {
-            offset = len - cmp::min(usize_bytes - end_align, len);
+            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);
             }
@@ -309,6 +309,17 @@ fn no_match_empty_reversed() {
     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..]));
+        }
+    }
 }
 
 #[cfg(test)]
@@ -385,4 +396,15 @@ fn no_match_empty_reversed() {
     fn no_match_reversed() {
         assert_eq!(None, memrchr(b'a', b"xyz"));
     }
+
+    #[test]
+    fn each_alignment() {
+        let mut data = [1u8; 64];
+        let needle = 2;
+        let pos = 40;
+        data[pos] = needle;
+        for start in 0..16 {
+            assert_eq!(Some(pos - start), memchr(needle, &data[start..]));
+        }
+    }
 }
index b93ca8277e636bb7b3b8ff1ed30cd84db1a20ef1..d0b59b42c1798a73a2ca56e75d553849ea5a9672 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use fmt;
 use hash;
 use io;
@@ -523,7 +521,6 @@ fn to_socket_addrs(&self) -> io::Result<T::Iter> {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use net::*;
     use net::test::{tsa, sa6, sa4};
 
index 2a8bd0c88beb6f535d2a53d81b839d3eb9cab951..c6a7a77e68a6b369c4cfd06f33e1cb67d7a95d1a 100644 (file)
@@ -63,8 +63,7 @@ impl IpAddr {
     /// Returns true for the special 'unspecified' address ([IPv4], [IPv6]).
     /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified
     /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified
-    #[unstable(feature="ip", issue="27709",
-               reason="recently added and depends on unstable Ipv4Addr.is_unspecified()")]
+    #[stable(feature = "ip_shared", since = "1.12.0")]
     pub fn is_unspecified(&self) -> bool {
         match *self {
             IpAddr::V4(ref a) => a.is_unspecified(),
@@ -75,7 +74,7 @@ pub fn is_unspecified(&self) -> bool {
     /// Returns true if this is a loopback address ([IPv4], [IPv6]).
     /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback
     /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback
-    #[unstable(feature="ip", reason="recently added", issue="27709")]
+    #[stable(feature = "ip_shared", since = "1.12.0")]
     pub fn is_loopback(&self) -> bool {
         match *self {
             IpAddr::V4(ref a) => a.is_loopback(),
@@ -86,8 +85,6 @@ pub fn is_loopback(&self) -> bool {
     /// Returns true if the address appears to be globally routable ([IPv4], [IPv6]).
     /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global
     /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global
-    #[unstable(feature="ip", issue="27709",
-               reason="recently added and depends on unstable Ip{v4,v6}Addr.is_global()")]
     pub fn is_global(&self) -> bool {
         match *self {
             IpAddr::V4(ref a) => a.is_global(),
@@ -98,7 +95,7 @@ pub fn is_global(&self) -> bool {
     /// Returns true if this is a multicast address ([IPv4], [IPv6]).
     /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast
     /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast
-    #[unstable(feature="ip", reason="recently added", issue="27709")]
+    #[stable(feature = "ip_shared", since = "1.12.0")]
     pub fn is_multicast(&self) -> bool {
         match *self {
             IpAddr::V4(ref a) => a.is_multicast(),
@@ -109,8 +106,6 @@ pub fn is_multicast(&self) -> bool {
     /// Returns true if this address is in a range designated for documentation ([IPv4], [IPv6]).
     /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation
     /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation
-    #[unstable(feature="ip", issue="27709",
-               reason="recently added and depends on unstable Ipv6Addr.is_documentation()")]
     pub fn is_documentation(&self) -> bool {
         match *self {
             IpAddr::V4(ref a) => a.is_documentation(),
@@ -147,6 +142,7 @@ pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
     /// This property is defined in _UNIX Network Programming, Second Edition_,
     /// W. Richard Stevens, p. 891; see also [ip7]
     /// [ip7][http://man7.org/linux/man-pages/man7/ip.7.html]
+    #[stable(feature = "ip_shared", since = "1.12.0")]
     pub fn is_unspecified(&self) -> bool {
         self.inner.s_addr == 0
     }
@@ -515,8 +511,7 @@ pub fn to_ipv4(&self) -> Option<Ipv4Addr> {
     }
 
     /// Returns the sixteen eight-bit integers the IPv6 address consists of.
-    #[unstable(feature = "ipv6_to_octets", reason = "needs some testing",
-               issue = "32313")]
+    #[stable(feature = "ipv6_to_octets", since = "1.12.0")]
     pub fn octets(&self) -> [u8; 16] {
         self.inner.s6_addr
     }
@@ -658,7 +653,6 @@ fn from_inner(addr: c::in6_addr) -> Ipv6Addr {
 // Tests for this module
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use net::*;
     use net::Ipv6MulticastScope::*;
     use net::test::{tsa, sa6, sa4};
index 11a16b271133be76cbc9ca1c386588a43b091ae6..2a78afa85f7f03ff9ce7cbe7b3ffa59c307ee6fd 100644 (file)
@@ -12,8 +12,6 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use prelude::v1::*;
-
 use io::{self, Error, ErrorKind};
 use sys_common::net as net_imp;
 
index 5851ce7135d2745c08faf78a6c990029db2fdbba..854d87c4cbead7114f36996d18db46c8bf1c4bf9 100644 (file)
@@ -13,8 +13,6 @@
 //! This module is "publicly exported" through the `FromStr` implementations
 //! below.
 
-use prelude::v1::*;
-
 use error::Error;
 use fmt;
 use net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
index 76617f159707dd2233da5ce8ab72b247bf05b84e..3c5f07c3e33a6db25ef7fd9f033d9f3825d080be 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
 use io::prelude::*;
 
 use fmt;
@@ -46,7 +45,6 @@
 ///
 /// ```no_run
 /// use std::net::{TcpListener, TcpStream};
-/// use std::thread;
 ///
 /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
 ///
 /// for stream in listener.incoming() {
 ///     match stream {
 ///         Ok(stream) => {
-///             thread::spawn(move|| {
-///                 // connection succeeded
-///                 handle_client(stream)
-///             });
+///             handle_client(stream);
 ///         }
 ///         Err(e) => { /* connection failed */ }
 ///     }
 /// }
-///
-/// // close the socket server
-/// drop(listener);
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct TcpListener(net_imp::TcpListener);
@@ -438,8 +430,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
-
     use io::ErrorKind;
     use io::prelude::*;
     use net::*;
index 9665fd722872fc54891d84a11e211fd194cc5741..98ac61f6461132d94f320d11ba31b7bb516803c4 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use env;
 use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
 use sync::atomic::{AtomicUsize, Ordering};
index 9d0279deb1bcb2bfc33ae32e4a8158c8cdb9d73a..781f026c12c7795e1b2c82fae0506c5b40d8b566 100644 (file)
@@ -355,8 +355,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
-
     use io::ErrorKind;
     use net::*;
     use net::test::{next_test_ip4, next_test_ip6};
index 20804d62dfab663401f07293496b3c4d1066973d..d1c2fc3d3fce9371a3584bf88f07f120834f139c 100644 (file)
@@ -24,9 +24,7 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::num::Wrapping;
 
-#[cfg(test)] use cmp::PartialEq;
 #[cfg(test)] use fmt;
-#[cfg(test)] use marker::Copy;
 #[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem};
 
 /// Helper function for testing numeric operations
@@ -52,7 +50,6 @@ mod tests {
     use u32;
     use u64;
     use usize;
-    use string::ToString;
     use ops::Mul;
 
     #[test]
@@ -287,7 +284,6 @@ fn test_uint_from_str_overflow() {
 mod bench {
     extern crate test;
     use self::test::Bencher;
-    use prelude::v1::*;
 
     #[bench]
     fn bench_pow_function(b: &mut Bencher) {
index 1be76961fea9efdfb9c04080ddbeb7422e306359..0f62877500b2c0831bb1851da283233e82c4b5e7 100644 (file)
@@ -155,6 +155,11 @@ pub struct stat {
     }
 }
 
+#[cfg(target_arch = "mips64")]
+mod arch {
+    pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
+}
+
 #[cfg(target_arch = "aarch64")]
 mod arch {
     use os::raw::{c_long, c_int};
index 2f67081e0d71093c29625a4de7c292112cca4dad..47f594a9b0c1efe0494e15098d8848f89433a164 100644 (file)
@@ -13,7 +13,6 @@
 #![stable(feature = "std_panic", since = "1.9.0")]
 
 use any::Any;
-use boxed::Box;
 use cell::UnsafeCell;
 use ops::{Deref, DerefMut};
 use panicking;
index 5961fd59699c1b8d0a92341e6c78f69729f0b648..0c10dcbdad6463c613cacaf6d378b5f37c132823 100644 (file)
@@ -17,7 +17,6 @@
 //! * Executing a panic up to doing the actual implementation
 //! * Shims around "try"
 
-use prelude::v1::*;
 use io::prelude::*;
 
 use any::Any;
index 2d19561139b58144d12df7dc4c37f838199a1505..9a5b1da0f08f4122f3b6b7b8613eaf822dcce50b 100644 (file)
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use ascii::*;
-use borrow::{Borrow, ToOwned, Cow};
+use borrow::{Borrow, Cow};
 use cmp;
 use error::Error;
 use fmt;
 use fs;
 use hash::{Hash, Hasher};
 use io;
-use iter;
+use iter::{self, FusedIterator};
 use mem;
 use ops::{self, Deref};
-use string::String;
-use vec::Vec;
 
 use ffi::{OsStr, OsString};
 
@@ -641,6 +639,25 @@ pub struct Iter<'a> {
     inner: Components<'a>,
 }
 
+#[stable(feature = "path_components_debug", since = "1.13.0")]
+impl<'a> fmt::Debug for Components<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        struct DebugHelper<'a>(&'a Path);
+
+        impl<'a> fmt::Debug for DebugHelper<'a> {
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                f.debug_list()
+                    .entries(self.0.components())
+                    .finish()
+            }
+        }
+
+        f.debug_tuple("Components")
+            .field(&DebugHelper(self.as_path()))
+            .finish()
+    }
+}
+
 impl<'a> Components<'a> {
     // how long is the prefix, if any?
     #[inline]
@@ -820,6 +837,25 @@ fn as_ref(&self) -> &OsStr {
     }
 }
 
+#[stable(feature = "path_iter_debug", since = "1.13.0")]
+impl<'a> fmt::Debug for Iter<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        struct DebugHelper<'a>(&'a Path);
+
+        impl<'a> fmt::Debug for DebugHelper<'a> {
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                f.debug_list()
+                    .entries(self.0.iter())
+                    .finish()
+            }
+        }
+
+        f.debug_tuple("Iter")
+            .field(&DebugHelper(self.as_path()))
+            .finish()
+    }
+}
+
 impl<'a> Iter<'a> {
     /// Extracts a slice corresponding to the portion of the path remaining for iteration.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -858,6 +894,9 @@ fn next_back(&mut self) -> Option<&'a OsStr> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for Iter<'a> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> Iterator for Components<'a> {
     type Item = Component<'a>;
@@ -958,6 +997,9 @@ fn next_back(&mut self) -> Option<Component<'a>> {
     }
 }
 
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for Components<'a> {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> cmp::PartialEq for Components<'a> {
     fn eq(&self, other: &Components<'a>) -> bool {
@@ -986,11 +1028,16 @@ fn cmp(&self, other: &Components<'a>) -> cmp::Ordering {
 // Basic types and traits
 ////////////////////////////////////////////////////////////////////////////////
 
-/// An owned, mutable path (akin to `String`).
+/// An owned, mutable path (akin to [`String`]).
+///
+/// This type provides methods like [`push`] and [`set_extension`] that mutate
+/// the path in place. It also implements [`Deref`] to [`Path`], meaning that
+/// all methods on [`Path`] slices are available on `PathBuf` values as well.
 ///
-/// This type provides methods like `push` and `set_extension` that mutate the
-/// path in place. It also implements `Deref` to `Path`, meaning that all
-/// methods on `Path` slices are available on `PathBuf` values as well.
+/// [`String`]: ../string/struct.String.html
+/// [`Path`]: struct.Path.html
+/// [`push`]: struct.PathBuf.html#method.push
+/// [`set_extension`]: struct.PathBuf.html#method.set_extension
 ///
 /// More details about the overall approach can be found in
 /// the module documentation.
@@ -1017,12 +1064,31 @@ fn as_mut_vec(&mut self) -> &mut Vec<u8> {
     }
 
     /// Allocates an empty `PathBuf`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::path::PathBuf;
+    ///
+    /// let path = PathBuf::new();
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new() -> PathBuf {
         PathBuf { inner: OsString::new() }
     }
 
-    /// Coerces to a `Path` slice.
+    /// Coerces to a [`Path`] slice.
+    ///
+    /// [`Path`]: struct.Path.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::path::{Path, PathBuf};
+    ///
+    /// let p = PathBuf::from("/test");
+    /// assert_eq!(Path::new("/test"), p.as_path());
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn as_path(&self) -> &Path {
         self
@@ -1087,10 +1153,26 @@ fn _push(&mut self, path: &Path) {
         self.inner.push(path);
     }
 
-    /// Truncate `self` to `self.parent()`.
+    /// Truncate `self` to [`self.parent()`].
     ///
-    /// Returns false and does nothing if `self.file_name()` is `None`.
+    /// Returns false and does nothing if [`self.file_name()`] is `None`.
     /// Otherwise, returns `true`.
+    ///
+    /// [`self.parent()`]: struct.PathBuf.html#method.parent
+    /// [`self.file_name()`]: struct.PathBuf.html#method.file_name
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::path::{Path, PathBuf};
+    ///
+    /// let mut p = PathBuf::from("/test/test.rs");
+    ///
+    /// p.pop();
+    /// assert_eq!(Path::new("/test"), p.as_path());
+    /// p.pop();
+    /// assert_eq!(Path::new("/"), p.as_path());
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn pop(&mut self) -> bool {
         match self.parent().map(|p| p.as_u8_slice().len()) {
@@ -1102,11 +1184,13 @@ pub fn pop(&mut self) -> bool {
         }
     }
 
-    /// Updates `self.file_name()` to `file_name`.
+    /// Updates [`self.file_name()`] to `file_name`.
     ///
-    /// If `self.file_name()` was `None`, this is equivalent to pushing
+    /// If [`self.file_name()`] was `None`, this is equivalent to pushing
     /// `file_name`.
     ///
+    /// [`self.file_name()`]: struct.PathBuf.html#method.file_name
+    ///
     /// # Examples
     ///
     /// ```
@@ -1133,12 +1217,29 @@ fn _set_file_name(&mut self, file_name: &OsStr) {
         self.push(file_name);
     }
 
-    /// Updates `self.extension()` to `extension`.
+    /// Updates [`self.extension()`] to `extension`.
+    ///
+    /// If [`self.file_name()`] is `None`, does nothing and returns `false`.
+    ///
+    /// Otherwise, returns `true`; if [`self.extension()`] is `None`, the
+    /// extension is added; otherwise it is replaced.
     ///
-    /// If `self.file_name()` is `None`, does nothing and returns `false`.
+    /// [`self.file_name()`]: struct.PathBuf.html#method.file_name
+    /// [`self.extension()`]: struct.PathBuf.html#method.extension
     ///
-    /// Otherwise, returns `true`; if `self.extension()` is `None`, the extension
-    /// is added; otherwise it is replaced.
+    /// # Examples
+    ///
+    /// ```
+    /// use std::path::{Path, PathBuf};
+    ///
+    /// let mut p = PathBuf::from("/feel/the");
+    ///
+    /// p.set_extension("force");
+    /// assert_eq!(Path::new("/feel/the.force"), p.as_path());
+    ///
+    /// p.set_extension("dark_side");
+    /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path());
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
         self._set_extension(extension.as_ref())
@@ -1163,7 +1264,18 @@ fn _set_extension(&mut self, extension: &OsStr) -> bool {
         true
     }
 
-    /// Consumes the `PathBuf`, yielding its internal `OsString` storage.
+    /// Consumes the `PathBuf`, yielding its internal [`OsString`] storage.
+    ///
+    /// [`OsString`]: ../ffi/struct.OsString.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::path::PathBuf;
+    ///
+    /// let p = PathBuf::from("/the/head");
+    /// let os_str = p.into_os_string();
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn into_os_string(self) -> OsString {
         self.inner
@@ -1301,7 +1413,7 @@ fn into(self) -> OsString {
     }
 }
 
-/// A slice of a path (akin to `str`).
+/// A slice of a path (akin to [`str`]).
 ///
 /// This type supports a number of operations for inspecting a path, including
 /// breaking the path into its components (separated by `/` or `\`, depending on
@@ -1310,7 +1422,10 @@ fn into(self) -> OsString {
 /// the module documentation.
 ///
 /// This is an *unsized* type, meaning that it must always be used behind a
-/// pointer like `&` or `Box`.
+/// pointer like `&` or [`Box`].
+///
+/// [`str`]: ../primitive.str.html
+/// [`Box`]: ../boxed/struct.Box.html
 ///
 /// # Examples
 ///
@@ -1372,7 +1487,9 @@ pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
         unsafe { mem::transmute(s.as_ref()) }
     }
 
-    /// Yields the underlying `OsStr` slice.
+    /// Yields the underlying [`OsStr`] slice.
+    ///
+    /// [`OsStr`]: ../ffi/struct.OsStr.html
     ///
     /// # Examples
     ///
@@ -1387,10 +1504,12 @@ pub fn as_os_str(&self) -> &OsStr {
         &self.inner
     }
 
-    /// Yields a `&str` slice if the `Path` is valid unicode.
+    /// Yields a [`&str`] slice if the `Path` is valid unicode.
     ///
     /// This conversion may entail doing a check for UTF-8 validity.
     ///
+    /// [`&str`]: ../primitive.str.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -1404,10 +1523,12 @@ pub fn to_str(&self) -> Option<&str> {
         self.inner.to_str()
     }
 
-    /// Converts a `Path` to a `Cow<str>`.
+    /// Converts a `Path` to a [`Cow<str>`].
     ///
     /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER.
     ///
+    /// [`Cow<str>`]: ../borrow/enum.Cow.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -1421,7 +1542,9 @@ pub fn to_string_lossy(&self) -> Cow<str> {
         self.inner.to_string_lossy()
     }
 
-    /// Converts a `Path` to an owned `PathBuf`.
+    /// Converts a `Path` to an owned [`PathBuf`].
+    ///
+    /// [`PathBuf`]: struct.PathBuf.html
     ///
     /// # Examples
     ///
@@ -1569,6 +1692,18 @@ pub fn file_name(&self) -> Option<&OsStr> {
     ///
     /// If `base` is not a prefix of `self` (i.e. `starts_with`
     /// returns `false`), returns `Err`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::path::Path;
+    ///
+    /// let path = Path::new("/test/haha/foo.txt");
+    ///
+    /// assert_eq!(path.strip_prefix("/test"), Ok(Path::new("haha/foo.txt")));
+    /// assert_eq!(path.strip_prefix("test").is_ok(), false);
+    /// assert_eq!(path.strip_prefix("/haha").is_ok(), false);
+    /// ```
     #[stable(since = "1.7.0", feature = "path_strip_prefix")]
     pub fn strip_prefix<'a, P: ?Sized>(&'a self, base: &'a P)
                                        -> Result<&'a Path, StripPrefixError>
@@ -1630,7 +1765,9 @@ fn _ends_with(&self, child: &Path) -> bool {
         iter_after(self.components().rev(), child.components().rev()).is_some()
     }
 
-    /// Extracts the stem (non-extension) portion of `self.file_name()`.
+    /// Extracts the stem (non-extension) portion of [`self.file_name()`].
+    ///
+    /// [`self.file_name()`]: struct.Path.html#method.file_name
     ///
     /// The stem is:
     ///
@@ -1653,7 +1790,9 @@ pub fn file_stem(&self) -> Option<&OsStr> {
         self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after))
     }
 
-    /// Extracts the extension of `self.file_name()`, if possible.
+    /// Extracts the extension of [`self.file_name()`], if possible.
+    ///
+    /// [`self.file_name()`]: struct.Path.html#method.file_name
     ///
     /// The extension is:
     ///
@@ -1676,9 +1815,12 @@ pub fn extension(&self) -> Option<&OsStr> {
         self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.and(after))
     }
 
-    /// Creates an owned `PathBuf` with `path` adjoined to `self`.
+    /// Creates an owned [`PathBuf`] with `path` adjoined to `self`.
+    ///
+    /// See [`PathBuf::push`] for more details on what it means to adjoin a path.
     ///
-    /// See `PathBuf::push` for more details on what it means to adjoin a path.
+    /// [`PathBuf`]: struct.PathBuf.html
+    /// [`PathBuf::push`]: struct.PathBuf.html#method.push
     ///
     /// # Examples
     ///
@@ -1698,9 +1840,12 @@ fn _join(&self, path: &Path) -> PathBuf {
         buf
     }
 
-    /// Creates an owned `PathBuf` like `self` but with the given file name.
+    /// Creates an owned [`PathBuf`] like `self` but with the given file name.
+    ///
+    /// See [`PathBuf::set_file_name`] for more details.
     ///
-    /// See `PathBuf::set_file_name` for more details.
+    /// [`PathBuf`]: struct.PathBuf.html
+    /// [`PathBuf::set_file_name`]: struct.PathBuf.html#method.set_file_name
     ///
     /// # Examples
     ///
@@ -1721,9 +1866,12 @@ fn _with_file_name(&self, file_name: &OsStr) -> PathBuf {
         buf
     }
 
-    /// Creates an owned `PathBuf` like `self` but with the given extension.
+    /// Creates an owned [`PathBuf`] like `self` but with the given extension.
     ///
-    /// See `PathBuf::set_extension` for more details.
+    /// See [`PathBuf::set_extension`] for more details.
+    ///
+    /// [`PathBuf`]: struct.PathBuf.html
+    /// [`PathBuf::set_extension`]: struct.PathBuf.html#method.set_extension
     ///
     /// # Examples
     ///
@@ -1771,7 +1919,9 @@ pub fn components(&self) -> Components {
         }
     }
 
-    /// Produce an iterator over the path's components viewed as `OsStr` slices.
+    /// Produce an iterator over the path's components viewed as [`OsStr`] slices.
+    ///
+    /// [`OsStr`]: ../ffi/struct.OsStr.html
     ///
     /// # Examples
     ///
@@ -1790,9 +1940,11 @@ pub fn iter(&self) -> Iter {
         Iter { inner: self.components() }
     }
 
-    /// Returns an object that implements `Display` for safely printing paths
+    /// Returns an object that implements [`Display`] for safely printing paths
     /// that may contain non-Unicode data.
     ///
+    /// [`Display`]: ../fmt/trait.Display.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -1854,11 +2006,13 @@ pub fn read_link(&self) -> io::Result<PathBuf> {
 
     /// Returns an iterator over the entries within a directory.
     ///
-    /// The iterator will yield instances of `io::Result<DirEntry>`. New errors may
-    /// be encountered after an iterator is initially constructed.
+    /// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. New
+    /// errors may be encountered after an iterator is initially constructed.
     ///
     /// This is an alias to [`fs::read_dir`].
     ///
+    /// [`io::Result`]: ../io/type.Result.html
+    /// [`DirEntry`]: ../fs/struct.DirEntry.html
     /// [`fs::read_dir`]: ../fs/fn.read_dir.html
     #[stable(feature = "path_ext", since = "1.5.0")]
     pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
@@ -2146,8 +2300,6 @@ fn description(&self) -> &str { "prefix not found" }
 #[cfg(test)]
 mod tests {
     use super::*;
-    use string::{ToString, String};
-    use vec::Vec;
 
     macro_rules! t(
         ($path:expr, iter: $iter:expr) => (
@@ -3481,4 +3633,47 @@ macro_rules! tc(
                 );
         }
     }
+
+    #[test]
+    fn test_components_debug() {
+        let path = Path::new("/tmp");
+
+        let mut components = path.components();
+
+        let expected = "Components([RootDir, Normal(\"tmp\")])";
+        let actual = format!("{:?}", components);
+        assert_eq!(expected, actual);
+
+        let _ = components.next().unwrap();
+        let expected = "Components([Normal(\"tmp\")])";
+        let actual = format!("{:?}", components);
+        assert_eq!(expected, actual);
+
+        let _ = components.next().unwrap();
+        let expected = "Components([])";
+        let actual = format!("{:?}", components);
+        assert_eq!(expected, actual);
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn test_iter_debug() {
+        let path = Path::new("/tmp");
+
+        let mut iter = path.iter();
+
+        let expected = "Iter([\"/\", \"tmp\"])";
+        let actual = format!("{:?}", iter);
+        assert_eq!(expected, actual);
+
+        let _ = iter.next().unwrap();
+        let expected = "Iter([\"tmp\"])";
+        let actual = format!("{:?}", iter);
+        assert_eq!(expected, actual);
+
+        let _ = iter.next().unwrap();
+        let expected = "Iter([])";
+        let actual = format!("{:?}", iter);
+        assert_eq!(expected, actual);
+    }
 }
index d31a593037622f7c6ad8692f94f9402b5413c2d6..2b92da6c684a43f2e5680000520583964b7d2bff 100644 (file)
@@ -27,7 +27,7 @@
 /// assert!(!bool_val);
 /// ```
 ///
-/// [`assert!`]: macro.assert!.html
+/// [`assert!`]: macro.assert.html
 /// [`if`]: ../book/if.html
 /// [`BitAnd`]: ops/trait.BitAnd.html
 /// [`BitOr`]: ops/trait.BitOr.html
index 660c098d30bc29d157bfb8888ae6e145482aa152..f0c4443070074aa3318f11605b11ba8abebf8b97 100644 (file)
@@ -12,7 +12,6 @@
 
 #![stable(feature = "process", since = "1.0.0")]
 
-use prelude::v1::*;
 use io::prelude::*;
 
 use ffi::OsStr;
@@ -810,7 +809,6 @@ pub fn exit(code: i32) -> ! {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use io::prelude::*;
 
     use io::ErrorKind;
index a3d9e4db7d19a4b0927b5e30356b813c412438d7..e3de1efaa31e3051457741b68523d92c37a3ea53 100644 (file)
@@ -30,7 +30,6 @@
 #[cfg(not(test))]
 #[lang = "start"]
 fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
-    use borrow::ToOwned;
     use mem;
     use panic;
     use sys;
index b1267acdee61a177fdd9b9fa8a077d613d58efab..ac0f400379e3cabf3504a10b496426774e2c0659 100644 (file)
@@ -113,8 +113,6 @@ pub fn is_leader(&self) -> bool { self.0 }
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
-
     use sync::{Arc, Barrier};
     use sync::mpsc::{channel, TryRecvError};
     use thread;
index 3c52ebc72f2cb279f187dbfdd1a1c15af580eebe..4c946e613ea91eda9008891c9a19eaa990aab63c 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use sync::atomic::{AtomicUsize, Ordering};
 use sync::{mutex, MutexGuard, PoisonError};
 use sys_common::condvar as sys;
@@ -82,10 +80,14 @@ impl Condvar {
     /// notified.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new() -> Condvar {
-        Condvar {
+        let mut c = Condvar {
             inner: box sys::Condvar::new(),
             mutex: AtomicUsize::new(0),
+        };
+        unsafe {
+            c.inner.init();
         }
+        c
     }
 
     /// Blocks the current thread until this condition variable receives a
@@ -140,6 +142,10 @@ pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>)
     /// differences that may not cause the maximum amount of time
     /// waited to be precisely `ms`.
     ///
+    /// Note that the best effort is made to ensure that the time waited is
+    /// measured with a monotonic clock, and not affected by the changes made to
+    /// the system time.
+    ///
     /// The returned boolean is `false` only if the timeout is known
     /// to have elapsed.
     ///
@@ -164,6 +170,10 @@ pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32)
     /// preemption or platform differences that may not cause the maximum
     /// amount of time waited to be precisely `dur`.
     ///
+    /// Note that the best effort is made to ensure that the time waited is
+    /// measured with a monotonic clock, and not affected by the changes made to
+    /// the system time.
+    ///
     /// The returned `WaitTimeoutResult` value indicates if the timeout is
     /// known to have elapsed.
     ///
@@ -245,8 +255,6 @@ fn drop(&mut self) {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
-
     use sync::mpsc::channel;
     use sync::{Condvar, Mutex, Arc};
     use thread;
index 4a70de0e7d8fccf7bba8b7de64fc53339c1e5ef2..0f9ef6fabb005eb06f6f5fb307fed95c38b6a300 100644 (file)
@@ -13,9 +13,7 @@
 use thread::{self, Thread};
 use sync::atomic::{AtomicBool, Ordering};
 use sync::Arc;
-use marker::{Sync, Send};
 use mem;
-use clone::Clone;
 use time::Instant;
 
 struct Inner {
index 11f785dffd16a6b1f67cc0f5e542c02aa23c937a..3d9f81413dc734202b1e8a6df174ed35703b2d2b 100644 (file)
@@ -394,13 +394,15 @@ pub enum TryRecvError {
 /// This enumeration is the list of possible errors that `recv_timeout` could
 /// not return data when called.
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
-#[unstable(feature = "mpsc_recv_timeout", issue = "34029")]
+#[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
 pub enum RecvTimeoutError {
     /// This channel is currently empty, but the sender(s) have not yet
     /// disconnected, so data may yet become available.
+    #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
     Timeout,
     /// This channel's sending half has become disconnected, and there will
     /// never be any more data received on this channel
+    #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
     Disconnected,
 }
 
@@ -912,8 +914,6 @@ pub fn recv(&self) -> Result<T, RecvError> {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(mpsc_recv_timeout)]
-    ///
     /// use std::sync::mpsc::{self, RecvTimeoutError};
     /// use std::time::Duration;
     ///
@@ -922,7 +922,7 @@ pub fn recv(&self) -> Result<T, RecvError> {
     /// let timeout = Duration::from_millis(100);
     /// assert_eq!(Err(RecvTimeoutError::Timeout), recv.recv_timeout(timeout));
     /// ```
-    #[unstable(feature = "mpsc_recv_timeout", issue = "34029")]
+    #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
     pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError> {
         // Do an optimistic try_recv to avoid the performance impact of
         // Instant::now() in the full-channel case.
@@ -1270,8 +1270,6 @@ fn cause(&self) -> Option<&error::Error> {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
-
     use env;
     use super::*;
     use thread;
@@ -1946,8 +1944,6 @@ fn destroy_upgraded_shared_port_when_sender_still_active() {
 
 #[cfg(test)]
 mod sync_tests {
-    use prelude::v1::*;
-
     use env;
     use thread;
     use super::*;
index 6a6c19cfcc308662bd09240da247fa93a3ef11cf..d926043fbbcd074e37fae9807f07b6a34cbfcce8 100644 (file)
@@ -148,8 +148,6 @@ fn drop(&mut self) {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
-
     use sync::mpsc::channel;
     use super::{Queue, Data, Empty, Inconsistent};
     use sync::Arc;
index 5aa4ce81b8ae43c53c4b9ecf8a19fcae72230106..677544d335e7a6d21df49c81402042a5a85374fc 100644 (file)
@@ -369,8 +369,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 #[cfg(test)]
 #[allow(unused_imports)]
 mod tests {
-    use prelude::v1::*;
-
     use thread;
     use sync::mpsc::*;
 
index 02506e7c2f3d91f7bf173e8e5da5949dec27d4ad..724d7b1be730d59953620950ffa5ca20f55b5172 100644 (file)
@@ -233,8 +233,6 @@ fn drop(&mut self) {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
-
     use sync::Arc;
     use super::Queue;
     use thread;
index 9d13a71ff95ee29098873374f2e50ec7a9274a38..9985daaba8f69a2eac4772cf2c91e11517b0f077 100644 (file)
@@ -36,7 +36,6 @@
 pub use self::Failure::*;
 use self::Blocker::*;
 
-use vec::Vec;
 use core::mem;
 use core::ptr;
 
index 6bc458397f1632282a8946cff69c45d1214e31de..c8ae88c233106461b12dd1f161c1c4af738d1244 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use cell::UnsafeCell;
 use fmt;
 use marker;
@@ -355,8 +353,6 @@ pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Fla
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
-
     use sync::mpsc::channel;
     use sync::{Arc, Mutex, Condvar};
     use sync::atomic::{AtomicUsize, Ordering};
index 54c1fe6c5640cebcb7312d0ad67fe8233c316b92..86d2986959c999abee5e10c3761f16f4fa0253fc 100644 (file)
@@ -369,8 +369,6 @@ pub fn poisoned(&self) -> bool {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
-
     use panic;
     use sync::mpsc::channel;
     use thread;
index 65b5686de869ca7fb05f9369a3435753612d5a35..4801bcffd081c69751c652c42e316229acb79a9f 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use cell::UnsafeCell;
 use fmt;
 use marker;
@@ -385,8 +383,6 @@ fn drop(&mut self) {
 mod tests {
     #![allow(deprecated)] // rand
 
-    use prelude::v1::*;
-
     use rand::{self, Rng};
     use sync::mpsc::channel;
     use thread;
@@ -552,8 +548,6 @@ fn test_rwlock_unsized() {
 
     #[test]
     fn test_rwlock_try_write() {
-        use mem::drop;
-
         let lock = RwLock::new(0isize);
         let read_guard = lock.read().unwrap();
 
index e877391fb8b5629283419cfe5fb6b4fbf9dff82f..fad2c277da417f8f27fa1fe9687e2d949d2929d9 100644 (file)
@@ -21,8 +21,6 @@
 
 #![allow(dead_code)] // different code on OSX/linux/etc
 
-use vec::Vec;
-
 /// One-time global initialization.
 pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
 
@@ -42,8 +40,6 @@ pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
           target_os = "solaris",
           target_os = "emscripten"))]
 mod imp {
-    use prelude::v1::*;
-
     use libc::c_char;
     use mem;
     use ffi::CStr;
@@ -91,8 +87,6 @@ fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
           target_os = "ios",
           target_os = "windows"))]
 mod imp {
-    use vec::Vec;
-
     pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
     }
 
index b2683750d67e2d8c4481103e45ecc2e04bbf0449..ce6fd4cb0754b1cc9297b4a97394b08aebc1356c 100644 (file)
 //! Documentation can be found on the `rt::at_exit` function.
 
 use alloc::boxed::FnBox;
-use boxed::Box;
 use ptr;
 use sys_common::mutex::Mutex;
-use vec::Vec;
 
 type Queue = Vec<Box<FnBox()>>;
 
index 4c23ceb63f287bd4a7c9c5efbc344404ed435d98..a509b80eaca9143eb33bc218b2efbce111637cb2 100644 (file)
@@ -137,10 +137,21 @@ pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> {
             let i: usize = inner[.. (inner.len() - rest.len())].parse().unwrap();
             inner = &rest[i..];
             rest = &rest[..i];
+            if rest.starts_with("_$") {
+                rest = &rest[1..];
+            }
             while !rest.is_empty() {
-                if rest.starts_with("$") {
+                if rest.starts_with(".") {
+                    if let Some('.') = rest[1..].chars().next() {
+                        writer.write_all(b"::")?;
+                        rest = &rest[2..];
+                    } else {
+                        writer.write_all(b".")?;
+                        rest = &rest[1..];
+                    }
+                } else if rest.starts_with("$") {
                     macro_rules! demangle {
-                        ($($pat:expr, => $demangled:expr),*) => ({
+                        ($($pat:expr => $demangled:expr),*) => ({
                             $(if rest.starts_with($pat) {
                                 try!(writer.write_all($demangled));
                                 rest = &rest[$pat.len()..];
@@ -155,29 +166,32 @@ macro_rules! demangle {
 
                     // see src/librustc/back/link.rs for these mappings
                     demangle! (
-                        "$SP$", => b"@",
-                        "$BP$", => b"*",
-                        "$RF$", => b"&",
-                        "$LT$", => b"<",
-                        "$GT$", => b">",
-                        "$LP$", => b"(",
-                        "$RP$", => b")",
-                        "$C$", => b",",
+                        "$SP$" => b"@",
+                        "$BP$" => b"*",
+                        "$RF$" => b"&",
+                        "$LT$" => b"<",
+                        "$GT$" => b">",
+                        "$LP$" => b"(",
+                        "$RP$" => b")",
+                        "$C$" => b",",
 
                         // in theory we can demangle any Unicode code point, but
                         // for simplicity we just catch the common ones.
-                        "$u7e$", => b"~",
-                        "$u20$", => b" ",
-                        "$u27$", => b"'",
-                        "$u5b$", => b"[",
-                        "$u5d$", => b"]",
-                        "$u7b$", => b"{",
-                        "$u7d$", => b"}"
+                        "$u7e$" => b"~",
+                        "$u20$" => b" ",
+                        "$u27$" => b"'",
+                        "$u5b$" => b"[",
+                        "$u5d$" => b"]",
+                        "$u7b$" => b"{",
+                        "$u7d$" => b"}",
+                        "$u3b$" => b";",
+                        "$u2b$" => b"+",
+                        "$u22$" => b"\""
                     )
                 } else {
-                    let idx = match rest.find('$') {
+                    let idx = match rest.char_indices().find(|&(_, c)| c == '$' || c == '.') {
                         None => rest.len(),
-                        Some(i) => i,
+                        Some((i, _)) => i,
                     };
                     writer.write_all(rest[..idx].as_bytes())?;
                     rest = &rest[idx..];
@@ -191,7 +205,6 @@ macro_rules! demangle {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use sys_common;
     macro_rules! t { ($a:expr, $b:expr) => ({
         let mut m = Vec::new();
@@ -213,6 +226,7 @@ fn demangle_dollars() {
         t!("_ZN8$RF$testE", "&test");
         t!("_ZN8$BP$test4foobE", "*test::foob");
         t!("_ZN9$u20$test4foobE", " test::foob");
+        t!("_ZN35Bar$LT$$u5b$u32$u3b$$u20$4$u5d$$GT$E", "Bar<[u32; 4]>");
     }
 
     #[test]
@@ -227,4 +241,17 @@ fn demangle_windows() {
         t!("ZN13test$u20$test4foobE", "test test::foob");
         t!("ZN12test$RF$test4foobE", "test&test::foob");
     }
+
+    #[test]
+    fn demangle_elements_beginning_with_underscore() {
+        t!("_ZN13_$LT$test$GT$E", "<test>");
+        t!("_ZN28_$u7b$$u7b$closure$u7d$$u7d$E", "{{closure}}");
+        t!("_ZN15__STATIC_FMTSTRE", "__STATIC_FMTSTR");
+    }
+
+    #[test]
+    fn demangle_trait_impls() {
+        t!("_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE",
+           "<Test + 'static as foo::Bar<Test>>::bar");
+    }
 }
index 33734a88cf32b18467beae65149f94a01b6fc3b9..b6f29dd5fc3d3184f6a528fcb36f70b64b3f1051 100644 (file)
@@ -27,6 +27,13 @@ impl Condvar {
     /// first used with any of the functions below.
     pub const fn new() -> Condvar { Condvar(imp::Condvar::new()) }
 
+    /// Prepares the condition variable for use.
+    ///
+    /// This should be called once the condition variable is at a stable memory
+    /// address.
+    #[inline]
+    pub unsafe fn init(&mut self) { self.0.init() }
+
     /// Signals one waiter on this condition variable to wake up.
     #[inline]
     pub unsafe fn notify_one(&self) { self.0.notify_one() }
index 7b08852ba51d1fbfa8fa5d451bffcd6f851204df..3cd70eddb858c1d0f8566855ff2fb0aca5fa478c 100644 (file)
@@ -7,7 +7,6 @@
 // <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 prelude::v1::*;
 use io;
 use io::ErrorKind;
 use io::Read;
@@ -53,7 +52,6 @@ pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io::
 
 #[cfg(test)]
 pub mod test {
-    use prelude::v1::*;
     use path::{Path, PathBuf};
     use env;
     use rand::{self, Rng};
@@ -93,7 +91,6 @@ pub fn tmpdir() -> TempDir {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use io::prelude::*;
     use super::*;
     use io;
index a1f3f477b3ab7dfa4f64eadac9847bc8568d4f92..d1ca676510714d1548ae005c08fc4e10d523f90f 100644 (file)
@@ -10,7 +10,6 @@
 
 #![allow(missing_docs)]
 
-use boxed::Box;
 use sync::Once;
 use sys;
 
index 7a2183c522f5b92154b198e55aea3cdc4455a5f4..d1a738770d3893fb66189c036009fd62375984db 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use marker::Sync;
 use sys::mutex as imp;
 
 /// An OS-based mutual exclusion lock.
index 442618c55b337f5dc157db2e81893ff8e481e496..a777cfe35e56d4125a9a565584ae96ebc1fca11a 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use cmp;
 use ffi::CString;
 use fmt;
@@ -608,8 +606,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
-
     use super::*;
     use collections::HashMap;
 
index 39d4104246732f56d0333aa58aa8ddada075284d..cbdeaad7f6bd3acfbff16c2cb7fa25ab688f904a 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use fmt;
 use marker;
 use ops::Deref;
@@ -160,7 +158,6 @@ fn drop(&mut self) {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
     use cell::RefCell;
     use sync::Arc;
index 16f4f01bf39fe9b058fb03817dac3821dd480b19..3ee160da5fa5b7876ab1a2c957b77c9cc3aa75f8 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use alloc::boxed::FnBox;
 use libc;
 use sys::stack_overflow;
index 0467c67167bd518d85d7a9fd2c419e17a404e4d3..95d8b6cc9516d2e3e5573863d9287ed65d70e105 100644 (file)
@@ -11,7 +11,6 @@
 #![allow(dead_code)] // stack_guard isn't used right now on all platforms
 
 use cell::RefCell;
-use string::String;
 use thread::Thread;
 use thread::LocalKeyState;
 
index 56885cdd56d99a348a75228e287e64ee3038079b..25a9d5720d9338bfb14ed8dba43bd03edaf36362 100644 (file)
@@ -233,7 +233,6 @@ fn drop(&mut self) {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use super::{Key, StaticKey};
 
     fn assert_sync<T: Sync>() {}
index c1b4f8a8c88c501d9dc174c8f7186001a9f37b15..8d357aa78c9e93568b91f508ea373052a523b58d 100644 (file)
@@ -37,9 +37,7 @@
 use ops;
 use slice;
 use str;
-use string::String;
 use sys_common::AsInner;
-use vec::Vec;
 
 const UTF8_REPLACEMENT_CHARACTER: &'static [u8] = b"\xEF\xBF\xBD";
 
@@ -807,7 +805,6 @@ fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() }
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use borrow::Cow;
     use super::*;
 
index 2e1c1900b46b3147aa565321a14bce1068676465..27b9f131d120b114cf66e41801d23ec185f028c5 100644 (file)
 
 use cell::UnsafeCell;
 use libc;
-use ptr;
 use sys::mutex::{self, Mutex};
-use time::{Instant, Duration};
+use time::Duration;
 
 pub struct Condvar { inner: UnsafeCell<libc::pthread_cond_t> }
 
 unsafe impl Send for Condvar {}
 unsafe impl Sync for Condvar {}
 
+const TIMESPEC_MAX: libc::timespec = libc::timespec {
+    tv_sec: <libc::time_t>::max_value(),
+    tv_nsec: 1_000_000_000 - 1,
+};
+
 impl Condvar {
     pub const fn new() -> Condvar {
         // Might be moved and address is changing it is better to avoid
@@ -26,6 +30,23 @@ pub const fn new() -> Condvar {
         Condvar { inner: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER) }
     }
 
+    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))]
+    pub unsafe fn init(&mut self) {}
+
+    #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))]
+    pub unsafe fn init(&mut self) {
+        use mem;
+        let mut attr: libc::pthread_condattr_t = mem::uninitialized();
+        let r = libc::pthread_condattr_init(&mut attr);
+        assert_eq!(r, 0);
+        let r = libc::pthread_condattr_setclock(&mut attr, libc::CLOCK_MONOTONIC);
+        assert_eq!(r, 0);
+        let r = libc::pthread_cond_init(self.inner.get(), &attr);
+        assert_eq!(r, 0);
+        let r = libc::pthread_condattr_destroy(&mut attr);
+        assert_eq!(r, 0);
+    }
+
     #[inline]
     pub unsafe fn notify_one(&self) {
         let r = libc::pthread_cond_signal(self.inner.get());
@@ -44,10 +65,45 @@ pub unsafe fn wait(&self, mutex: &Mutex) {
         debug_assert_eq!(r, 0);
     }
 
+    // This implementation is used on systems that support pthread_condattr_setclock
+    // where we configure condition variable to use monotonic clock (instead of
+    // default system clock). This approach avoids all problems that result
+    // from changes made to the system time.
+    #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))]
+    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+        use mem;
+
+        let mut now: libc::timespec = mem::zeroed();
+        let r = libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now);
+        assert_eq!(r, 0);
+
+        // Nanosecond calculations can't overflow because both values are below 1e9.
+        let nsec = dur.subsec_nanos() as libc::c_long + now.tv_nsec as libc::c_long;
+        // FIXME: Casting u64 into time_t could truncate the value.
+        let sec = (dur.as_secs() as libc::time_t)
+            .checked_add((nsec / 1_000_000_000) as libc::time_t)
+            .and_then(|s| s.checked_add(now.tv_sec));
+        let nsec = nsec % 1_000_000_000;
+
+        let timeout = sec.map(|s| {
+            libc::timespec { tv_sec: s, tv_nsec: nsec }
+        }).unwrap_or(TIMESPEC_MAX);
+
+        let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex),
+                                            &timeout);
+        assert!(r == libc::ETIMEDOUT || r == 0);
+        r == 0
+    }
+
+
     // This implementation is modeled after libcxx's condition_variable
     // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46
     // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367
+    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))]
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+        use ptr;
+        use time::Instant;
+
         // First, figure out what time it currently is, in both system and
         // stable time.  pthread_cond_timedwait uses system time, but we want to
         // report timeout based on stable time.
@@ -66,12 +122,7 @@ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
             s.checked_add(seconds)
         }).map(|s| {
             libc::timespec { tv_sec: s, tv_nsec: nsec }
-        }).unwrap_or_else(|| {
-            libc::timespec {
-                tv_sec: <libc::time_t>::max_value(),
-                tv_nsec: 1_000_000_000 - 1,
-            }
-        });
+        }).unwrap_or(TIMESPEC_MAX);
 
         // And wait!
         let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex),
index 825e74cabdebb6b3c4264ad247ed90741fcf8c9a..d59b4fc0b70b8032a961d9123da86e7b5c2276ac 100644 (file)
@@ -14,7 +14,6 @@
 
 use ffi::{OsStr, OsString};
 use mem;
-use prelude::v1::*;
 use sys::os_str::Buf;
 use sys_common::{FromInner, IntoInner, AsInner};
 
index a4564b9543b3430cdd810b87ecf5c5bf65b434c2..3f93fce1935611f236f611d3eb5ed9652617d851 100644 (file)
@@ -14,7 +14,6 @@
 
 use libc;
 
-use prelude::v1::*;
 use ascii;
 use ffi::OsStr;
 use fmt;
@@ -789,7 +788,6 @@ fn into_raw_fd(self) -> RawFd {
 
 #[cfg(test)]
 mod test {
-    use prelude::v1::*;
     use thread;
     use io;
     use io::prelude::*;
index 430ec5f94a6f85da5a0444ddfa0e73b4f52d9f33..5bd92f2eb574d7a85281000626fb72bcd1baf99c 100644 (file)
@@ -12,8 +12,6 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use prelude::v1::*;
-
 use io;
 use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
 use process;
@@ -114,7 +112,7 @@ fn exec(&mut self) -> io::Error {
 pub trait ExitStatusExt {
     /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
     /// a process.
-    #[unstable(feature = "exit_status_from", issue = "32713")]
+    #[stable(feature = "exit_status_from", since = "1.12.0")]
     fn from_raw(raw: i32) -> Self;
 
     /// If the process was terminated by a signal, returns that signal.
index b99f4a2eacde563d489fa690b06bbb19fea50f35..b2b1f16f20a9aed7b5542f283718aa43b6f34fe0 100644 (file)
@@ -10,8 +10,6 @@
 
 #![unstable(reason = "not public", issue = "0", feature = "fd")]
 
-use prelude::v1::*;
-
 use io::{self, Read};
 use libc::{self, c_int, size_t, c_void};
 use mem;
index 3b132744f7055ce176e0f0689aca601b53a454c6..e6fe3eb112a6093ea038044132736d8bdb5ef40e 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
 use os::unix::prelude::*;
 
 use ffi::{CString, CStr, OsString, OsStr};
@@ -534,7 +533,6 @@ impl fmt::Debug for File {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         #[cfg(target_os = "linux")]
         fn get_path(fd: c_int) -> Option<PathBuf> {
-            use string::ToString;
             let mut p = PathBuf::from("/proc/self/fd");
             p.push(&fd.to_string());
             readlink(&p).ok()
index 6f1b70acb60bc35c3c9f5dfc0cc60c71403bcf76..3f77abd7f44d8f4f56be637a66781da946f300a6 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use ffi::CStr;
 use io;
 use libc::{self, c_int, size_t, sockaddr, socklen_t};
index c29e87f91c9a7e247471f2c4749e3264e663d572..e61804efd50f6882d5f6e698e935bd8163f5b569 100644 (file)
@@ -12,7 +12,6 @@
 
 #![allow(unused_imports)] // lots of cfg code here
 
-use prelude::v1::*;
 use os::unix::prelude::*;
 
 use error::Error as StdError;
index d5eea5d1f3be563887c6545c818cae8f372e1663..5a733c0cb87637f7a235782b0bc3a415d60c4aca 100644 (file)
@@ -13,9 +13,7 @@
 
 use borrow::Cow;
 use fmt::{self, Debug};
-use vec::Vec;
 use str;
-use string::String;
 use mem;
 use sys_common::{AsInner, IntoInner};
 
index 010594133387a4602261369cf4b0e89cfb81e642..ffe8032e46055e9f6af9e63491e26d463117a4ab 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use cmp;
 use io;
 use libc::{self, c_int};
index d68867fb3d2ce9d164466ef0a1164a1f8fb008c9..50014f51f6cf46420fbaaa2a3e2e68db15933f3e 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
 use os::unix::prelude::*;
 
 use collections::hash_map::{HashMap, Entry};
@@ -593,7 +592,6 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use prelude::v1::*;
 
     use ffi::OsStr;
     use mem;
index 25a7a3ce50dc431a7d22c5cfd215d0c25de29f82..e4ca8344ee2873d31ce9c10c8e8dae16594c66ac 100644 (file)
 
 pub use self::imp::OsRng;
 
-#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))]
+use mem;
+
+fn next_u32(mut fill_buf: &mut FnMut(&mut [u8])) -> u32 {
+    let mut buf: [u8; 4] = [0; 4];
+    fill_buf(&mut buf);
+    unsafe { mem::transmute::<[u8; 4], u32>(buf) }
+}
+
+fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 {
+    let mut buf: [u8; 8] = [0; 8];
+    fill_buf(&mut buf);
+    unsafe { mem::transmute::<[u8; 8], u64>(buf) }
+}
+
+#[cfg(all(unix,
+          not(target_os = "ios"),
+          not(target_os = "openbsd"),
+          not(target_os = "freebsd")))]
 mod imp {
     use self::OsRngInner::*;
+    use super::{next_u32, next_u64};
 
     use fs::File;
     use io;
     use libc;
-    use mem;
     use rand::Rng;
     use rand::reader::ReaderRng;
     use sys::os::errno;
@@ -87,18 +104,6 @@ fn getrandom_fill_bytes(v: &mut [u8]) {
         }
     }
 
-    fn getrandom_next_u32() -> u32 {
-        let mut buf: [u8; 4] = [0; 4];
-        getrandom_fill_bytes(&mut buf);
-        unsafe { mem::transmute::<[u8; 4], u32>(buf) }
-    }
-
-    fn getrandom_next_u64() -> u64 {
-        let mut buf: [u8; 8] = [0; 8];
-        getrandom_fill_bytes(&mut buf);
-        unsafe { mem::transmute::<[u8; 8], u64>(buf) }
-    }
-
     #[cfg(all(target_os = "linux",
               any(target_arch = "x86_64",
                   target_arch = "x86",
@@ -163,13 +168,13 @@ pub fn new() -> io::Result<OsRng> {
     impl Rng for OsRng {
         fn next_u32(&mut self) -> u32 {
             match self.inner {
-                OsGetrandomRng => getrandom_next_u32(),
+                OsGetrandomRng => next_u32(&mut getrandom_fill_bytes),
                 OsReaderRng(ref mut rng) => rng.next_u32(),
             }
         }
         fn next_u64(&mut self) -> u64 {
             match self.inner {
-                OsGetrandomRng => getrandom_next_u64(),
+                OsGetrandomRng => next_u64(&mut getrandom_fill_bytes),
                 OsReaderRng(ref mut rng) => rng.next_u64(),
             }
         }
@@ -184,9 +189,10 @@ fn fill_bytes(&mut self, v: &mut [u8]) {
 
 #[cfg(target_os = "openbsd")]
 mod imp {
+    use super::{next_u32, next_u64};
+
     use io;
     use libc;
-    use mem;
     use sys::os::errno;
     use rand::Rng;
 
@@ -205,14 +211,10 @@ pub fn new() -> io::Result<OsRng> {
 
     impl Rng for OsRng {
         fn next_u32(&mut self) -> u32 {
-            let mut v = [0; 4];
-            self.fill_bytes(&mut v);
-            unsafe { mem::transmute(v) }
+            next_u32(&mut |v| self.fill_bytes(v))
         }
         fn next_u64(&mut self) -> u64 {
-            let mut v = [0; 8];
-            self.fill_bytes(&mut v);
-            unsafe { mem::transmute(v) }
+            next_u64(&mut |v| self.fill_bytes(v))
         }
         fn fill_bytes(&mut self, v: &mut [u8]) {
             // getentropy(2) permits a maximum buffer size of 256 bytes
@@ -230,8 +232,9 @@ fn fill_bytes(&mut self, v: &mut [u8]) {
 
 #[cfg(target_os = "ios")]
 mod imp {
+    use super::{next_u32, next_u64};
+
     use io;
-    use mem;
     use ptr;
     use rand::Rng;
     use libc::{c_int, size_t};
@@ -265,14 +268,10 @@ pub fn new() -> io::Result<OsRng> {
 
     impl Rng for OsRng {
         fn next_u32(&mut self) -> u32 {
-            let mut v = [0; 4];
-            self.fill_bytes(&mut v);
-            unsafe { mem::transmute(v) }
+            next_u32(&mut |v| self.fill_bytes(v))
         }
         fn next_u64(&mut self) -> u64 {
-            let mut v = [0; 8];
-            self.fill_bytes(&mut v);
-            unsafe { mem::transmute(v) }
+            next_u64(&mut |v| self.fill_bytes(v))
         }
         fn fill_bytes(&mut self, v: &mut [u8]) {
             let ret = unsafe {
@@ -286,3 +285,51 @@ fn fill_bytes(&mut self, v: &mut [u8]) {
         }
     }
 }
+
+#[cfg(target_os = "freebsd")]
+mod imp {
+    use super::{next_u32, next_u64};
+
+    use io;
+    use libc;
+    use rand::Rng;
+    use ptr;
+
+    pub struct OsRng {
+        // dummy field to ensure that this struct cannot be constructed outside
+        // of this module
+        _dummy: (),
+    }
+
+    impl OsRng {
+        /// Create a new `OsRng`.
+        pub fn new() -> io::Result<OsRng> {
+            Ok(OsRng { _dummy: () })
+        }
+    }
+
+    impl Rng for OsRng {
+        fn next_u32(&mut self) -> u32 {
+            next_u32(&mut |v| self.fill_bytes(v))
+        }
+        fn next_u64(&mut self) -> u64 {
+            next_u64(&mut |v| self.fill_bytes(v))
+        }
+        fn fill_bytes(&mut self, v: &mut [u8]) {
+            let mib = [libc::CTL_KERN, libc::KERN_ARND];
+            // kern.arandom permits a maximum buffer size of 256 bytes
+            for s in v.chunks_mut(256) {
+                let mut s_len = s.len();
+                let ret = unsafe {
+                    libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
+                                 s.as_mut_ptr() as *mut _, &mut s_len,
+                                 ptr::null(), 0)
+                };
+                if ret == -1 || s_len != s.len() {
+                    panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
+                           ret, s.len(), s_len);
+                }
+            }
+        }
+    }
+}
index 08aeb5fb8ccdeae96abf30a8569e9824dfc34856..c754d5b8359a9cc5b80beae763013b0443653fdd 100644 (file)
@@ -45,10 +45,10 @@ pub unsafe fn read(&self) {
         // We roughly maintain the deadlocking behavior by panicking to ensure
         // that this lock acquisition does not succeed.
         //
-        // We also check whether there this lock is already write locked. This
+        // We also check whether this lock is already write locked. This
         // is only possible if it was write locked by the current thread and
         // the implementation allows recursive locking. The POSIX standard
-        // doesn't require recursivly locking a rwlock to deadlock, but we can't
+        // doesn't require recursively locking a rwlock to deadlock, but we can't
         // allow that because it could lead to aliasing issues.
         if r == libc::EAGAIN {
             panic!("rwlock maximum reader count exceeded");
index 37d1d9a969ed8d7a435a0fdf4b9818938348a1cf..972bdbc38186b06eab0373222b9b492e41e1d137 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use io;
 use libc;
 use sys::fd::FileDesc;
index 75e10d2585308cecb85d17e374fff32c0842509f..5db7086e42752b1387227bba79c10a30818b70aa 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use alloc::boxed::FnBox;
 use cmp;
 use ffi::CStr;
@@ -193,8 +191,6 @@ pub unsafe fn init() -> Option<usize> { None }
           target_os = "solaris"))]
 #[cfg_attr(test, allow(dead_code))]
 pub mod guard {
-    use prelude::v1::*;
-
     use libc;
     use libc::mmap;
     use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
index acbfacce8bd7f073e165ded5210a39e94f016825..cd42b7d05ee384d4ec7b9b918d2c5def938b9420 100644 (file)
@@ -21,8 +21,6 @@
 //! manner we pay a semi-large one-time cost up front for detecting whether a
 //! function is available but afterwards it's just a load and a jump.
 
-use prelude::v1::*;
-
 use ffi::CString;
 use sync::atomic::{AtomicUsize, Ordering};
 use sys::c;
index 8075374d42bdda788504fe95a8e405d6e30da33c..d708b327c55cb3e687a689e75d89235f93da004e 100644 (file)
@@ -24,6 +24,9 @@ pub const fn new() -> Condvar {
         Condvar { inner: UnsafeCell::new(c::CONDITION_VARIABLE_INIT) }
     }
 
+    #[inline]
+    pub unsafe fn init(&mut self) {}
+
     #[inline]
     pub unsafe fn wait(&self, mutex: &Mutex) {
         let r = c::SleepConditionVariableSRW(self.inner.get(),
index dde13ec8364b63533fd4421046f49a485cea1c06..5227280808f5bdfa9fba3bfd056a2840b8e32b6e 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
 use os::windows::prelude::*;
 
 use ffi::{CString, OsStr};
index 56c6a73d4f82b768760c058e88ae44ebae40c7ea..98166bf8cda09d9bcf7d8ac38788bd09d5c37bb8 100644 (file)
@@ -83,10 +83,11 @@ fn into_raw_handle(self) -> RawHandle {
 }
 
 /// Windows-specific extensions to `std::process::ExitStatus`
-#[unstable(feature = "exit_status_from", issue = "32713")]
+#[stable(feature = "exit_status_from", since = "1.12.0")]
 pub trait ExitStatusExt {
     /// Creates a new `ExitStatus` from the raw underlying `u32` return value of
     /// a process.
+    #[stable(feature = "exit_status_from", since = "1.12.0")]
     fn from_raw(raw: u32) -> Self;
 }
 
index 4e6cef9a28d8f32147d5db051c5e95c2f5469a69..fe448cdd78feb9ee71ad2ff6011b06622e1ed36c 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
 use os::windows::prelude::*;
 
 use ffi::OsString;
index d10abae2865271dadfc6af7a3c1f3fa62cd41da9..97e746ee345763cc75e3723c5fbfb6f0d7a4deb5 100644 (file)
@@ -10,8 +10,6 @@
 
 #![unstable(issue = "0", feature = "windows_handle")]
 
-use prelude::v1::*;
-
 use cmp;
 use io::{ErrorKind, Read};
 use io;
index 12219c1e9d42bf750717bdb1c8f16b169c17d1e7..9741a704e8fe51e1ab5667157fe37be52b3cac07 100644 (file)
@@ -10,8 +10,6 @@
 
 #![allow(missing_docs, bad_style)]
 
-use prelude::v1::*;
-
 use ffi::{OsStr, OsString};
 use io::{self, ErrorKind};
 use os::windows::ffi::{OsStrExt, OsStringExt};
index 8762b34e3da484df7fbf49854f4ac57f754a8a1d..855603685905958de4bf5494a677bc4bc23e4497 100644 (file)
@@ -29,8 +29,6 @@
 //! CriticalSection is used and we keep track of who's holding the mutex to
 //! detect recursive locks.
 
-use prelude::v1::*;
-
 use cell::UnsafeCell;
 use mem;
 use sync::atomic::{AtomicUsize, Ordering};
index 71e164f012f1f7c4dfe9cba2ef212660414da296..aca6994503ff8aa46495e32747fda5c7c1e8a127 100644 (file)
@@ -10,8 +10,6 @@
 
 #![unstable(issue = "0", feature = "windows_net")]
 
-use prelude::v1::*;
-
 use cmp;
 use io::{self, Read};
 use libc::{c_int, c_void, c_ulong};
index 0cea7f81e363237fa745023505916db18df864fc..260fc3c4db62ef8371929b95cdcb36e1b1754930 100644 (file)
@@ -12,7 +12,6 @@
 
 #![allow(bad_style)]
 
-use prelude::v1::*;
 use os::windows::prelude::*;
 
 use error::Error as StdError;
index 26767a1349e6fc12a121fbef639843292333ba1d..a065c7a7fd013e3f4f1e7a2f4fd95583d6c63271 100644 (file)
@@ -14,9 +14,6 @@
 use borrow::Cow;
 use fmt::{self, Debug};
 use sys_common::wtf8::{Wtf8, Wtf8Buf};
-use string::String;
-use result::Result;
-use option::Option;
 use mem;
 use sys_common::{AsInner, IntoInner};
 
index 6e9c67051a6eb3559c17a3d2d813df4b685816df..ed7e88e72cd5609d69fa296ab0e811bd733db231 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
 use os::windows::prelude::*;
 
 use ffi::OsStr;
index 3ca75cf3643769e977e2802df9f1377ce951d22e..d371714ff0e690822d7af30d78cf9948224c5ba9 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use ascii::*;
 use collections::HashMap;
 use collections;
@@ -491,7 +489,6 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
     use ffi::{OsStr, OsString};
     use super::make_command_line;
 
index fa3cab2191edde5ba25924ef0a838e235b6aae75..01249f05f620252134d8c53d5a4c7ea1edca267a 100644 (file)
@@ -10,7 +10,6 @@
 
 #![unstable(issue = "0", feature = "windows_stdio")]
 
-use prelude::v1::*;
 use io::prelude::*;
 
 use cmp;
index 0383e92c79ec7b24a2c1d0c8ff4575e404c4ac1a..5a376a867ee6448288bac2cd1c534a7bb56e77a9 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use alloc::boxed::FnBox;
 use io;
 use ffi::CStr;
index 59da74b728797cdc20457187c77ed379222575e9..5d3084094fbddd4f02b375b724303fd8734ac157 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::v1::*;
-
 use ptr;
 use sys::c;
 use sys_common::mutex::Mutex;
index 152b9771086b80c7a32017eab810b14a0a152a96..c44dee49f14a69373eed7cbcf6952358b701f8e5 100644 (file)
@@ -369,7 +369,6 @@ unsafe fn register_dtor(&self) {
     // Due to rust-lang/rust#18804, make sure this is not generic!
     #[cfg(target_os = "linux")]
     unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
-        use prelude::v1::*;
         use mem;
         use libc;
         use sys_common::thread_local as os;
@@ -460,8 +459,6 @@ fn _tlv_atexit(dtor: unsafe extern fn(*mut u8),
 
 #[doc(hidden)]
 pub mod os {
-    use prelude::v1::*;
-
     use cell::{Cell, UnsafeCell};
     use marker;
     use ptr;
@@ -529,8 +526,6 @@ pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
-
     use sync::mpsc::{channel, Sender};
     use cell::{Cell, UnsafeCell};
     use super::LocalKeyState;
@@ -693,8 +688,6 @@ fn drop(&mut self) {
 
 #[cfg(test)]
 mod dynamic_tests {
-    use prelude::v1::*;
-
     use cell::RefCell;
     use collections::HashMap;
 
index f06c105d30e6500eee11e92e8f8c73ecdd4c07ff..e3f3f9dd6de1e8ce5513a22de6de15a417999211 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use prelude::v1::*;
-
 use any::Any;
 use cell::UnsafeCell;
 use ffi::{CStr, CString};
@@ -322,6 +320,24 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T> where
 }
 
 /// Gets a handle to the thread that invokes it.
+///
+/// #Examples
+///
+/// Getting a handle to the current thread with `thread::current()`:
+///
+/// ```
+/// use std::thread;
+///
+/// let handler = thread::Builder::new()
+///     .name("named thread".into())
+///     .spawn(|| {
+///         let handle = thread::current();
+///         assert_eq!(handle.name(), Some("named thread"));
+///     })
+///     .unwrap();
+///
+/// handler.join().unwrap();
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn current() -> Thread {
     thread_info::current_thread().expect("use of std::thread::current() is not \
@@ -732,8 +748,6 @@ fn _assert_both<T: Send + Sync>() {}
 
 #[cfg(test)]
 mod tests {
-    use prelude::v1::*;
-
     use any::Any;
     use sync::mpsc::{channel, Sender};
     use result;
@@ -786,8 +800,6 @@ fn test_join_panic() {
 
     #[test]
     fn test_spawn_sched() {
-        use clone::Clone;
-
         let (tx, rx) = channel();
 
         fn f(i: i32, tx: Sender<()>) {
index c959e2108f5a7ce09869c2b1b6adc6bb7ce9f35e..64a71133a8c0235aadf0a94f68be2e45288630b8 100644 (file)
@@ -39,6 +39,7 @@ pub enum Abi {
     Vectorcall,
     Aapcs,
     Win64,
+    SysV64,
 
     // Multiplatform ABIs second
     Rust,
@@ -86,6 +87,7 @@ pub enum AbiArchitecture {
     AbiData {abi: Abi::Vectorcall, name: "vectorcall"},
     AbiData {abi: Abi::Aapcs, name: "aapcs" },
     AbiData {abi: Abi::Win64, name: "win64" },
+    AbiData {abi: Abi::SysV64, name: "sysv64" },
 
     // Cross-platform ABIs
     //
index f8a5cb0b04a8e8bcab9f759e780b0fd9dab19d80..fcb99444957c4aaddf75cbd5fb930b1c641e7b97 100644 (file)
@@ -336,7 +336,7 @@ pub struct TyParam {
     pub id: NodeId,
     pub bounds: TyParamBounds,
     pub default: Option<P<Ty>>,
-    pub span: Span
+    pub span: Span,
 }
 
 /// Represents lifetimes and type parameters attached to a declaration
@@ -346,6 +346,7 @@ pub struct Generics {
     pub lifetimes: Vec<LifetimeDef>,
     pub ty_params: P<[TyParam]>,
     pub where_clause: WhereClause,
+    pub span: Span,
 }
 
 impl Generics {
@@ -368,7 +369,8 @@ fn default() ->  Generics {
             where_clause: WhereClause {
                 id: DUMMY_NODE_ID,
                 predicates: Vec::new(),
-            }
+            },
+            span: DUMMY_SP,
         }
     }
 }
@@ -439,6 +441,22 @@ pub struct Crate {
     pub exported_macros: Vec<MacroDef>,
 }
 
+/// A spanned compile-time attribute list item.
+pub type NestedMetaItem = Spanned<NestedMetaItemKind>;
+
+/// Possible values inside of compile-time attribute lists.
+///
+/// E.g. the '..' in `#[name(..)]`.
+#[derive(Clone, Eq, RustcEncodable, RustcDecodable, Hash, Debug, PartialEq)]
+pub enum NestedMetaItemKind {
+    /// A full MetaItem, for recursive meta items.
+    MetaItem(P<MetaItem>),
+    /// A literal.
+    ///
+    /// E.g. "foo", 64, true
+    Literal(Lit),
+}
+
 /// A spanned compile-time attribute item.
 ///
 /// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
@@ -456,7 +474,7 @@ pub enum MetaItemKind {
     /// List meta item.
     ///
     /// E.g. `derive(..)` as in `#[derive(..)]`
-    List(InternedString, Vec<P<MetaItem>>),
+    List(InternedString, Vec<NestedMetaItem>),
     /// Name value meta item.
     ///
     /// E.g. `feature = "foo"` as in `#[feature = "foo"]`
@@ -472,19 +490,21 @@ fn eq(&self, other: &MetaItemKind) -> bool {
                 Word(ref no) => (*ns) == (*no),
                 _ => false
             },
+            List(ref ns, ref miss) => match *other {
+                List(ref no, ref miso) => {
+                    ns == no &&
+                        miss.iter().all(|mi| {
+                            miso.iter().any(|x| x.node == mi.node)
+                        })
+                }
+                _ => false
+            },
             NameValue(ref ns, ref vs) => match *other {
                 NameValue(ref no, ref vo) => {
                     (*ns) == (*no) && vs.node == vo.node
                 }
                 _ => false
             },
-            List(ref ns, ref miss) => match *other {
-                List(ref no, ref miso) => {
-                    ns == no &&
-                        miss.iter().all(|mi| miso.iter().any(|x| x.node == mi.node))
-                }
-                _ => false
-            }
         }
     }
 }
@@ -1105,6 +1125,30 @@ pub fn is_str(&self) -> bool {
             _ => false,
         }
     }
+
+    /// Returns true if this literal has no suffix. Note: this will return true
+    /// for literals with prefixes such as raw strings and byte strings.
+    pub fn is_unsuffixed(&self) -> bool {
+        match *self {
+            // unsuffixed variants
+            LitKind::Str(..) => true,
+            LitKind::ByteStr(..) => true,
+            LitKind::Byte(..) => true,
+            LitKind::Char(..) => true,
+            LitKind::Int(_, LitIntType::Unsuffixed) => true,
+            LitKind::FloatUnsuffixed(..) => true,
+            LitKind::Bool(..) => true,
+            // suffixed variants
+            LitKind::Int(_, LitIntType::Signed(..)) => false,
+            LitKind::Int(_, LitIntType::Unsigned(..)) => false,
+            LitKind::Float(..) => false,
+        }
+    }
+
+    /// Returns true if this literal has a suffix.
+    pub fn is_suffixed(&self) -> bool {
+        !self.is_unsuffixed()
+    }
 }
 
 // NB: If you change this, you'll probably want to change the corresponding
@@ -1120,7 +1164,7 @@ pub struct MutTy {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct MethodSig {
     pub unsafety: Unsafety,
-    pub constness: Constness,
+    pub constness: Spanned<Constness>,
     pub abi: Abi,
     pub decl: P<FnDecl>,
     pub generics: Generics,
@@ -1624,42 +1668,14 @@ pub struct Variant_ {
 pub type Variant = Spanned<Variant_>;
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum PathListItemKind {
-    Ident {
-        name: Ident,
-        /// renamed in list, e.g. `use foo::{bar as baz};`
-        rename: Option<Ident>,
-        id: NodeId
-    },
-    Mod {
-        /// renamed in list, e.g. `use foo::{self as baz};`
-        rename: Option<Ident>,
-        id: NodeId
-    }
-}
-
-impl PathListItemKind {
-    pub fn id(&self) -> NodeId {
-        match *self {
-            PathListItemKind::Ident { id, .. } | PathListItemKind::Mod { id, .. } => id
-        }
-    }
-
-    pub fn name(&self) -> Option<Ident> {
-        match *self {
-            PathListItemKind::Ident { name, .. } => Some(name),
-            PathListItemKind::Mod { .. } => None,
-        }
-    }
-
-    pub fn rename(&self) -> Option<Ident> {
-        match *self {
-            PathListItemKind::Ident { rename, .. } | PathListItemKind::Mod { rename, .. } => rename
-        }
-    }
+pub struct PathListItem_ {
+    pub name: Ident,
+    /// renamed in list, e.g. `use foo::{bar as baz};`
+    pub rename: Option<Ident>,
+    pub id: NodeId,
 }
 
-pub type PathListItem = Spanned<PathListItemKind>;
+pub type PathListItem = Spanned<PathListItem_>;
 
 pub type ViewPath = Spanned<ViewPath_>;
 
@@ -1846,7 +1862,7 @@ pub enum ItemKind {
     /// A function declaration (`fn` or `pub fn`).
     ///
     /// E.g. `fn foo(bar: usize) -> usize { .. }`
-    Fn(P<FnDecl>, Unsafety, Constness, Abi, Generics, P<Block>),
+    Fn(P<FnDecl>, Unsafety, Spanned<Constness>, Abi, Generics, P<Block>),
     /// A module declaration (`mod` or `pub mod`).
     ///
     /// E.g. `mod foo;` or `mod foo { .. }`
@@ -1867,6 +1883,10 @@ pub enum ItemKind {
     ///
     /// E.g. `struct Foo<A> { x: A }`
     Struct(VariantData, Generics),
+    /// A union definition (`union` or `pub union`).
+    ///
+    /// E.g. `union Foo<A, B> { x: A, y: B }`
+    Union(VariantData, Generics), // FIXME: not yet implemented
     /// A Trait declaration (`trait` or `pub trait`).
     ///
     /// E.g. `trait Foo { .. }` or `trait Foo<T> { .. }`
@@ -1903,6 +1923,7 @@ pub fn descriptive_variant(&self) -> &str {
             ItemKind::Ty(..) => "type alias",
             ItemKind::Enum(..) => "enum",
             ItemKind::Struct(..) => "struct",
+            ItemKind::Union(..) => "union",
             ItemKind::Trait(..) => "trait",
             ItemKind::Mac(..) |
             ItemKind::Impl(..) |
index b622f6861b38379059ea23b23994b76792b9265c..81ee96459fd64edbf9e7c04eaa966d217de318ff 100644 (file)
 pub use self::IntType::*;
 
 use ast;
-use ast::{AttrId, Attribute, Attribute_, MetaItem, MetaItemKind};
-use ast::{Expr, Item, Local, Stmt, StmtKind};
-use codemap::{respan, spanned, dummy_spanned, Spanned};
+use ast::{AttrId, Attribute, Attribute_};
+use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
+use ast::{Lit, Expr, Item, Local, Stmt, StmtKind};
+use codemap::{respan, spanned, dummy_spanned};
 use syntax_pos::{Span, BytePos, DUMMY_SP};
 use errors::Handler;
 use feature_gate::{Features, GatedCfg};
@@ -40,6 +41,7 @@ enum AttrError {
     MissingSince,
     MissingFeature,
     MultipleStabilityLevels,
+    UnsupportedLiteral
 }
 
 fn handle_errors(diag: &Handler, span: Span, error: AttrError) {
@@ -52,10 +54,12 @@ fn handle_errors(diag: &Handler, span: Span, error: AttrError) {
         AttrError::MissingFeature => span_err!(diag, span, E0546, "missing 'feature'"),
         AttrError::MultipleStabilityLevels => span_err!(diag, span, E0544,
                                                         "multiple stability levels"),
+        AttrError::UnsupportedLiteral => span_err!(diag, span, E0565, "unsupported literal"),
     }
 }
 
 pub fn mark_used(attr: &Attribute) {
+    debug!("Marking {:?} as used.", attr);
     let AttrId(id) = attr.node.id;
     USED_ATTRS.with(|slot| {
         let idx = (id / 64) as usize;
@@ -77,60 +81,120 @@ pub fn is_used(attr: &Attribute) -> bool {
     })
 }
 
-pub trait AttrMetaMethods {
-    fn check_name(&self, name: &str) -> bool {
-        name == &self.name()[..]
+impl NestedMetaItem {
+    /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem.
+    pub fn meta_item(&self) -> Option<&P<MetaItem>> {
+        match self.node {
+            NestedMetaItemKind::MetaItem(ref item) => Some(&item),
+            _ => None
+        }
+    }
+
+    /// Returns the Lit if self is a NestedMetaItemKind::Literal.
+    pub fn literal(&self) -> Option<&Lit> {
+        match self.node {
+            NestedMetaItemKind::Literal(ref lit) => Some(&lit),
+            _ => None
+        }
     }
 
-    /// Retrieve the name of the meta item, e.g. `foo` in `#[foo]`,
-    /// `#[foo="bar"]` and `#[foo(bar)]`
-    fn name(&self) -> InternedString;
+    /// Returns the Span for `self`.
+    pub fn span(&self) -> Span {
+        self.span
+    }
+
+    /// Returns true if this list item is a MetaItem with a name of `name`.
+    pub fn check_name(&self, name: &str) -> bool {
+        self.meta_item().map_or(false, |meta_item| meta_item.check_name(name))
+    }
+
+    /// Returns the name of the meta item, e.g. `foo` in `#[foo]`,
+    /// `#[foo="bar"]` and `#[foo(bar)]`, if self is a MetaItem
+    pub fn name(&self) -> Option<InternedString> {
+        self.meta_item().and_then(|meta_item| Some(meta_item.name()))
+    }
+
+    /// Gets the string value if self is a MetaItem and the MetaItem is a
+    /// MetaItemKind::NameValue variant containing a string, otherwise None.
+    pub fn value_str(&self) -> Option<InternedString> {
+        self.meta_item().and_then(|meta_item| meta_item.value_str())
+    }
+
+    /// Returns a MetaItem if self is a MetaItem with Kind Word.
+    pub fn word(&self) -> Option<&P<MetaItem>> {
+        self.meta_item().and_then(|meta_item| if meta_item.is_word() {
+            Some(meta_item)
+        } else {
+            None
+        })
+    }
 
-    /// Gets the string value if self is a MetaItemKind::NameValue variant
-    /// containing a string, otherwise None.
-    fn value_str(&self) -> Option<InternedString>;
     /// Gets a list of inner meta items from a list MetaItem type.
-    fn meta_item_list(&self) -> Option<&[P<MetaItem>]>;
+    pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
+        self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
+    }
 
-    /// Indicates if the attribute is a Word.
-    fn is_word(&self) -> bool;
+    /// Returns `true` if the variant is MetaItem.
+    pub fn is_meta_item(&self) -> bool {
+        self.meta_item().is_some()
+    }
 
-    /// Indicates if the attribute is a Value String.
-    fn is_value_str(&self) -> bool {
+    /// Returns `true` if the variant is Literal.
+    pub fn is_literal(&self) -> bool {
+        self.literal().is_some()
+    }
+
+    /// Returns `true` if self is a MetaItem and the meta item is a word.
+    pub fn is_word(&self) -> bool {
+        self.word().is_some()
+    }
+
+    /// Returns `true` if self is a MetaItem and the meta item is a ValueString.
+    pub fn is_value_str(&self) -> bool {
         self.value_str().is_some()
     }
 
-    /// Indicates if the attribute is a Meta-Item List.
-    fn is_meta_item_list(&self) -> bool {
+    /// Returns `true` if self is a MetaItem and the meta item is a list.
+    pub fn is_meta_item_list(&self) -> bool {
         self.meta_item_list().is_some()
     }
-
-    fn span(&self) -> Span;
 }
 
-impl AttrMetaMethods for Attribute {
-    fn check_name(&self, name: &str) -> bool {
+impl Attribute {
+    pub fn check_name(&self, name: &str) -> bool {
         let matches = name == &self.name()[..];
         if matches {
             mark_used(self);
         }
         matches
     }
-    fn name(&self) -> InternedString { self.meta().name() }
-    fn value_str(&self) -> Option<InternedString> {
+
+    pub fn name(&self) -> InternedString { self.meta().name() }
+
+    pub fn value_str(&self) -> Option<InternedString> {
         self.meta().value_str()
     }
-    fn meta_item_list(&self) -> Option<&[P<MetaItem>]> {
+
+    pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
         self.meta().meta_item_list()
     }
 
-    fn is_word(&self) -> bool { self.meta().is_word() }
+    pub fn is_word(&self) -> bool { self.meta().is_word() }
+
+    pub fn span(&self) -> Span { self.meta().span }
+
+    pub fn is_meta_item_list(&self) -> bool {
+        self.meta_item_list().is_some()
+    }
 
-    fn span(&self) -> Span { self.meta().span }
+    /// Indicates if the attribute is a Value String.
+    pub fn is_value_str(&self) -> bool {
+        self.value_str().is_some()
+    }
 }
 
-impl AttrMetaMethods for MetaItem {
-    fn name(&self) -> InternedString {
+impl MetaItem {
+    pub fn name(&self) -> InternedString {
         match self.node {
             MetaItemKind::Word(ref n) => (*n).clone(),
             MetaItemKind::NameValue(ref n, _) => (*n).clone(),
@@ -138,7 +202,7 @@ fn name(&self) -> InternedString {
         }
     }
 
-    fn value_str(&self) -> Option<InternedString> {
+    pub fn value_str(&self) -> Option<InternedString> {
         match self.node {
             MetaItemKind::NameValue(_, ref v) => {
                 match v.node {
@@ -150,53 +214,45 @@ fn value_str(&self) -> Option<InternedString> {
         }
     }
 
-    fn meta_item_list(&self) -> Option<&[P<MetaItem>]> {
+    pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
         match self.node {
             MetaItemKind::List(_, ref l) => Some(&l[..]),
             _ => None
         }
     }
 
-    fn is_word(&self) -> bool {
+    pub fn is_word(&self) -> bool {
         match self.node {
             MetaItemKind::Word(_) => true,
             _ => false,
         }
     }
 
-    fn span(&self) -> Span { self.span }
-}
+    pub fn span(&self) -> Span { self.span }
 
-// Annoying, but required to get test_cfg to work
-impl AttrMetaMethods for P<MetaItem> {
-    fn name(&self) -> InternedString { (**self).name() }
-    fn value_str(&self) -> Option<InternedString> { (**self).value_str() }
-    fn meta_item_list(&self) -> Option<&[P<MetaItem>]> {
-        (**self).meta_item_list()
+    pub fn check_name(&self, name: &str) -> bool {
+        name == &self.name()[..]
     }
-    fn is_word(&self) -> bool { (**self).is_word() }
-    fn is_value_str(&self) -> bool { (**self).is_value_str() }
-    fn is_meta_item_list(&self) -> bool { (**self).is_meta_item_list() }
-    fn span(&self) -> Span { (**self).span() }
-}
 
+    pub fn is_value_str(&self) -> bool {
+        self.value_str().is_some()
+    }
 
-pub trait AttributeMethods {
-    fn meta(&self) -> &MetaItem;
-    fn with_desugared_doc<T, F>(&self, f: F) -> T where
-        F: FnOnce(&Attribute) -> T;
+    pub fn is_meta_item_list(&self) -> bool {
+        self.meta_item_list().is_some()
+    }
 }
 
-impl AttributeMethods for Attribute {
+impl Attribute {
     /// Extract the MetaItem from inside this Attribute.
-    fn meta(&self) -> &MetaItem {
+    pub fn meta(&self) -> &MetaItem {
         &self.node.value
     }
 
     /// Convert self to a normal #[doc="foo"] comment, if it is a
     /// comment like `///` or `/** */`. (Returns self unchanged for
     /// non-sugared doc attributes.)
-    fn with_desugared_doc<T, F>(&self, f: F) -> T where
+    pub fn with_desugared_doc<T, F>(&self, f: F) -> T where
         F: FnOnce(&Attribute) -> T,
     {
         if self.node.is_sugared_doc {
@@ -229,10 +285,14 @@ pub fn mk_name_value_item(name: InternedString, value: ast::Lit)
     mk_spanned_name_value_item(DUMMY_SP, name, value)
 }
 
-pub fn mk_list_item(name: InternedString, items: Vec<P<MetaItem>>) -> P<MetaItem> {
+pub fn mk_list_item(name: InternedString, items: Vec<NestedMetaItem>) -> P<MetaItem> {
     mk_spanned_list_item(DUMMY_SP, name, items)
 }
 
+pub fn mk_list_word_item(name: InternedString) -> ast::NestedMetaItem {
+    dummy_spanned(NestedMetaItemKind::MetaItem(mk_spanned_word_item(DUMMY_SP, name)))
+}
+
 pub fn mk_word_item(name: InternedString) -> P<MetaItem> {
     mk_spanned_word_item(DUMMY_SP, name)
 }
@@ -242,7 +302,7 @@ pub fn mk_spanned_name_value_item(sp: Span, name: InternedString, value: ast::Li
     P(respan(sp, MetaItemKind::NameValue(name, value)))
 }
 
-pub fn mk_spanned_list_item(sp: Span, name: InternedString, items: Vec<P<MetaItem>>)
+pub fn mk_spanned_list_item(sp: Span, name: InternedString, items: Vec<NestedMetaItem>)
                             -> P<MetaItem> {
     P(respan(sp, MetaItemKind::List(name, items)))
 }
@@ -332,9 +392,17 @@ pub fn contains(haystack: &[P<MetaItem>], needle: &MetaItem) -> bool {
     })
 }
 
-pub fn contains_name<AM: AttrMetaMethods>(metas: &[AM], name: &str) -> bool {
+pub fn list_contains_name(items: &[NestedMetaItem], name: &str) -> bool {
+    debug!("attr::list_contains_name (name={})", name);
+    items.iter().any(|item| {
+        debug!("  testing: {:?}", item.name());
+        item.check_name(name)
+    })
+}
+
+pub fn contains_name(attrs: &[Attribute], name: &str) -> bool {
     debug!("attr::contains_name (name={})", name);
-    metas.iter().any(|item| {
+    attrs.iter().any(|item| {
         debug!("  testing: {}", item.name());
         item.check_name(name)
     })
@@ -357,27 +425,6 @@ pub fn last_meta_item_value_str_by_name(items: &[P<MetaItem>], name: &str)
 
 /* Higher-level applications */
 
-pub fn sort_meta_items(items: Vec<P<MetaItem>>) -> Vec<P<MetaItem>> {
-    // This is sort of stupid here, but we need to sort by
-    // human-readable strings.
-    let mut v = items.into_iter()
-        .map(|mi| (mi.name(), mi))
-        .collect::<Vec<(InternedString, P<MetaItem>)>>();
-
-    v.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b));
-
-    // There doesn't seem to be a more optimal way to do this
-    v.into_iter().map(|(_, m)| m.map(|Spanned {node, span}| {
-        Spanned {
-            node: match node {
-                MetaItemKind::List(n, mis) => MetaItemKind::List(n, sort_meta_items(mis)),
-                _ => node
-            },
-            span: span
-        }
-    })).collect()
-}
-
 pub fn find_crate_name(attrs: &[Attribute]) -> Option<InternedString> {
     first_attr_value_str_by_name(attrs, "crate_name")
 }
@@ -391,8 +438,9 @@ pub fn find_export_name_attr(diag: &Handler, attrs: &[Attribute]) -> Option<Inte
             } else {
                 struct_span_err!(diag, attr.span, E0558,
                                  "export_name attribute has invalid format")
-                                .help("use #[export_name=\"*\"]")
-                                .emit();
+                    .span_label(attr.span,
+                                &format!("did you mean #[export_name=\"*\"]?"))
+                    .emit();
                 None
             }
         } else {
@@ -427,14 +475,15 @@ pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> In
                 if items.len() != 1 {
                     diagnostic.map(|d|{ span_err!(d, attr.span, E0534, "expected one argument"); });
                     InlineAttr::None
-                } else if contains_name(&items[..], "always") {
+                } else if list_contains_name(&items[..], "always") {
                     InlineAttr::Always
-                } else if contains_name(&items[..], "never") {
+                } else if list_contains_name(&items[..], "never") {
                     InlineAttr::Never
                 } else {
                     diagnostic.map(|d| {
-                        span_err!(d, (*items[0]).span, E0535, "invalid argument");
+                        span_err!(d, items[0].span, E0535, "invalid argument");
                     });
+
                     InlineAttr::None
                 }
             }
@@ -453,27 +502,44 @@ pub fn requests_inline(attrs: &[Attribute]) -> bool {
 
 /// Tests if a cfg-pattern matches the cfg set
 pub fn cfg_matches(cfgs: &[P<MetaItem>], cfg: &ast::MetaItem,
-                   sess: &ParseSess, features: Option<&Features>)
+                   sess: &ParseSess,
+                   features: Option<&Features>)
                    -> bool {
     match cfg.node {
-        ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "any" =>
-            mis.iter().any(|mi| cfg_matches(cfgs, &mi, sess, features)),
-        ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "all" =>
-            mis.iter().all(|mi| cfg_matches(cfgs, &mi, sess, features)),
-        ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "not" => {
-            if mis.len() != 1 {
-                span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern");
-                return false;
+        ast::MetaItemKind::List(ref pred, ref mis) => {
+            for mi in mis.iter() {
+                if !mi.is_meta_item() {
+                    handle_errors(&sess.span_diagnostic, mi.span, AttrError::UnsupportedLiteral);
+                    return false;
+                }
+            }
+
+            // The unwraps below may look dangerous, but we've already asserted
+            // that they won't fail with the loop above.
+            match &pred[..] {
+                "any" => mis.iter().any(|mi| {
+                    cfg_matches(cfgs, mi.meta_item().unwrap(), sess, features)
+                }),
+                "all" => mis.iter().all(|mi| {
+                    cfg_matches(cfgs, mi.meta_item().unwrap(), sess, features)
+                }),
+                "not" => {
+                    if mis.len() != 1 {
+                        span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern");
+                        return false;
+                    }
+
+                    !cfg_matches(cfgs, mis[0].meta_item().unwrap(), sess, features)
+                },
+                p => {
+                    span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", p);
+                    false
+                }
             }
-            !cfg_matches(cfgs, &mis[0], sess, features)
-        }
-        ast::MetaItemKind::List(ref pred, _) => {
-            span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", pred);
-            false
         },
         ast::MetaItemKind::Word(_) | ast::MetaItemKind::NameValue(..) => {
-            if let (Some(features), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) {
-                gated_cfg.check_and_emit(sess, features);
+            if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) {
+                gated_cfg.check_and_emit(sess, feats);
             }
             contains(cfgs, cfg)
         }
@@ -557,14 +623,19 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
                     let mut since = None;
                     let mut reason = None;
                     for meta in metas {
-                        match &*meta.name() {
-                            "since" => if !get(meta, &mut since) { continue 'outer },
-                            "reason" => if !get(meta, &mut reason) { continue 'outer },
-                            _ => {
-                                handle_errors(diagnostic, meta.span,
-                                              AttrError::UnknownMetaItem(meta.name()));
-                                continue 'outer
+                        if let Some(mi) = meta.meta_item() {
+                            match &*mi.name() {
+                                "since" => if !get(mi, &mut since) { continue 'outer },
+                                "reason" => if !get(mi, &mut reason) { continue 'outer },
+                                _ => {
+                                    handle_errors(diagnostic, mi.span,
+                                                  AttrError::UnknownMetaItem(mi.name()));
+                                    continue 'outer
+                                }
                             }
+                        } else {
+                            handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral);
+                            continue 'outer
                         }
                     }
 
@@ -595,15 +666,20 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
                     let mut reason = None;
                     let mut issue = None;
                     for meta in metas {
-                        match &*meta.name() {
-                            "feature" => if !get(meta, &mut feature) { continue 'outer },
-                            "reason" => if !get(meta, &mut reason) { continue 'outer },
-                            "issue" => if !get(meta, &mut issue) { continue 'outer },
-                            _ => {
-                                handle_errors(diagnostic, meta.span,
-                                              AttrError::UnknownMetaItem(meta.name()));
-                                continue 'outer
+                        if let Some(mi) = meta.meta_item() {
+                            match &*mi.name() {
+                                "feature" => if !get(mi, &mut feature) { continue 'outer },
+                                "reason" => if !get(mi, &mut reason) { continue 'outer },
+                                "issue" => if !get(mi, &mut issue) { continue 'outer },
+                                _ => {
+                                    handle_errors(diagnostic, meta.span,
+                                                  AttrError::UnknownMetaItem(mi.name()));
+                                    continue 'outer
+                                }
                             }
+                        } else {
+                            handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral);
+                            continue 'outer
                         }
                     }
 
@@ -645,14 +721,19 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
                     let mut feature = None;
                     let mut since = None;
                     for meta in metas {
-                        match &*meta.name() {
-                            "feature" => if !get(meta, &mut feature) { continue 'outer },
-                            "since" => if !get(meta, &mut since) { continue 'outer },
-                            _ => {
-                                handle_errors(diagnostic, meta.span,
-                                              AttrError::UnknownMetaItem(meta.name()));
-                                continue 'outer
+                        if let NestedMetaItemKind::MetaItem(ref mi) = meta.node {
+                            match &*mi.name() {
+                                "feature" => if !get(mi, &mut feature) { continue 'outer },
+                                "since" => if !get(mi, &mut since) { continue 'outer },
+                                _ => {
+                                    handle_errors(diagnostic, meta.span,
+                                                  AttrError::UnknownMetaItem(mi.name()));
+                                    continue 'outer
+                                }
                             }
+                        } else {
+                            handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral);
+                            continue 'outer
                         }
                     }
 
@@ -739,14 +820,19 @@ fn find_deprecation_generic<'a, I>(diagnostic: &Handler,
             let mut since = None;
             let mut note = None;
             for meta in metas {
-                match &*meta.name() {
-                    "since" => if !get(meta, &mut since) { continue 'outer },
-                    "note" => if !get(meta, &mut note) { continue 'outer },
-                    _ => {
-                        handle_errors(diagnostic, meta.span,
-                                      AttrError::UnknownMetaItem(meta.name()));
-                        continue 'outer
+                if let NestedMetaItemKind::MetaItem(ref mi) = meta.node {
+                    match &*mi.name() {
+                        "since" => if !get(mi, &mut since) { continue 'outer },
+                        "note" => if !get(mi, &mut note) { continue 'outer },
+                        _ => {
+                            handle_errors(diagnostic, meta.span,
+                                          AttrError::UnknownMetaItem(mi.name()));
+                            continue 'outer
+                        }
                     }
+                } else {
+                    handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral);
+                    continue 'outer
                 }
             }
 
@@ -796,32 +882,35 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
         ast::MetaItemKind::List(ref s, ref items) if s == "repr" => {
             mark_used(attr);
             for item in items {
-                match item.node {
-                    ast::MetaItemKind::Word(ref word) => {
-                        let hint = match &word[..] {
-                            // Can't use "extern" because it's not a lexical identifier.
-                            "C" => Some(ReprExtern),
-                            "packed" => Some(ReprPacked),
-                            "simd" => Some(ReprSimd),
-                            _ => match int_type_of_word(&word) {
-                                Some(ity) => Some(ReprInt(item.span, ity)),
-                                None => {
-                                    // Not a word we recognize
-                                    span_err!(diagnostic, item.span, E0552,
-                                              "unrecognized representation hint");
-                                    None
-                                }
-                            }
-                        };
+                if !item.is_meta_item() {
+                    handle_errors(diagnostic, item.span, AttrError::UnsupportedLiteral);
+                    continue
+                }
 
-                        match hint {
-                            Some(h) => acc.push(h),
-                            None => { }
+                if let Some(mi) = item.word() {
+                    let word = &*mi.name();
+                    let hint = match word {
+                        // Can't use "extern" because it's not a lexical identifier.
+                        "C" => Some(ReprExtern),
+                        "packed" => Some(ReprPacked),
+                        "simd" => Some(ReprSimd),
+                        _ => match int_type_of_word(word) {
+                            Some(ity) => Some(ReprInt(item.span, ity)),
+                            None => {
+                                // Not a word we recognize
+                                span_err!(diagnostic, item.span, E0552,
+                                          "unrecognized representation hint");
+                                None
+                            }
                         }
+                    };
+
+                    if let Some(h) = hint {
+                        acc.push(h);
                     }
-                    // Not a word:
-                    _ => span_err!(diagnostic, item.span, E0553,
-                                   "unrecognized enum representation hint"),
+                } else {
+                    span_err!(diagnostic, item.span, E0553,
+                              "unrecognized enum representation hint");
                 }
             }
         }
index a825cf866a878309eeac575eca99db0a140c079d..69a979176521b47d8f38b3e1841b34da99880aa5 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use attr::{AttrMetaMethods, HasAttrs};
+use attr::HasAttrs;
 use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue};
 use fold::Folder;
 use {fold, attr};
@@ -52,6 +52,7 @@ fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
                 return None;
             }
         };
+
         let (cfg, mi) = match (attr_list.len(), attr_list.get(0), attr_list.get(1)) {
             (2, Some(cfg), Some(mi)) => (cfg, mi),
             _ => {
@@ -61,15 +62,24 @@ fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
             }
         };
 
-        if attr::cfg_matches(self.config, &cfg, self.sess, self.features) {
-            self.process_cfg_attr(respan(mi.span, ast::Attribute_ {
-                id: attr::mk_attr_id(),
-                style: attr.node.style,
-                value: mi.clone(),
-                is_sugared_doc: false,
-            }))
-        } else {
-            None
+        use attr::cfg_matches;
+        match (cfg.meta_item(), mi.meta_item()) {
+            (Some(cfg), Some(mi)) =>
+                if cfg_matches(self.config, &cfg, self.sess, self.features) {
+                    self.process_cfg_attr(respan(mi.span, ast::Attribute_ {
+                        id: attr::mk_attr_id(),
+                        style: attr.node.style,
+                        value: mi.clone(),
+                        is_sugared_doc: false,
+                    }))
+                } else {
+                    None
+                },
+            _ => {
+                let msg = "unexpected literal(s) in `#[cfg_attr(<cfg pattern>, <attr>)]`";
+                self.sess.span_diagnostic.span_err(attr.span, msg);
+                None
+            }
         }
     }
 
@@ -91,7 +101,12 @@ fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
                 return true;
             }
 
-            attr::cfg_matches(self.config, &mis[0], self.sess, self.features)
+            if !mis[0].is_meta_item() {
+                self.sess.span_diagnostic.span_err(mis[0].span, "unexpected literal");
+                return true;
+            }
+
+            attr::cfg_matches(self.config, mis[0].meta_item().unwrap(), self.sess, self.features)
         })
     }
 
@@ -165,6 +180,9 @@ fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
             ast::ItemKind::Struct(def, generics) => {
                 ast::ItemKind::Struct(fold_struct(self, def), generics)
             }
+            ast::ItemKind::Union(def, generics) => {
+                ast::ItemKind::Union(fold_struct(self, def), generics)
+            }
             ast::ItemKind::Enum(def, generics) => {
                 let variants = def.variants.into_iter().filter_map(|v| {
                     self.configure(v).map(|v| {
index 010b1d638e63cf2085e89ea9f265a3376d228b47..9110e989a8a1491f6d1f884a78d79e06790c1241 100644 (file)
@@ -161,6 +161,24 @@ fn main() {}
 ```
 "##,
 
+E0565: r##"
+A literal was used in an attribute that doesn't support literals.
+
+Erroneous code example:
+
+```compile_fail,E0565
+#[inline("always")] // error: unsupported literal
+pub fn something() {}
+```
+
+Literals in attributes are new and largely unsupported. Work to support literals
+where appropriate is ongoing. Try using an unquoted name instead:
+
+```
+#[inline(always)]
+pub fn something() {}
+```
+"##,
 }
 
 register_diagnostics! {
index 6ba3b92483fddd8ad617a677fcece75f1f5da94a..43e190f5deb813d26cfcb13f2c11ec919df40fc1 100644 (file)
@@ -60,13 +60,6 @@ fn map_attrs<F: FnOnce(Vec<ast::Attribute>) -> Vec<ast::Attribute>>(self, f: F)
 }
 
 impl Annotatable {
-    pub fn attrs(&self) -> &[ast::Attribute] {
-        HasAttrs::attrs(self)
-    }
-    pub fn fold_attrs(self, attrs: Vec<ast::Attribute>) -> Annotatable {
-        self.map_attrs(|_| attrs)
-    }
-
     pub fn expect_item(self) -> P<ast::Item> {
         match self {
             Annotatable::Item(i) => i,
index 5d6429f7bdfffa1bac2326fd821c5d664832b00a..3dcdbc890962790de746e2fe145d5e987d75547a 100644 (file)
@@ -12,7 +12,7 @@
 use ast::{self, Ident, Generics, Expr, BlockCheckMode, UnOp, PatKind};
 use attr;
 use syntax_pos::{Span, DUMMY_SP, Pos};
-use codemap::{respan, Spanned};
+use codemap::{dummy_spanned, respan, Spanned};
 use ext::base::ExtCtxt;
 use parse::token::{self, keywords, InternedString};
 use ptr::P;
@@ -171,9 +171,11 @@ fn pat_ident_binding_mode(&self,
                               span: Span,
                               ident: ast::Ident,
                               bm: ast::BindingMode) -> P<ast::Pat>;
-    fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec<P<ast::Pat>> ) -> P<ast::Pat>;
-    fn pat_struct(&self, span: Span,
-                  path: ast::Path, field_pats: Vec<Spanned<ast::FieldPat>> ) -> P<ast::Pat>;
+    fn pat_path(&self, span: Span, path: ast::Path) -> P<ast::Pat>;
+    fn pat_tuple_struct(&self, span: Span, path: ast::Path,
+                        subpats: Vec<P<ast::Pat>>) -> P<ast::Pat>;
+    fn pat_struct(&self, span: Span, path: ast::Path,
+                  field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat>;
     fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat>;
 
     fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat>;
@@ -277,10 +279,13 @@ fn item_ty_poly(&self,
     fn attribute(&self, sp: Span, mi: P<ast::MetaItem>) -> ast::Attribute;
 
     fn meta_word(&self, sp: Span, w: InternedString) -> P<ast::MetaItem>;
+
+    fn meta_list_item_word(&self, sp: Span, w: InternedString) -> ast::NestedMetaItem;
+
     fn meta_list(&self,
                  sp: Span,
                  name: InternedString,
-                 mis: Vec<P<ast::MetaItem>> )
+                 mis: Vec<ast::NestedMetaItem> )
                  -> P<ast::MetaItem>;
     fn meta_name_value(&self,
                        sp: Span,
@@ -802,10 +807,10 @@ fn expr_try(&self, sp: Span, head: P<ast::Expr>) -> P<ast::Expr> {
         let binding_expr = self.expr_ident(sp, binding_variable);
 
         // Ok(__try_var) pattern
-        let ok_pat = self.pat_enum(sp, ok_path, vec!(binding_pat.clone()));
+        let ok_pat = self.pat_tuple_struct(sp, ok_path, vec![binding_pat.clone()]);
 
         // Err(__try_var)  (pattern and expression resp.)
-        let err_pat = self.pat_enum(sp, err_path.clone(), vec!(binding_pat));
+        let err_pat = self.pat_tuple_struct(sp, err_path.clone(), vec![binding_pat]);
         let err_inner_expr = self.expr_call(sp, self.expr_path(err_path),
                                             vec!(binding_expr.clone()));
         // return Err(__try_var)
@@ -842,18 +847,16 @@ fn pat_ident_binding_mode(&self,
         let pat = PatKind::Ident(bm, Spanned{span: span, node: ident}, None);
         self.pat(span, pat)
     }
-    fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
-        let pat = if subpats.is_empty() {
-            PatKind::Path(None, path)
-        } else {
-            PatKind::TupleStruct(path, subpats, None)
-        };
-        self.pat(span, pat)
+    fn pat_path(&self, span: Span, path: ast::Path) -> P<ast::Pat> {
+        self.pat(span, PatKind::Path(None, path))
     }
-    fn pat_struct(&self, span: Span,
-                  path: ast::Path, field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat> {
-        let pat = PatKind::Struct(path, field_pats, false);
-        self.pat(span, pat)
+    fn pat_tuple_struct(&self, span: Span, path: ast::Path,
+                        subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
+        self.pat(span, PatKind::TupleStruct(path, subpats, None))
+    }
+    fn pat_struct(&self, span: Span, path: ast::Path,
+                  field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat> {
+        self.pat(span, PatKind::Struct(path, field_pats, false))
     }
     fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
         self.pat(span, PatKind::Tuple(pats, None))
@@ -862,25 +865,25 @@ fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
     fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
         let some = self.std_path(&["option", "Option", "Some"]);
         let path = self.path_global(span, some);
-        self.pat_enum(span, path, vec!(pat))
+        self.pat_tuple_struct(span, path, vec![pat])
     }
 
     fn pat_none(&self, span: Span) -> P<ast::Pat> {
         let some = self.std_path(&["option", "Option", "None"]);
         let path = self.path_global(span, some);
-        self.pat_enum(span, path, vec!())
+        self.pat_path(span, path)
     }
 
     fn pat_ok(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
         let some = self.std_path(&["result", "Result", "Ok"]);
         let path = self.path_global(span, some);
-        self.pat_enum(span, path, vec!(pat))
+        self.pat_tuple_struct(span, path, vec![pat])
     }
 
     fn pat_err(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
         let some = self.std_path(&["result", "Result", "Err"]);
         let path = self.path_global(span, some);
-        self.pat_enum(span, path, vec!(pat))
+        self.pat_tuple_struct(span, path, vec![pat])
     }
 
     fn arm(&self, _span: Span, pats: Vec<P<ast::Pat>>, expr: P<ast::Expr>) -> ast::Arm {
@@ -1016,7 +1019,7 @@ fn item_fn_poly(&self,
                   Vec::new(),
                   ast::ItemKind::Fn(self.fn_decl(inputs, output),
                               ast::Unsafety::Normal,
-                              ast::Constness::NotConst,
+                              dummy_spanned(ast::Constness::NotConst),
                               Abi::Rust,
                               generics,
                               body))
@@ -1141,10 +1144,16 @@ fn attribute(&self, sp: Span, mi: P<ast::MetaItem>) -> ast::Attribute {
     fn meta_word(&self, sp: Span, w: InternedString) -> P<ast::MetaItem> {
         attr::mk_spanned_word_item(sp, w)
     }
-    fn meta_list(&self, sp: Span, name: InternedString, mis: Vec<P<ast::MetaItem>>)
+
+    fn meta_list_item_word(&self, sp: Span, w: InternedString) -> ast::NestedMetaItem {
+        respan(sp, ast::NestedMetaItemKind::MetaItem(attr::mk_spanned_word_item(sp, w)))
+    }
+
+    fn meta_list(&self, sp: Span, name: InternedString, mis: Vec<ast::NestedMetaItem>)
                  -> P<ast::MetaItem> {
         attr::mk_spanned_list_item(sp, name, mis)
     }
+
     fn meta_name_value(&self, sp: Span, name: InternedString, value: ast::LitKind)
                        -> P<ast::MetaItem> {
         attr::mk_spanned_name_value_item(sp, name, respan(sp, value))
@@ -1178,7 +1187,7 @@ fn item_use_simple_(&self, sp: Span, vis: ast::Visibility,
     fn item_use_list(&self, sp: Span, vis: ast::Visibility,
                      path: Vec<ast::Ident>, imports: &[ast::Ident]) -> P<ast::Item> {
         let imports = imports.iter().map(|id| {
-            let item = ast::PathListItemKind::Ident {
+            let item = ast::PathListItem_ {
                 name: *id,
                 rename: None,
                 id: ast::DUMMY_NODE_ID,
index 031d9a2d3f46e781debb012b0325b787345ddcfb..15ebf95d6239370e76ce470dae113680613dbfd4 100644 (file)
@@ -13,7 +13,6 @@
 use ast;
 use ext::hygiene::Mark;
 use attr::{self, HasAttrs};
-use attr::AttrMetaMethods;
 use codemap::{dummy_spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use syntax_pos::{self, Span, ExpnId};
 use config::StripUnconfigured;
@@ -491,18 +490,7 @@ fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander)
 pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
     let t = match t.node.clone() {
         ast::TyKind::Mac(mac) => {
-            if fld.cx.ecfg.features.unwrap().type_macros {
-                expand_mac_invoc(mac, None, Vec::new(), t.span, fld)
-            } else {
-                feature_gate::emit_feature_err(
-                    &fld.cx.parse_sess.span_diagnostic,
-                    "type_macros",
-                    t.span,
-                    feature_gate::GateIssue::Language,
-                    "type macros are experimental");
-
-                DummyResult::raw_ty(t.span)
-            }
+            expand_mac_invoc(mac, None, Vec::new(), t.span, fld)
         }
         _ => t
     };
index d94bfe7dcbdac2df758c55f87ec3256c1b9ee523..02c44c3a56d7e61e31c8820535a54aebe5332de4 100644 (file)
 use self::AttributeGate::*;
 
 use abi::Abi;
-use ast::{NodeId, PatKind};
-use ast;
+use ast::{self, NodeId, PatKind};
 use attr;
-use attr::AttrMetaMethods;
-use codemap::CodeMap;
+use codemap::{CodeMap, Spanned};
 use syntax_pos::Span;
 use errors::Handler;
 use visit::{self, FnKind, Visitor};
@@ -164,10 +162,6 @@ pub fn new() -> Features {
     // Allows using `box` in patterns; RFC 469
     (active, box_patterns, "1.0.0", Some(29641)),
 
-    // Allows using the unsafe_no_drop_flag attribute (unlikely to
-    // switch to Accepted; see RFC 320)
-    (active, unsafe_no_drop_flag, "1.0.0", None),
-
     // Allows using the unsafe_destructor_blind_to_params attribute;
     // RFC 1238
     (active, dropck_parametricity, "1.3.0", Some(28498)),
@@ -217,9 +211,6 @@ pub fn new() -> Features {
     // Allows associated type defaults
     (active, associated_type_defaults, "1.2.0", Some(29661)),
 
-    // Allows macros to appear in the type position.
-    (active, type_macros, "1.3.0", Some(27245)),
-
     // allow `repr(simd)`, and importing the various simd intrinsics
     (active, repr_simd, "1.4.0", Some(27731)),
 
@@ -287,7 +278,17 @@ pub fn new() -> Features {
     (active, relaxed_adts, "1.12.0", Some(35626)),
 
     // The `!` type
-    (active, never_type, "1.13.0", Some(35121))
+    (active, never_type, "1.13.0", Some(35121)),
+
+    // Allows all literals in attribute lists and values of key-value pairs.
+    (active, attr_literals, "1.13.0", Some(34981)),
+
+    // Allows the sysV64 ABI to be specified on all platforms
+    // instead of just the platforms on which it is the C ABI
+    (active, abi_sysv64, "1.13.0", Some(36167)),
+
+    // Use the import semantics from RFC 1560.
+    (active, item_like_imports, "1.13.0", Some(35120))
 );
 
 declare_features! (
@@ -300,7 +301,8 @@ pub fn new() -> Features {
     (removed, quad_precision_float, "1.0.0", None),
     (removed, struct_inherit, "1.0.0", None),
     (removed, test_removed_feature, "1.0.0", None),
-    (removed, visible_private_types, "1.0.0", None)
+    (removed, visible_private_types, "1.0.0", None),
+    (removed, unsafe_no_drop_flag, "1.0.0", None)
 );
 
 declare_features! (
@@ -324,6 +326,8 @@ pub fn new() -> Features {
     // mean anything
     (accepted, test_accepted_feature, "1.0.0", None),
     (accepted, tuple_indexing, "1.0.0", None),
+    // Allows macros to appear in the type position.
+    (accepted, type_macros, "1.13.0", Some(27245)),
     (accepted, while_let, "1.0.0", None),
     // Allows `#[deprecated]` attribute
     (accepted, deprecated, "1.9.0", Some(29935))
@@ -517,11 +521,6 @@ fn f(features: &Features) -> bool {
                                       is just used for rustc unit tests \
                                       and will never be stable",
                                      cfg_fn!(rustc_attrs))),
-    ("rustc_no_mir", Whitelisted, Gated("rustc_attrs",
-                                        "the `#[rustc_no_mir]` attribute \
-                                         is just used to make tests pass \
-                                         and will never be stable",
-                                        cfg_fn!(rustc_attrs))),
     ("rustc_inherit_overflow_checks", Whitelisted, Gated("rustc_attrs",
                                                          "the `#[rustc_inherit_overflow_checks]` \
                                                           attribute is just used to control \
@@ -570,10 +569,6 @@ fn f(features: &Features) -> bool {
                                                         attribute is just used for the Rust test \
                                                         suite",
                                                        cfg_fn!(omit_gdb_pretty_printer_section))),
-    ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag",
-                                               "unsafe_no_drop_flag has unstable semantics \
-                                                and may be removed in the future",
-                                               cfg_fn!(unsafe_no_drop_flag))),
     ("unsafe_destructor_blind_to_params",
      Normal,
      Gated("dropck_parametricity",
@@ -823,31 +818,59 @@ macro_rules! gate_feature_post {
 impl<'a> PostExpansionVisitor<'a> {
     fn check_abi(&self, abi: Abi, span: Span) {
         match abi {
-            Abi::RustIntrinsic =>
+            Abi::RustIntrinsic => {
                 gate_feature_post!(&self, intrinsics, span,
-                                   "intrinsics are subject to change"),
+                                   "intrinsics are subject to change");
+            },
             Abi::PlatformIntrinsic => {
                 gate_feature_post!(&self, platform_intrinsics, span,
-                                   "platform intrinsics are experimental and possibly buggy")
+                                   "platform intrinsics are experimental and possibly buggy");
             },
             Abi::Vectorcall => {
                 gate_feature_post!(&self, abi_vectorcall, span,
-                                   "vectorcall is experimental and subject to change")
-            }
+                                   "vectorcall is experimental and subject to change");
+            },
             Abi::RustCall => {
                 gate_feature_post!(&self, unboxed_closures, span,
                                    "rust-call ABI is subject to change");
-            }
+            },
+            Abi::SysV64 => {
+                gate_feature_post!(&self, abi_sysv64, span,
+                                   "sysv64 ABI is experimental and subject to change");
+            },
             _ => {}
         }
     }
 }
 
+fn contains_novel_literal(item: &ast::MetaItem) -> bool {
+    use ast::MetaItemKind::*;
+    use ast::NestedMetaItemKind::*;
+
+    match item.node {
+        Word(..) => false,
+        NameValue(_, ref lit) => !lit.node.is_str(),
+        List(_, ref list) => list.iter().any(|li| {
+            match li.node {
+                MetaItem(ref mi) => contains_novel_literal(&**mi),
+                Literal(_) => true,
+            }
+        }),
+    }
+}
+
 impl<'a> Visitor for PostExpansionVisitor<'a> {
     fn visit_attribute(&mut self, attr: &ast::Attribute) {
         if !self.context.cm.span_allows_unstable(attr.span) {
+            // check for gated attributes
             self.context.check_attribute(attr, false);
         }
+
+        if contains_novel_literal(&*(attr.node.value)) {
+            gate_feature_post!(&self, attr_literals, attr.span,
+                               "non-string literals in attributes, or string \
+                               literals in top-level positions, are experimental");
+        }
     }
 
     fn visit_name(&mut self, sp: Span, name: ast::Name) {
@@ -907,7 +930,7 @@ fn visit_item(&mut self, i: &ast::Item) {
                 for attr in &i.attrs {
                     if attr.name() == "repr" {
                         for item in attr.meta_item_list().unwrap_or(&[]) {
-                            if item.name() == "simd" {
+                            if item.check_name("simd") {
                                 gate_feature_post!(&self, repr_simd, i.span,
                                                    "SIMD types are experimental \
                                                     and possibly buggy");
@@ -1059,7 +1082,7 @@ fn visit_fn(&mut self,
                 _node_id: NodeId) {
         // check for const fn declarations
         match fn_kind {
-            FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {
+            FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _) => {
                 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
             }
             _ => {
@@ -1091,7 +1114,7 @@ fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
                 if block.is_none() {
                     self.check_abi(sig.abi, ti.span);
                 }
-                if sig.constness == ast::Constness::Const {
+                if sig.constness.node == ast::Constness::Const {
                     gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
                 }
             }
@@ -1118,7 +1141,7 @@ fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
                                   "associated constants are experimental")
             }
             ast::ImplItemKind::Method(ref sig, _) => {
-                if sig.constness == ast::Constness::Const {
+                if sig.constness.node == ast::Constness::Const {
                     gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
                 }
             }
@@ -1167,13 +1190,14 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> F
             }
             Some(list) => {
                 for mi in list {
-                    let name = if mi.is_word() {
-                                   mi.name()
-                               } else {
-                                   span_err!(span_handler, mi.span, E0556,
-                                             "malformed feature, expected just one word");
-                                   continue
-                               };
+                    let name = if let Some(word) = mi.word() {
+                        word.name()
+                    } else {
+                        span_err!(span_handler, mi.span, E0556,
+                                  "malformed feature, expected just one word");
+                        continue
+                    };
+
                     if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
                         .find(|& &(n, _, _, _)| name == n) {
                         *(setter(&mut features)) = true;
index b257ab98987dc24701760d1ec76301380d39aa1e..7500bfe9caa8035af34db43799ce035458d9ead7 100644 (file)
@@ -47,6 +47,10 @@ fn fold_meta_items(&mut self, meta_items: Vec<P<MetaItem>>) -> Vec<P<MetaItem>>
         noop_fold_meta_items(meta_items, self)
     }
 
+    fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem {
+        noop_fold_meta_list_item(list_item, self)
+    }
+
     fn fold_meta_item(&mut self, meta_item: P<MetaItem>) -> P<MetaItem> {
         noop_fold_meta_item(meta_item, self)
     }
@@ -307,18 +311,10 @@ pub fn noop_fold_view_path<T: Folder>(view_path: P<ViewPath>, fld: &mut T) -> P<
                 ViewPathList(fld.fold_path(path),
                              path_list_idents.move_map(|path_list_ident| {
                                 Spanned {
-                                    node: match path_list_ident.node {
-                                        PathListItemKind::Ident { id, name, rename } =>
-                                            PathListItemKind::Ident {
-                                                id: fld.new_id(id),
-                                                rename: rename,
-                                                name: name
-                                            },
-                                        PathListItemKind::Mod { id, rename } =>
-                                            PathListItemKind::Mod {
-                                                id: fld.new_id(id),
-                                                rename: rename
-                                            }
+                                    node: PathListItem_ {
+                                        id: fld.new_id(path_list_ident.node.id),
+                                        rename: path_list_ident.node.rename,
+                                        name: path_list_ident.node.name,
                                     },
                                     span: fld.new_span(path_list_ident.span)
                                 }
@@ -513,12 +509,25 @@ pub fn noop_fold_mac<T: Folder>(Spanned {node, span}: Mac, fld: &mut T) -> Mac {
     }
 }
 
+pub fn noop_fold_meta_list_item<T: Folder>(li: NestedMetaItem, fld: &mut T)
+    -> NestedMetaItem {
+    Spanned {
+        node: match li.node {
+            NestedMetaItemKind::MetaItem(mi) =>  {
+                NestedMetaItemKind::MetaItem(fld.fold_meta_item(mi))
+            },
+            NestedMetaItemKind::Literal(lit) => NestedMetaItemKind::Literal(lit)
+        },
+        span: fld.new_span(li.span)
+    }
+}
+
 pub fn noop_fold_meta_item<T: Folder>(mi: P<MetaItem>, fld: &mut T) -> P<MetaItem> {
     mi.map(|Spanned {node, span}| Spanned {
         node: match node {
             MetaItemKind::Word(id) => MetaItemKind::Word(id),
             MetaItemKind::List(id, mis) => {
-                MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_item(e)))
+                MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_list_item(e)))
             }
             MetaItemKind::NameValue(id, s) => MetaItemKind::NameValue(id, s)
         },
@@ -698,12 +707,13 @@ pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: Option<Lifetime>, fld: &mut T)
     o_lt.map(|lt| fld.fold_lifetime(lt))
 }
 
-pub fn noop_fold_generics<T: Folder>(Generics {ty_params, lifetimes, where_clause}: Generics,
+pub fn noop_fold_generics<T: Folder>(Generics {ty_params, lifetimes, where_clause, span}: Generics,
                                      fld: &mut T) -> Generics {
     Generics {
         ty_params: fld.fold_ty_params(ty_params),
         lifetimes: fld.fold_lifetime_defs(lifetimes),
         where_clause: fld.fold_where_clause(where_clause),
+        span: fld.new_span(span),
     }
 }
 
@@ -875,6 +885,10 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
             let struct_def = folder.fold_variant_data(struct_def);
             ItemKind::Struct(struct_def, folder.fold_generics(generics))
         }
+        ItemKind::Union(struct_def, generics) => {
+            let struct_def = folder.fold_variant_data(struct_def);
+            ItemKind::Union(struct_def, folder.fold_generics(generics))
+        }
         ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
             ItemKind::DefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone()))
         }
index b4311fc007d3db1b72cfbf05ddb9ca87fc922b71..65bc9f34c9061ed55d5074cc5d4024d647b62b4f 100644 (file)
@@ -26,7 +26,6 @@
 
 #![feature(associated_consts)]
 #![feature(const_fn)]
-#![feature(filling_drop)]
 #![feature(libc)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
index 2ae3236cd5aa72f818d353cf3e6aa75c722cc255..27dd055cd3ae7431ce46e5651c26cf9e98e24d04 100644 (file)
@@ -193,9 +193,26 @@ pub fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
         Ok(attrs)
     }
 
-    /// matches meta_item = IDENT
-    /// | IDENT = lit
-    /// | IDENT meta_seq
+    fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
+        let lit = self.parse_lit()?;
+        debug!("Checking if {:?} is unusuffixed.", lit);
+
+        if !lit.node.is_unsuffixed() {
+            let msg = "suffixed literals are not allowed in attributes";
+            self.diagnostic().struct_span_err(lit.span, msg)
+                             .help("instead of using a suffixed literal \
+                                    (1u8, 1.0f32, etc.), use an unsuffixed version \
+                                    (1, 1.0, etc.).")
+                             .emit()
+        }
+
+        Ok(lit)
+    }
+
+    /// Per RFC#1559, matches the following grammar:
+    ///
+    /// meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
+    /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
     pub fn parse_meta_item(&mut self) -> PResult<'a, P<ast::MetaItem>> {
         let nt_meta = match self.token {
             token::Interpolated(token::NtMeta(ref e)) => Some(e.clone()),
@@ -213,16 +230,7 @@ pub fn parse_meta_item(&mut self) -> PResult<'a, P<ast::MetaItem>> {
         match self.token {
             token::Eq => {
                 self.bump();
-                let lit = self.parse_lit()?;
-                // FIXME #623 Non-string meta items are not serialized correctly;
-                // just forbid them for now
-                match lit.node {
-                    ast::LitKind::Str(..) => {}
-                    _ => {
-                        self.span_err(lit.span,
-                                      "non-string literals are not allowed in meta-items");
-                    }
-                }
+                let lit = self.parse_unsuffixed_lit()?;
                 let hi = self.span.hi;
                 Ok(P(spanned(lo, hi, ast::MetaItemKind::NameValue(name, lit))))
             }
@@ -238,11 +246,35 @@ pub fn parse_meta_item(&mut self) -> PResult<'a, P<ast::MetaItem>> {
         }
     }
 
-    /// matches meta_seq = ( COMMASEP(meta_item) )
-    fn parse_meta_seq(&mut self) -> PResult<'a, Vec<P<ast::MetaItem>>> {
+    /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;
+    fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
+        let sp = self.span;
+        let lo = self.span.lo;
+
+        match self.parse_unsuffixed_lit() {
+            Ok(lit) => {
+                return Ok(spanned(lo, self.span.hi, ast::NestedMetaItemKind::Literal(lit)))
+            }
+            Err(ref mut err) => self.diagnostic().cancel(err)
+        }
+
+        match self.parse_meta_item() {
+            Ok(mi) => {
+                return Ok(spanned(lo, self.span.hi, ast::NestedMetaItemKind::MetaItem(mi)))
+            }
+            Err(ref mut err) => self.diagnostic().cancel(err)
+        }
+
+        let found = self.this_token_to_string();
+        let msg = format!("expected unsuffixed literal or identifier, found {}", found);
+        Err(self.diagnostic().struct_span_err(sp, &msg))
+    }
+
+    /// matches meta_seq = ( COMMASEP(meta_item_inner) )
+    fn parse_meta_seq(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
         self.parse_unspanned_seq(&token::OpenDelim(token::Paren),
                                  &token::CloseDelim(token::Paren),
                                  SeqSep::trailing_allowed(token::Comma),
-                                 |p: &mut Parser<'a>| p.parse_meta_item())
+                                 |p: &mut Parser<'a>| p.parse_meta_item_inner())
     }
 }
index cd1fdcfe9d130ce94a4e428a9c6d1255222c8190..af95e44a567bab9245e182d726026e9f55ecd280 100644 (file)
@@ -674,11 +674,11 @@ pub fn integer_lit(s: &str,
 mod tests {
     use super::*;
     use std::rc::Rc;
-    use syntax_pos::{Span, BytePos, Pos, NO_EXPANSION};
+    use syntax_pos::{self, Span, BytePos, Pos, NO_EXPANSION};
     use codemap::Spanned;
     use ast::{self, PatKind};
     use abi::Abi;
-    use attr::{first_attr_value_str_by_name, AttrMetaMethods};
+    use attr::first_attr_value_str_by_name;
     use parse;
     use parse::parser::Parser;
     use parse::token::{str_to_ident};
@@ -937,7 +937,10 @@ fn parser_done(p: Parser){
                                 variadic: false
                             }),
                                     ast::Unsafety::Normal,
-                                    ast::Constness::NotConst,
+                                    Spanned {
+                                        span: sp(0,2),
+                                        node: ast::Constness::NotConst,
+                                    },
                                     Abi::Rust,
                                     ast::Generics{ // no idea on either of these:
                                         lifetimes: Vec::new(),
@@ -945,7 +948,8 @@ fn parser_done(p: Parser){
                                         where_clause: ast::WhereClause {
                                             id: ast::DUMMY_NODE_ID,
                                             predicates: Vec::new(),
-                                        }
+                                        },
+                                        span: syntax_pos::DUMMY_SP,
                                     },
                                     P(ast::Block {
                                         stmts: vec!(ast::Stmt {
index 126e8816d055924d3faf250ed32a4c840efdc68f..92ec0fdb3de3160cfd90caa9686dffe109897f38 100644 (file)
@@ -39,7 +39,7 @@
 use ast::{Visibility, WhereClause};
 use ast::{BinOpKind, UnOp};
 use ast;
-use codemap::{self, CodeMap, Spanned, spanned};
+use codemap::{self, CodeMap, Spanned, spanned, respan};
 use syntax_pos::{self, Span, BytePos, mk_sp};
 use errors::{self, DiagnosticBuilder};
 use ext::tt::macro_parser;
@@ -520,12 +520,21 @@ pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> {
                 self.bug("ident interpolation not converted to real token");
             }
             _ => {
-                let mut err = self.fatal(&format!("expected identifier, found `{}`",
-                                                  self.this_token_to_string()));
-                if self.token == token::Underscore {
-                    err.note("`_` is a wildcard pattern, not an identifier");
-                }
-                Err(err)
+                let last_token = self.last_token.clone().map(|t| *t);
+                Err(match last_token {
+                    Some(token::DocComment(_)) => self.span_fatal_help(self.last_span,
+                        "found a documentation comment that doesn't document anything",
+                        "doc comments must come before what they document, maybe a comment was \
+                        intended with `//`?"),
+                    _ => {
+                        let mut err = self.fatal(&format!("expected identifier, found `{}`",
+                                                          self.this_token_to_string()));
+                        if self.token == token::Underscore {
+                            err.note("`_` is a wildcard pattern, not an identifier");
+                        }
+                        err
+                    }
+                })
             }
         }
     }
@@ -716,8 +725,8 @@ pub fn expect_gt(&mut self) -> PResult<'a, ()> {
                 let gt_str = Parser::token_to_string(&token::Gt);
                 let this_token_str = self.this_token_to_string();
                 Err(self.fatal(&format!("expected `{}`, found `{}`",
-                                   gt_str,
-                                   this_token_str)))
+                                        gt_str,
+                                        this_token_str)))
             }
         }
     }
@@ -927,6 +936,7 @@ pub fn bump(&mut self) {
         // Stash token for error recovery (sometimes; clone is not necessarily cheap).
         self.last_token = if self.token.is_ident() ||
                           self.token.is_path() ||
+                          self.token.is_doc_comment() ||
                           self.token == token::Comma {
             Some(Box::new(self.token.clone()))
         } else {
@@ -1018,6 +1028,11 @@ pub fn span_warn(&self, sp: Span, m: &str) {
     pub fn span_err(&self, sp: Span, m: &str) {
         self.sess.span_diagnostic.span_err(sp, m)
     }
+    pub fn span_err_help(&self, sp: Span, m: &str, h: &str) {
+        let mut err = self.sess.span_diagnostic.mut_span_err(sp, m);
+        err.help(h);
+        err.emit();
+    }
     pub fn span_bug(&self, sp: Span, m: &str) -> ! {
         self.sess.span_diagnostic.span_bug(sp, m)
     }
@@ -4021,8 +4036,14 @@ fn parse_stmt_without_recovery(&mut self, macro_expanded: bool) -> PResult<'a, O
                 None => {
                     let unused_attrs = |attrs: &[_], s: &mut Self| {
                         if attrs.len() > 0 {
-                            s.span_err(s.span,
-                                "expected statement after outer attribute");
+                            let last_token = s.last_token.clone().map(|t| *t);
+                            match last_token {
+                                Some(token::DocComment(_)) => s.span_err_help(s.last_span,
+                                    "found a documentation comment that doesn't document anything",
+                                    "doc comments must come before what they document, maybe a \
+                                    comment was intended with `//`?"),
+                                _ => s.span_err(s.span, "expected statement after outer attribute"),
+                            }
                         }
                     };
 
@@ -4066,9 +4087,30 @@ pub fn parse_block(&mut self) -> PResult<'a, P<Block>> {
         if !self.eat(&token::OpenDelim(token::Brace)) {
             let sp = self.span;
             let tok = self.this_token_to_string();
-            return Err(self.span_fatal_help(sp,
-                                 &format!("expected `{{`, found `{}`", tok),
-                                 "place this code inside a block"));
+            let mut e = self.span_fatal(sp, &format!("expected `{{`, found `{}`", tok));
+
+            // Check to see if the user has written something like
+            //
+            //    if (cond)
+            //      bar;
+            //
+            // Which is valid in other languages, but not Rust.
+            match self.parse_stmt_without_recovery(false) {
+                Ok(Some(stmt)) => {
+                    let mut stmt_span = stmt.span;
+                    // expand the span to include the semicolon, if it exists
+                    if self.eat(&token::Semi) {
+                        stmt_span.hi = self.last_span.hi;
+                    }
+                    e.span_help(stmt_span, "try placing this code inside a block");
+                }
+                Err(mut e) => {
+                    self.recover_stmt_(SemiColonMode::Break);
+                    e.cancel();
+                }
+                _ => ()
+            }
+            return Err(e);
         }
 
         self.parse_block_tail(lo, BlockCheckMode::Default)
@@ -4251,6 +4293,7 @@ fn parse_ty_param(&mut self) -> PResult<'a, TyParam> {
     /// where   typaramseq = ( typaram ) | ( typaram , typaramseq )
     pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
         maybe_whole!(self, NtGenerics);
+        let span_lo = self.span.lo;
 
         if self.eat(&token::Lt) {
             let lifetime_defs = self.parse_lifetime_defs()?;
@@ -4273,7 +4316,8 @@ pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
                 where_clause: WhereClause {
                     id: ast::DUMMY_NODE_ID,
                     predicates: Vec::new(),
-                }
+                },
+                span: mk_sp(span_lo, self.last_span.hi),
             })
         } else {
             Ok(ast::Generics::default())
@@ -4726,7 +4770,7 @@ fn mk_item(&mut self, lo: BytePos, hi: BytePos, ident: Ident,
     /// Parse an item-position function declaration.
     fn parse_item_fn(&mut self,
                      unsafety: Unsafety,
-                     constness: Constness,
+                     constness: Spanned<Constness>,
                      abi: abi::Abi)
                      -> PResult<'a, ItemInfo> {
         let (ident, mut generics) = self.parse_fn_header()?;
@@ -4752,18 +4796,21 @@ pub fn is_const_item(&mut self) -> bool {
     /// - `extern fn`
     /// - etc
     pub fn parse_fn_front_matter(&mut self)
-                                 -> PResult<'a, (ast::Constness, ast::Unsafety, abi::Abi)> {
+                                 -> PResult<'a, (Spanned<ast::Constness>,
+                                                ast::Unsafety,
+                                                abi::Abi)> {
         let is_const_fn = self.eat_keyword(keywords::Const);
+        let const_span = self.last_span;
         let unsafety = self.parse_unsafety()?;
         let (constness, unsafety, abi) = if is_const_fn {
-            (Constness::Const, unsafety, Abi::Rust)
+            (respan(const_span, Constness::Const), unsafety, Abi::Rust)
         } else {
             let abi = if self.eat_keyword(keywords::Extern) {
                 self.parse_opt_abi()?.unwrap_or(Abi::C)
             } else {
                 Abi::Rust
             };
-            (Constness::NotConst, unsafety, abi)
+            (respan(self.last_span, Constness::NotConst), unsafety, abi)
         };
         self.expect_keyword(keywords::Fn)?;
         Ok((constness, unsafety, abi))
@@ -5127,14 +5174,13 @@ pub fn parse_single_struct_field(&mut self,
                 self.bump();
             }
             token::CloseDelim(token::Brace) => {}
-            _ => {
-                let span = self.span;
-                let token_str = self.this_token_to_string();
-                return Err(self.span_fatal_help(span,
-                                     &format!("expected `,`, or `}}`, found `{}`",
-                                             token_str),
-                                     "struct fields should be separated by commas"))
-            }
+            token::DocComment(_) => return Err(self.span_fatal_help(self.span,
+                        "found a documentation comment that doesn't document anything",
+                        "doc comments must come before what they document, maybe a comment was \
+                        intended with `//`?")),
+            _ => return Err(self.span_fatal_help(self.span,
+                    &format!("expected `,`, or `}}`, found `{}`", self.this_token_to_string()),
+                    "struct fields should be separated by commas")),
         }
         Ok(a_var)
     }
@@ -5663,9 +5709,12 @@ fn parse_item_(&mut self, attrs: Vec<Attribute>,
 
             if self.eat_keyword(keywords::Fn) {
                 // EXTERN FUNCTION ITEM
+                let fn_span = self.last_span;
                 let abi = opt_abi.unwrap_or(Abi::C);
                 let (ident, item_, extra_attrs) =
-                    self.parse_item_fn(Unsafety::Normal, Constness::NotConst, abi)?;
+                    self.parse_item_fn(Unsafety::Normal,
+                                       respan(fn_span, Constness::NotConst),
+                                       abi)?;
                 let last_span = self.last_span;
                 let item = self.mk_item(lo,
                                         last_span.hi,
@@ -5699,6 +5748,7 @@ fn parse_item_(&mut self, attrs: Vec<Attribute>,
             return Ok(Some(item));
         }
         if self.eat_keyword(keywords::Const) {
+            let const_span = self.last_span;
             if self.check_keyword(keywords::Fn)
                 || (self.check_keyword(keywords::Unsafe)
                     && self.look_ahead(1, |t| t.is_keyword(keywords::Fn))) {
@@ -5710,7 +5760,9 @@ fn parse_item_(&mut self, attrs: Vec<Attribute>,
                 };
                 self.bump();
                 let (ident, item_, extra_attrs) =
-                    self.parse_item_fn(unsafety, Constness::Const, Abi::Rust)?;
+                    self.parse_item_fn(unsafety,
+                                       respan(const_span, Constness::Const),
+                                       Abi::Rust)?;
                 let last_span = self.last_span;
                 let item = self.mk_item(lo,
                                         last_span.hi,
@@ -5774,8 +5826,11 @@ fn parse_item_(&mut self, attrs: Vec<Attribute>,
         if self.check_keyword(keywords::Fn) {
             // FUNCTION ITEM
             self.bump();
+            let fn_span = self.last_span;
             let (ident, item_, extra_attrs) =
-                self.parse_item_fn(Unsafety::Normal, Constness::NotConst, Abi::Rust)?;
+                self.parse_item_fn(Unsafety::Normal,
+                                   respan(fn_span, Constness::NotConst),
+                                   Abi::Rust)?;
             let last_span = self.last_span;
             let item = self.mk_item(lo,
                                     last_span.hi,
@@ -5795,8 +5850,11 @@ fn parse_item_(&mut self, attrs: Vec<Attribute>,
                 Abi::Rust
             };
             self.expect_keyword(keywords::Fn)?;
+            let fn_span = self.last_span;
             let (ident, item_, extra_attrs) =
-                self.parse_item_fn(Unsafety::Unsafe, Constness::NotConst, abi)?;
+                self.parse_item_fn(Unsafety::Unsafe,
+                                   respan(fn_span, Constness::NotConst),
+                                   abi)?;
             let last_span = self.last_span;
             let item = self.mk_item(lo,
                                     last_span.hi,
@@ -5997,13 +6055,16 @@ fn parse_path_list_items(&mut self) -> PResult<'a, Vec<ast::PathListItem>> {
                                  &token::CloseDelim(token::Brace),
                                  SeqSep::trailing_allowed(token::Comma), |this| {
             let lo = this.span.lo;
-            let node = if this.eat_keyword(keywords::SelfValue) {
-                let rename = this.parse_rename()?;
-                ast::PathListItemKind::Mod { id: ast::DUMMY_NODE_ID, rename: rename }
+            let ident = if this.eat_keyword(keywords::SelfValue) {
+                keywords::SelfValue.ident()
             } else {
-                let ident = this.parse_ident()?;
-                let rename = this.parse_rename()?;
-                ast::PathListItemKind::Ident { name: ident, rename: rename, id: ast::DUMMY_NODE_ID }
+                this.parse_ident()?
+            };
+            let rename = this.parse_rename()?;
+            let node = ast::PathListItem_ {
+                name: ident,
+                rename: rename,
+                id: ast::DUMMY_NODE_ID
             };
             let hi = this.last_span.hi;
             Ok(spanned(lo, hi, node))
index 6fdc9b714d34724202173d5417087ba1ea0bd4f3..dc0fb02ea45d9dc32dee323fa114dcb620313b0c 100644 (file)
@@ -203,7 +203,7 @@ pub fn can_begin_expr(&self) -> bool {
     pub fn is_lit(&self) -> bool {
         match *self {
             Literal(_, _) => true,
-            _          => false,
+            _             => false,
         }
     }
 
@@ -215,6 +215,14 @@ pub fn is_ident(&self) -> bool {
         }
     }
 
+    /// Returns `true` if the token is a documentation comment.
+    pub fn is_doc_comment(&self) -> bool {
+        match *self {
+            DocComment(..)   => true,
+            _                => false,
+        }
+    }
+
     /// Returns `true` if the token is interpolated.
     pub fn is_interpolated(&self) -> bool {
         match *self {
index a77c678248b565642a31fc5b60851c62ff1a9299..8563d27908db61428405892616fa437fc5948e77 100644 (file)
@@ -16,7 +16,6 @@
 use ast::Attribute;
 use util::parser::AssocOp;
 use attr;
-use attr::{AttrMetaMethods, AttributeMethods};
 use codemap::{self, CodeMap};
 use syntax_pos::{self, BytePos};
 use errors;
@@ -120,7 +119,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
         // of the feature gate, so we fake them up here.
 
         // #![feature(prelude_import)]
-        let prelude_import_meta = attr::mk_word_item(InternedString::new("prelude_import"));
+        let prelude_import_meta = attr::mk_list_word_item(InternedString::new("prelude_import"));
         let list = attr::mk_list_item(InternedString::new("feature"),
                                       vec![prelude_import_meta]);
         let fake_attr = attr::mk_attr_inner(attr::mk_attr_id(), list);
@@ -406,6 +405,10 @@ pub fn block_to_string(blk: &ast::Block) -> String {
     })
 }
 
+pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String {
+    to_string(|s| s.print_meta_list_item(li))
+}
+
 pub fn meta_item_to_string(mi: &ast::MetaItem) -> String {
     to_string(|s| s.print_meta_item(mi))
 }
@@ -764,6 +767,17 @@ fn print_attribute_inline(&mut self, attr: &ast::Attribute,
         }
     }
 
+    fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) -> io::Result<()> {
+        match item.node {
+            ast::NestedMetaItemKind::MetaItem(ref mi) => {
+                self.print_meta_item(mi)
+            },
+            ast::NestedMetaItemKind::Literal(ref lit) => {
+                self.print_literal(lit)
+            }
+        }
+    }
+
     fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> {
         try!(self.ibox(INDENT_UNIT));
         match item.node {
@@ -780,7 +794,7 @@ fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> {
                 try!(self.popen());
                 try!(self.commasep(Consistent,
                               &items[..],
-                              |s, i| s.print_meta_item(&i)));
+                              |s, i| s.print_meta_list_item(&i)));
                 try!(self.pclose());
             }
         }
@@ -1001,6 +1015,7 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> io::Result<()> {
                         id: ast::DUMMY_NODE_ID,
                         predicates: Vec::new(),
                     },
+                    span: syntax_pos::DUMMY_SP,
                 };
                 try!(self.print_ty_fn(f.abi,
                                  f.unsafety,
@@ -1184,7 +1199,7 @@ pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
                 try!(self.print_fn(
                     decl,
                     unsafety,
-                    constness,
+                    constness.node,
                     abi,
                     Some(item.ident),
                     typarams,
@@ -1236,7 +1251,10 @@ pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
                 try!(self.head(&visibility_qualified(&item.vis, "struct")));
                 try!(self.print_struct(&struct_def, generics, item.ident, item.span, true));
             }
-
+            ast::ItemKind::Union(ref struct_def, ref generics) => {
+                try!(self.head(&visibility_qualified(&item.vis, "union")));
+                try!(self.print_struct(&struct_def, generics, item.ident, item.span, true));
+            }
             ast::ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
                 try!(self.head(""));
                 try!(self.print_visibility(&item.vis));
@@ -1518,7 +1536,7 @@ pub fn print_method_sig(&mut self,
                             -> io::Result<()> {
         self.print_fn(&m.decl,
                       m.unsafety,
-                      m.constness,
+                      m.constness.node,
                       m.abi,
                       Some(ident),
                       &m.generics,
@@ -2878,26 +2896,13 @@ pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> io::Result<()> {
                     try!(word(&mut self.s, "::{"));
                 }
                 try!(self.commasep(Inconsistent, &idents[..], |s, w| {
-                    match w.node {
-                        ast::PathListItemKind::Ident { name, rename, .. } => {
-                            try!(s.print_ident(name));
-                            if let Some(ident) = rename {
-                                try!(space(&mut s.s));
-                                try!(s.word_space("as"));
-                                try!(s.print_ident(ident));
-                            }
-                            Ok(())
-                        },
-                        ast::PathListItemKind::Mod { rename, .. } => {
-                            try!(word(&mut s.s, "self"));
-                            if let Some(ident) = rename {
-                                try!(space(&mut s.s));
-                                try!(s.word_space("as"));
-                                try!(s.print_ident(ident));
-                            }
-                            Ok(())
-                        }
+                    try!(s.print_ident(w.node.name));
+                    if let Some(ident) = w.node.rename {
+                        try!(space(&mut s.s));
+                        try!(s.word_space("as"));
+                        try!(s.print_ident(ident));
                     }
+                    Ok(())
                 }));
                 word(&mut self.s, "}")
             }
@@ -2982,6 +2987,7 @@ pub fn print_ty_fn(&mut self,
                 id: ast::DUMMY_NODE_ID,
                 predicates: Vec::new(),
             },
+            span: syntax_pos::DUMMY_SP,
         };
         try!(self.print_fn(decl,
                       unsafety,
index 9d04cb75daa0e7c3318d804961a89b65ddaf2c85..c3f8a977a659b572a63dc14be1aba96cd6e36975 100644 (file)
@@ -39,7 +39,7 @@
 use std::fmt::{self, Display, Debug};
 use std::iter::FromIterator;
 use std::ops::Deref;
-use std::{ptr, slice, vec};
+use std::{mem, ptr, slice, vec};
 
 use serialize::{Encodable, Decodable, Encoder, Decoder};
 
@@ -74,12 +74,22 @@ pub fn unwrap(self) -> T {
     pub fn map<F>(mut self, f: F) -> P<T> where
         F: FnOnce(T) -> T,
     {
+        let p: *mut T = &mut *self.ptr;
+
+        // Leak self in case of panic.
+        // FIXME(eddyb) Use some sort of "free guard" that
+        // only deallocates, without dropping the pointee,
+        // in case the call the `f` below ends in a panic.
+        mem::forget(self);
+
         unsafe {
-            let p = &mut *self.ptr;
-            // FIXME(#5016) this shouldn't need to drop-fill to be safe.
-            ptr::write(p, f(ptr::read_and_drop(p)));
+            ptr::write(p, f(ptr::read(p)));
+
+            // Recreate self from the raw pointer.
+            P {
+                ptr: Box::from_raw(p)
+            }
         }
-        self
     }
 }
 
index faf6a17a150459fb62cd380b952340d5b90b12d5..6155ad729a2893d5ebcf976411947bda8741ccbc 100644 (file)
 use std::slice;
 use std::mem;
 use std::vec;
-use attr::AttrMetaMethods;
 use attr;
 use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos};
 use std::rc::Rc;
 
-use codemap::{self, CodeMap, ExpnInfo, NameAndSpan, MacroAttribute};
+use codemap::{self, CodeMap, ExpnInfo, NameAndSpan, MacroAttribute, dummy_spanned};
 use errors;
 use errors::snippet::{SnippetData};
 use config;
@@ -210,9 +209,8 @@ fn fold_item(&mut self, i: P<ast::Item>) -> SmallVector<P<ast::Item>> {
                 folded.map(|ast::Item {id, ident, attrs, node, vis, span}| {
                     let allow_str = InternedString::new("allow");
                     let dead_code_str = InternedString::new("dead_code");
-                    let allow_dead_code_item =
-                        attr::mk_list_item(allow_str,
-                                           vec![attr::mk_word_item(dead_code_str)]);
+                    let word_vec = vec![attr::mk_list_word_item(dead_code_str)];
+                    let allow_dead_code_item = attr::mk_list_item(allow_str, word_vec);
                     let allow_dead_code = attr::mk_attr_outer(attr::mk_attr_id(),
                                                               allow_dead_code_item);
 
@@ -413,6 +411,7 @@ fn should_panic(i: &ast::Item) -> ShouldPanic {
         Some(attr) => {
             let msg = attr.meta_item_list()
                 .and_then(|list| list.iter().find(|mi| mi.check_name("expected")))
+                .and_then(|li| li.meta_item())
                 .and_then(|mi| mi.value_str());
             ShouldPanic::Yes(msg)
         }
@@ -485,7 +484,7 @@ fn mk_main(cx: &mut TestCtxt) -> P<ast::Item> {
     let main_body = ecx.block(sp, vec![call_test_main]);
     let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], main_ret_ty),
                            ast::Unsafety::Normal,
-                           ast::Constness::NotConst,
+                           dummy_spanned(ast::Constness::NotConst),
                            ::abi::Abi::Rust, ast::Generics::default(), main_body);
     let main = P(ast::Item {
         ident: token::str_to_ident("main"),
index 582412119caa875923f6d41e6ad34c40829547e1..efd9b027504f0a5fa0acf8ae4079f31c210b4e60 100644 (file)
@@ -31,7 +31,7 @@
 #[derive(Copy, Clone, PartialEq, Eq)]
 pub enum FnKind<'a> {
     /// fn foo() or extern "Abi" fn foo()
-    ItemFn(Ident, &'a Generics, Unsafety, Constness, Abi, &'a Visibility),
+    ItemFn(Ident, &'a Generics, Unsafety, Spanned<Constness>, Abi, &'a Visibility),
 
     /// fn foo(&self)
     Method(Ident, &'a MethodSig, Option<&'a Visibility>),
@@ -278,7 +278,8 @@ pub fn walk_item<V: Visitor>(visitor: &mut V, item: &Item) {
             visitor.visit_ty(typ);
             walk_list!(visitor, visit_impl_item, impl_items);
         }
-        ItemKind::Struct(ref struct_definition, ref generics) => {
+        ItemKind::Struct(ref struct_definition, ref generics) |
+        ItemKind::Union(ref struct_definition, ref generics) => {
             visitor.visit_generics(generics);
             visitor.visit_variant_data(struct_definition, item.ident,
                                      generics, item.id, item.span);
@@ -367,8 +368,8 @@ pub fn walk_path<V: Visitor>(visitor: &mut V, path: &Path) {
 }
 
 pub fn walk_path_list_item<V: Visitor>(visitor: &mut V, _prefix: &Path, item: &PathListItem) {
-    walk_opt_ident(visitor, item.span, item.node.name());
-    walk_opt_ident(visitor, item.span, item.node.rename());
+    visitor.visit_ident(item.span, item.node.name);
+    walk_opt_ident(visitor, item.span, item.node.rename);
 }
 
 pub fn walk_path_segment<V: Visitor>(visitor: &mut V, path_span: Span, segment: &PathSegment) {
index cfc98bf36871f5d78353ff9903ba8ee4c6ba5fdf..efb2fe5eb3b0feb5b627c1ac991f02979e03b116 100644 (file)
@@ -40,6 +40,7 @@ pub fn expand_deriving_copy(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: true,
         methods: Vec::new(),
         associated_types: Vec::new(),
     };
index ce8ce2209d8c4513038fb21f84780c7aa870537d..f1a3a1f41b14ee37cb4b7ed025700f99112ca1e1 100644 (file)
@@ -80,6 +80,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
         additional_bounds: bounds,
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![MethodDef {
                           name: "clone",
                           generics: LifetimeBounds::empty(),
index 2ab0f0ff54669c40e94e3fa0cd99f734ae672fdb..425a47a991bc4dc552eb5f56f0fa579bd44050f8 100644 (file)
@@ -40,7 +40,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<
     }
 
     let inline = cx.meta_word(span, InternedString::new("inline"));
-    let hidden = cx.meta_word(span, InternedString::new("hidden"));
+    let hidden = cx.meta_list_item_word(span, InternedString::new("hidden"));
     let doc = cx.meta_list(span, InternedString::new("doc"), vec![hidden]);
     let attrs = vec![cx.attribute(span, inline), cx.attribute(span, doc)];
     let trait_def = TraitDef {
@@ -50,6 +50,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![MethodDef {
                           name: "assert_receiver_is_total_eq",
                           generics: LifetimeBounds::empty(),
index 8ae77e79310b2805886363bbf7c23b2b50a35d32..6b2e36e63b65708d5152098d517405b075de9cea 100644 (file)
@@ -32,6 +32,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![MethodDef {
                           name: "cmp",
                           generics: LifetimeBounds::empty(),
@@ -104,7 +105,7 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
         };
 
         let eq_arm = cx.arm(span,
-                            vec![cx.pat_enum(span, equals_path.clone(), vec![])],
+                            vec![cx.pat_path(span, equals_path.clone())],
                             old);
         let neq_arm = cx.arm(span,
                              vec![cx.pat_ident(span, test_id)],
index f70e0cf4ac45768048ff1070b605372a9cd20959..64b8829dad7b1e5eb9f248a450c821580ee40a36 100644 (file)
@@ -97,6 +97,7 @@ macro_rules! md {
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: methods,
         associated_types: Vec::new(),
     };
index 10a9738742e4486c470f6e531eee3b1c9cefd89f..99d60c43c5457deec8b75c111a56a83acb0d5233 100644 (file)
@@ -88,6 +88,7 @@ macro_rules! md {
         additional_bounds: vec![],
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: methods,
         associated_types: Vec::new(),
     };
@@ -165,7 +166,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<
         };
 
         let eq_arm = cx.arm(span,
-                            vec![cx.pat_some(span, cx.pat_enum(span, ordering.clone(), vec![]))],
+                            vec![cx.pat_some(span, cx.pat_path(span, ordering.clone()))],
                             old);
         let neq_arm = cx.arm(span,
                              vec![cx.pat_ident(span, test_id)],
index a31c695e360490e7e6077f4ce995c3514f028d6a..b974699003b974b3dfec586fc4863b5a53b18518 100644 (file)
@@ -35,6 +35,7 @@ pub fn expand_deriving_debug(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![MethodDef {
                           name: "fmt",
                           generics: LifetimeBounds::empty(),
index 9a332227053c7bab3576145baf8b5c0eca153fe9..22b9eb8e754453ea44d56f3669c8fbf1371e8c71 100644 (file)
@@ -62,6 +62,7 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![MethodDef {
                           name: "decode",
                           generics: LifetimeBounds {
@@ -110,7 +111,7 @@ fn decodable_substructure(cx: &mut ExtCtxt,
     return match *substr.fields {
         StaticStruct(_, ref summary) => {
             let nfields = match *summary {
-                Unnamed(ref fields) => fields.len(),
+                Unnamed(ref fields, _) => fields.len(),
                 Named(ref fields) => fields.len(),
             };
             let read_struct_field = cx.ident_of("read_struct_field");
@@ -193,9 +194,9 @@ fn decode_static_fields<F>(cx: &mut ExtCtxt,
     where F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P<Expr>
 {
     match *fields {
-        Unnamed(ref fields) => {
+        Unnamed(ref fields, is_tuple) => {
             let path_expr = cx.expr_path(outer_pat_path);
-            if fields.is_empty() {
+            if !is_tuple {
                 path_expr
             } else {
                 let fields = fields.iter()
index 9df3db938b1f918fba8649a251f19ff34aa2511e..b15fd2b49a65547c241ed463f0c5a55767754f71 100644 (file)
@@ -32,6 +32,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![MethodDef {
                           name: "default",
                           generics: LifetimeBounds::empty(),
@@ -57,8 +58,8 @@ fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructur
     return match *substr.fields {
         StaticStruct(_, ref summary) => {
             match *summary {
-                Unnamed(ref fields) => {
-                    if fields.is_empty() {
+                Unnamed(ref fields, is_tuple) => {
+                    if !is_tuple {
                         cx.expr_ident(trait_span, substr.type_ident)
                     } else {
                         let exprs = fields.iter().map(|sp| default_call(*sp)).collect();
index 940fdf037711ffac788171a8c8a30423744bd04e..a4074184b6e81ce7275f1af8a5367b2787712f03 100644 (file)
@@ -138,6 +138,7 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec!(
             MethodDef {
                 name: "encode",
index cd49e7ec9d2c6764ce98c42a3bd270eace612025..5c636d43a71421c7a7d188f5ddcf14e4c9b08757 100644 (file)
 use syntax::abi::Abi;
 use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind, VariantData};
 use syntax::attr;
-use syntax::attr::AttrMetaMethods;
 use syntax::ext::base::{Annotatable, ExtCtxt};
 use syntax::ext::build::AstBuilder;
-use syntax::codemap::{self, respan};
+use syntax::codemap::{self, dummy_spanned, respan};
 use syntax::util::move_map::MoveMap;
 use syntax::parse::token::{InternedString, keywords};
 use syntax::ptr::P;
@@ -229,6 +228,9 @@ pub struct TraitDef<'a> {
     /// Is it an `unsafe` trait?
     pub is_unsafe: bool,
 
+    /// Can this trait be derived for unions?
+    pub supports_unions: bool,
+
     pub methods: Vec<MethodDef<'a>>,
 
     pub associated_types: Vec<(ast::Ident, Ty<'a>)>,
@@ -294,8 +296,8 @@ pub struct FieldInfo<'a> {
 
 /// Fields for a static method
 pub enum StaticFields {
-    /// Tuple structs/enum variants like this.
-    Unnamed(Vec<Span>),
+    /// Tuple and unit structs/enum variants like this.
+    Unnamed(Vec<Span>, bool /*is tuple*/),
     /// Normal structs/struct variants.
     Named(Vec<(Ident, Span)>),
 }
@@ -488,7 +490,7 @@ fn create_derived_impl(&self,
             }
         });
 
-        let Generics { mut lifetimes, ty_params, mut where_clause } = self.generics
+        let Generics { mut lifetimes, ty_params, mut where_clause, span } = self.generics
             .to_generics(cx, self.span, type_ident, generics);
         let mut ty_params = ty_params.into_vec();
 
@@ -590,6 +592,7 @@ fn create_derived_impl(&self,
             lifetimes: lifetimes,
             ty_params: P::from_vec(ty_params),
             where_clause: where_clause,
+            span: span,
         };
 
         // Create the reference to the trait.
@@ -623,7 +626,7 @@ fn create_derived_impl(&self,
         let unused_qual = cx.attribute(self.span,
                                        cx.meta_list(self.span,
                                                     InternedString::new("allow"),
-                                                    vec![cx.meta_word(self.span,
+                                                    vec![cx.meta_list_item_word(self.span,
                                            InternedString::new("unused_qualifications"))]));
         let mut a = vec![attr, unused_qual];
         a.extend(self.attributes.iter().cloned());
@@ -901,7 +904,8 @@ fn create_method(&self,
                                                 generics: fn_generics,
                                                 abi: abi,
                                                 unsafety: unsafety,
-                                                constness: ast::Constness::NotConst,
+                                                constness:
+                                                    dummy_spanned(ast::Constness::NotConst),
                                                 decl: fn_decl,
                                             },
                                             body_block),
@@ -1470,7 +1474,7 @@ fn summarise_struct(&self, cx: &mut ExtCtxt, struct_def: &VariantData) -> Static
             (_, false) => Named(named_idents),
             // empty structs
             _ if struct_def.is_struct() => Named(named_idents),
-            _ => Unnamed(just_spans),
+            _ => Unnamed(just_spans, struct_def.is_tuple()),
         }
     }
 
@@ -1510,26 +1514,32 @@ fn create_struct_pattern
         }
 
         let subpats = self.create_subpatterns(cx, paths, mutbl);
-        let pattern = if struct_def.is_struct() {
-            let field_pats = subpats.into_iter()
-                .zip(&ident_exprs)
-                .map(|(pat, &(sp, ident, _, _))| {
-                    if ident.is_none() {
-                        cx.span_bug(sp, "a braced struct with unnamed fields in `derive`");
-                    }
-                    codemap::Spanned {
-                        span: pat.span,
-                        node: ast::FieldPat {
-                            ident: ident.unwrap(),
-                            pat: pat,
-                            is_shorthand: false,
-                        },
-                    }
-                })
-                .collect();
-            cx.pat_struct(self.span, struct_path, field_pats)
-        } else {
-            cx.pat_enum(self.span, struct_path, subpats)
+        let pattern = match *struct_def {
+            VariantData::Struct(..) => {
+                let field_pats = subpats.into_iter()
+                    .zip(&ident_exprs)
+                    .map(|(pat, &(sp, ident, _, _))| {
+                        if ident.is_none() {
+                            cx.span_bug(sp, "a braced struct with unnamed fields in `derive`");
+                        }
+                        codemap::Spanned {
+                            span: pat.span,
+                            node: ast::FieldPat {
+                                ident: ident.unwrap(),
+                                pat: pat,
+                                is_shorthand: false,
+                            },
+                        }
+                    })
+                    .collect();
+                cx.pat_struct(self.span, struct_path, field_pats)
+            }
+            VariantData::Tuple(..) => {
+                cx.pat_tuple_struct(self.span, struct_path, subpats)
+            }
+            VariantData::Unit(..) => {
+                cx.pat_path(self.span, struct_path)
+            }
         };
 
         (pattern, ident_exprs)
index 356c54fcf31202299bac568cee529e21d418f536..210878b7c9f0e09d3d62d1052cc967514bcece27 100644 (file)
@@ -207,7 +207,8 @@ fn mk_ty_param(cx: &ExtCtxt,
     cx.typaram(span, cx.ident_of(name), bounds, None)
 }
 
-fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>) -> Generics {
+fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>, span: Span)
+               -> Generics {
     Generics {
         lifetimes: lifetimes,
         ty_params: P::from_vec(ty_params),
@@ -215,6 +216,7 @@ fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>) -
             id: ast::DUMMY_NODE_ID,
             predicates: Vec::new(),
         },
+        span: span,
     }
 }
 
@@ -257,7 +259,7 @@ pub fn to_generics(&self,
                 }
             })
             .collect();
-        mk_generics(lifetimes, ty_params)
+        mk_generics(lifetimes, ty_params, span)
     }
 }
 
index 81c8e7112dbd590d131d29dc9165e6b6a05fb45d..0941ebca868e3207e340ff03d6e6cb9ac7a80aa9 100644 (file)
@@ -36,6 +36,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![MethodDef {
                           name: "hash",
                           generics: LifetimeBounds {
index aee86b246b9852dd61f10337428ea07164a5012e..81085122e875bf47ce8799d51e6478ac171f93aa 100644 (file)
@@ -11,7 +11,6 @@
 //! The compiler code necessary to implement the `#[derive]` extensions.
 
 use syntax::ast::{self, MetaItem};
-use syntax::attr::AttrMetaMethods;
 use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv};
 use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier};
 use syntax::ext::build::AstBuilder;
@@ -98,8 +97,8 @@ fn expand_derive(cx: &mut ExtCtxt,
             let mut eq_span = None;
 
             for titem in traits.iter().rev() {
-                let tname = if titem.is_word() {
-                    titem.name()
+                let tname = if let Some(word) = titem.word() {
+                    word.name()
                 } else {
                     cx.span_err(titem.span, "malformed `derive` entry");
                     continue;
index 0f171805bb0a988fb95853932fa3619b46b37627..b11bbea84abcedfa3e77f15cd85347a3e26e7087 100644 (file)
@@ -221,6 +221,25 @@ pub fn primary_spans(&self) -> &[Span] {
         &self.primary_spans
     }
 
+    /// Replaces all occurances of one Span with another. Used to move Spans in areas that don't
+    /// display well (like std macros). Returns true if replacements occurred.
+    pub fn replace(&mut self, before: Span, after: Span) -> bool {
+        let mut replacements_occurred = false;
+        for primary_span in &mut self.primary_spans {
+            if *primary_span == before {
+                *primary_span = after;
+                replacements_occurred = true;
+            }
+        }
+        for span_label in &mut self.span_labels {
+            if span_label.0 == before {
+                span_label.0 = after;
+                replacements_occurred = true;
+            }
+        }
+        replacements_occurred
+    }
+
     /// Returns the strings to highlight. We always ensure that there
     /// is an entry for each of the primary spans -- for each primary
     /// span P, if there is at least one label with span P, we return
index 850127d9f29505f72f0998f50e584346fd026dbd..2b4193306ddf5d08faa91a464431ef37b6887e01 100644 (file)
@@ -42,7 +42,6 @@
 #![feature(staged_api)]
 #![feature(question_mark)]
 #![feature(panic_unwind)]
-#![feature(mpsc_recv_timeout)]
 
 extern crate getopts;
 extern crate term;
index 680ad3ecd64a6c156cb65fce6d67a90e08be4d8e..8292a68417810064b85b66ec32ded4bf89ac08d1 100644 (file)
@@ -56,6 +56,9 @@ pub enum _Unwind_Reason_Code {
 #[cfg(target_arch = "mips")]
 pub const unwinder_private_data_size: usize = 2;
 
+#[cfg(target_arch = "mips64")]
+pub const unwinder_private_data_size: usize = 2;
+
 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
 pub const unwinder_private_data_size: usize = 2;
 
index 786aad117be48547f4ca50fae84c4879fa992d4d..eee68eafa7e8e4ce996b49f5551636639a6c331a 160000 (submodule)
--- a/src/llvm
+++ b/src/llvm
@@ -1 +1 @@
-Subproject commit 786aad117be48547f4ca50fae84c4879fa992d4d
+Subproject commit eee68eafa7e8e4ce996b49f5551636639a6c331a
index c37d3747da75c280237dc2d6b925078e69555499..755bc3db4ff795865ea31b5b4f38ac920d8acacb 160000 (submodule)
@@ -1 +1 @@
-Subproject commit c37d3747da75c280237dc2d6b925078e69555499
+Subproject commit 755bc3db4ff795865ea31b5b4f38ac920d8acacb
index 4f78519e13aa860096998f43bf8c0c30a1937dc9..fde2f83e220f92b4a5784904f0f37e9fb3b6a4f0 100644 (file)
@@ -363,6 +363,7 @@ dependencies = [
  "rustc_back 0.0.0",
  "rustc_const_eval 0.0.0",
  "rustc_const_math 0.0.0",
+ "rustc_data_structures 0.0.0",
  "rustc_driver 0.0.0",
  "rustc_errors 0.0.0",
  "rustc_lint 0.0.0",
@@ -410,3 +411,5 @@ dependencies = [
  "serialize 0.0.0",
 ]
 
+[metadata]
+"checksum gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)" = "3da3a2cbaeb01363c8e3704fd9fd0eb2ceb17c6f27abd4c1ef040fb57d20dc79"
index 70aef55d799c114be7c0a975a7ba94af02a3b960..d47b541b4c3bc5ece7d8916d768d883d25d21bb1 100644 (file)
@@ -118,3 +118,5 @@ dependencies = [
  "libc 0.0.0",
 ]
 
+[metadata]
+"checksum gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "806e63121fbf30760b060a5fc2d1e9f47e1bd356d183e8870367c6c12cc9d5ed"
index 0555a96ff24ce900d6b6f53f56021a6c02496a91..a271987210b673411e77c959379f55d6b49b40a3 100644 (file)
@@ -131,12 +131,19 @@ LLVMRustAddPass(LLVMPassManagerRef PM, LLVMPassRef rust_pass) {
 #define SUBTARGET_PPC
 #endif
 
+#ifdef LLVM_COMPONENT_SYSTEMZ
+#define SUBTARGET_SYSTEMZ SUBTARGET(SystemZ)
+#else
+#define SUBTARGET_SYSTEMZ
+#endif
+
 #define GEN_SUBTARGETS    \
         SUBTARGET_X86     \
         SUBTARGET_ARM     \
         SUBTARGET_AARCH64 \
         SUBTARGET_MIPS    \
-        SUBTARGET_PPC
+        SUBTARGET_PPC     \
+        SUBTARGET_SYSTEMZ
 
 #define SUBTARGET(x) namespace llvm {                \
     extern const SubtargetFeatureKV x##FeatureKV[];  \
index 0da25e7ac57b7a7eea4628692251f0b92743d3cd..82fb2b0918f79fcfedb4f37614103f47bbd1dee3 100644 (file)
@@ -521,6 +521,15 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateLexicalBlock(
         ));
 }
 
+extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateLexicalBlockFile(
+    LLVMRustDIBuilderRef Builder,
+    LLVMRustMetadataRef Scope,
+    LLVMRustMetadataRef File) {
+    return wrap(Builder->createLexicalBlockFile(
+        unwrapDI<DIDescriptor>(Scope),
+        unwrapDI<DIFile>(File)));
+}
+
 extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable(
     LLVMRustDIBuilderRef Builder,
     LLVMRustMetadataRef Context,
index 378810a8b89fc9f0caad49ae7101c62d4241e8a0..67f8730c25825563934bbc630785f60cb8101224 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-08-07
+2016-08-23
index aaf88a67d27499e360c13d89271ec2b3521303f0..f9cf819dc9487649557a1b10888f73e5b6bea165 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-07-06
-rustc_key: 411fd48b
-cargo: nightly-2016-07-05
+rustc: beta-2016-08-17
+rustc_key: 195e6261
+cargo: nightly-2016-08-21
diff --git a/src/test/codegen/abi-sysv64.rs b/src/test/codegen/abi-sysv64.rs
new file mode 100644 (file)
index 0000000..2b8e8a1
--- /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.
+
+// Checks if the correct annotation for the sysv64 ABI is passed to
+// llvm. Also checks that the abi-sysv64 feature gate allows usage
+// of the sysv64 abi.
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(abi_sysv64)]
+
+// CHECK: define x86_64_sysvcc i64 @has_sysv64_abi
+#[no_mangle]
+pub extern "sysv64" fn has_sysv64_abi(a: i64) -> i64 {
+    a * 2
+}
index 20d049394345256dad72cc965d5d1c670b1f0f12..40603845da2b00b0d60e651bd57aad369719a805 100644 (file)
@@ -11,7 +11,6 @@
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
-#![feature(rustc_attrs)]
 
 // Hack to get the correct size for the length part in slices
 // CHECK: @helper([[USIZE:i[0-9]+]])
@@ -21,13 +20,12 @@ fn helper(_: usize) {
 
 // CHECK-LABEL: @no_op_slice_adjustment
 #[no_mangle]
-#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn no_op_slice_adjustment(x: &[u8]) -> &[u8] {
     // We used to generate an extra alloca and memcpy for the block's trailing expression value, so
     // check that we copy directly to the return value slot
-// CHECK: [[SRC:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %x to
-// CHECK: [[DST:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %sret_slot to i8*
-// CHECK: call void @llvm.memcpy.{{.*}}(i8* [[DST]], i8* [[SRC]],
+// CHECK: %2 = insertvalue { i8*, [[USIZE]] } undef, i8* %0, 0
+// CHECK: %3 = insertvalue { i8*, [[USIZE]] } %2, [[USIZE]] %1, 1
+// CHECK: ret { i8*, [[USIZE]] } %3
     { x }
 }
 
index 74c7192259ac4044108f287b39fb09114773b5eb..c8c9f5b407c421b11458d6b6c514f54ac64afbaf 100644 (file)
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
-#![feature(rustc_attrs)]
 
 static X: i32 = 5;
 
 // CHECK-LABEL: @raw_ptr_to_raw_ptr_noop
 // CHECK-NOT: alloca
 #[no_mangle]
-#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn raw_ptr_to_raw_ptr_noop() -> *const i32{
     &X as *const i32
 }
@@ -26,7 +24,6 @@ pub fn raw_ptr_to_raw_ptr_noop() -> *const i32{
 // CHECK-LABEL: @reference_to_raw_ptr_noop
 // CHECK-NOT: alloca
 #[no_mangle]
-#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn reference_to_raw_ptr_noop() -> *const i32 {
     &X
 }
index ea4c932d43549ce74efb7c6204950922d473e01a..36a582ca73709bb35b3e9ad14ecd96ab9743ef1b 100644 (file)
@@ -11,7 +11,6 @@
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
-#![feature(rustc_attrs)]
 
 // Below, these constants are defined as enum variants that by itself would
 // have a lower alignment than the enum type. Ensure that we mark them
 // CHECK: @STATIC = {{.*}}, align 4
 
 // This checks the constants from inline_enum_const
-// CHECK: @const{{[0-9]+}} = {{.*}}, align 2
+// CHECK: @ref{{[0-9]+}} = {{.*}}, align 2
 
 // This checks the constants from {low,high}_align_const, they share the same
 // constant, but the alignment differs, so the higher one should be used
-// CHECK: @const{{[0-9]+}} = {{.*}}, align 4
+// CHECK: [[LOW_HIGH:@ref[0-9]+]] = {{.*}}, align 4
+// CHECK: [[LOW_HIGH_REF:@const[0-9]+]] = {{.*}} [[LOW_HIGH]]
 
 #[derive(Copy, Clone)]
 
@@ -40,32 +40,28 @@ pub enum E<A, B> {
 
 // CHECK-LABEL: @static_enum_const
 #[no_mangle]
-#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn static_enum_const() -> E<i16, i32> {
    STATIC
 }
 
 // CHECK-LABEL: @inline_enum_const
 #[no_mangle]
-#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn inline_enum_const() -> E<i8, i16> {
-    E::A(0)
+    *&E::A(0)
 }
 
 // CHECK-LABEL: @low_align_const
 #[no_mangle]
-#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn low_align_const() -> E<i16, [i16; 3]> {
 // Check that low_align_const and high_align_const use the same constant
-// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{[0-9]+}}, i8* {{.*}} [[LOW_HIGH:@const[0-9]+]]
-    E::A(0)
+// CHECK: load {{.*}} bitcast ({ i16, i16, [4 x i8] }** [[LOW_HIGH_REF]]
+    *&E::A(0)
 }
 
 // CHECK-LABEL: @high_align_const
 #[no_mangle]
-#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn high_align_const() -> E<i16, i32> {
 // Check that low_align_const and high_align_const use the same constant
-// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{[0-9]}}, i8* {{.*}} [[LOW_HIGH]]
-    E::A(0)
+// CHECK: load {{.*}} bitcast ({ i16, i16, [4 x i8] }** [[LOW_HIGH_REF]]
+    *&E::A(0)
 }
index 25f8c130469973d888c617dca289abc639386b54..a4bd5cf2c158e3d3dcd6de4a36ede21ce28cb5d3 100644 (file)
@@ -11,7 +11,6 @@
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
-#![feature(rustc_attrs)]
 
 struct SomeUniqueName;
 
@@ -25,19 +24,20 @@ pub fn possibly_unwinding() {
 
 // CHECK-LABEL: @droppy
 #[no_mangle]
-#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn droppy() {
 // Check that there are exactly 6 drop calls. The cleanups for the unwinding should be reused, so
 // that's one new drop call per call to possibly_unwinding(), and finally 3 drop calls for the
 // regular function exit. We used to have problems with quadratic growths of drop calls in such
 // functions.
-// CHECK: call{{.*}}drop{{.*}}SomeUniqueName
-// CHECK: call{{.*}}drop{{.*}}SomeUniqueName
-// CHECK: call{{.*}}drop{{.*}}SomeUniqueName
+// CHECK-NOT: invoke{{.*}}drop{{.*}}SomeUniqueName
 // CHECK: call{{.*}}drop{{.*}}SomeUniqueName
 // CHECK: call{{.*}}drop{{.*}}SomeUniqueName
 // CHECK: call{{.*}}drop{{.*}}SomeUniqueName
 // CHECK-NOT: call{{.*}}drop{{.*}}SomeUniqueName
+// CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName
+// CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName
+// CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName
+// CHECK-NOT: {{(call|invoke).*}}drop{{.*}}SomeUniqueName
 // The next line checks for the } that ends the function definition
 // CHECK-LABEL: {{^[}]}}
     let _s = SomeUniqueName;
index a65a3e1bb66fe52a446bb25cf4fda9a497ca612f..def5269e07a02b1c345a897e5677c65ba9fa9276 100644 (file)
@@ -11,7 +11,6 @@
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
-#![feature(rustc_attrs)]
 
 pub struct Bytes {
   a: u8,
@@ -22,15 +21,14 @@ pub struct Bytes {
 
 // CHECK-LABEL: @borrow
 #[no_mangle]
-#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn borrow(x: &i32) -> &i32 {
 // CHECK: load {{(i32\*, )?}}i32** %x{{.*}}, !nonnull
+    &x; // keep variable in an alloca
     x
 }
 
 // CHECK-LABEL: @_box
 #[no_mangle]
-#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn _box(x: Box<i32>) -> i32 {
 // CHECK: load {{(i32\*, )?}}i32** %x{{.*}}, !nonnull
     *x
index c1acdaf70319195642dfe409f54ee8074980a531..a2cedc853a1e6dbf6a41beb9fce51950a096733b 100644 (file)
@@ -10,7 +10,6 @@
 
 // compile-flags: -C no-prepopulate-passes
 
-#![feature(rustc_attrs)]
 #![crate_type = "lib"]
 use std::marker::PhantomData;
 
@@ -19,7 +18,6 @@ struct Zst { phantom: PhantomData<Zst> }
 
 // CHECK-LABEL: @mir
 #[no_mangle]
-#[rustc_mir]
 fn mir(){
     // CHECK-NOT: getelementptr
     // CHECK-NOT: store{{.*}}undef
index 199f7f0201877b95ac0b71a3bc12ed81af01e1a9..9de74f72005e359a20f35cf2d8a5fcbaa2532cbd 100644 (file)
@@ -13,7 +13,7 @@
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
-#![feature(naked_functions, rustc_attrs)]
+#![feature(naked_functions)]
 
 // CHECK: Function Attrs: naked uwtable
 // CHECK-NEXT: define internal void @naked_empty()
@@ -26,11 +26,11 @@ fn naked_empty() {
 // CHECK: Function Attrs: naked uwtable
 #[no_mangle]
 #[naked]
-#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 // CHECK-NEXT: define internal void @naked_with_args(i{{[0-9]+}})
 fn naked_with_args(a: isize) {
     // CHECK: %a = alloca i{{[0-9]+}}
     // CHECK: ret void
+    &a; // keep variable in an alloca
 }
 
 // CHECK: Function Attrs: naked uwtable
@@ -46,10 +46,10 @@ fn naked_with_return() -> isize {
 // CHECK-NEXT: define internal i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}})
 #[no_mangle]
 #[naked]
-#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 fn naked_with_args_and_return(a: isize) -> isize {
     // CHECK: %a = alloca i{{[0-9]+}}
     // CHECK: ret i{{[0-9]+}} %{{[0-9]+}}
+    &a; // keep variable in an alloca
     a
 }
 
index 36c83412e4f0f4775d73e65356841c27b6f86aa4..49ed2229fcd2b721bcb865a468a718095d10515b 100644 (file)
@@ -11,7 +11,6 @@
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
-#![feature(rustc_attrs)]
 
 // Hack to get the correct size for the length part in slices
 // CHECK: @helper([[USIZE:i[0-9]+]])
@@ -21,12 +20,14 @@ fn helper(_: usize) {
 
 // CHECK-LABEL: @ref_dst
 #[no_mangle]
-#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn ref_dst(s: &[u8]) {
     // We used to generate an extra alloca and memcpy to ref the dst, so check that we copy
     // directly to the alloca for "x"
-// CHECK: [[SRC:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %s to i8*
-// CHECK: [[DST:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %x to i8*
-// CHECK: call void @llvm.memcpy.{{.*}}(i8* [[DST]], i8* [[SRC]],
+// CHECK: [[X0:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %x, i32 0, i32 0
+// CHECK: store i8* %0, i8** [[X0]]
+// CHECK: [[X1:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %x, i32 0, i32 1
+// CHECK: store [[USIZE]] %1, [[USIZE]]* [[X1]]
+
     let x = &*s;
+    &x; // keep variable in an alloca
 }
index 89bb5d93c74fa1b7f29e553b4f65cb92d6a77878..9141b7245e35aa0d89465e01ce1b9ef887522cec 100644 (file)
@@ -11,7 +11,6 @@
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
-#![feature(rustc_attrs)]
 
 pub struct Bytes {
   a: u8,
@@ -24,12 +23,11 @@ pub struct Bytes {
 // The array is stored as i32, but its alignment is lower, go with 1 byte to avoid target
 // dependent alignment
 #[no_mangle]
-#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) {
-// CHECK: %y = alloca [4 x i8]
+// CHECK: %arg1 = alloca [4 x i8]
 // CHECK: [[TMP:%.+]] = alloca i32
 // CHECK: store i32 %1, i32* [[TMP]]
-// CHECK: [[Y8:%[0-9]+]] = bitcast [4 x i8]* %y to i8*
+// CHECK: [[Y8:%[0-9]+]] = bitcast [4 x i8]* %arg1 to i8*
 // CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8*
 // CHECK: call void @llvm.memcpy.{{.*}}(i8* [[Y8]], i8* [[TMP8]], i{{[0-9]+}} 4, i32 1, i1 false)
     *x = y;
@@ -39,12 +37,11 @@ pub struct Bytes {
 // The struct is stored as i32, but its alignment is lower, go with 1 byte to avoid target
 // dependent alignment
 #[no_mangle]
-#[rustc_no_mir] // FIXME #27840 MIR has different codegen.
 pub fn small_struct_alignment(x: &mut Bytes, y: Bytes) {
-// CHECK: %y = alloca %Bytes
+// CHECK: %arg1 = alloca %Bytes
 // CHECK: [[TMP:%.+]] = alloca i32
 // CHECK: store i32 %1, i32* [[TMP]]
-// CHECK: [[Y8:%[0-9]+]] = bitcast %Bytes* %y to i8*
+// CHECK: [[Y8:%[0-9]+]] = bitcast %Bytes* %arg1 to i8*
 // CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8*
 // CHECK: call void @llvm.memcpy.{{.*}}(i8* [[Y8]], i8* [[TMP8]], i{{[0-9]+}} 4, i32 1, i1 false)
     *x = y;
index a6bc9db199c8be156ec2c2f49ce470b93a720e15..5a3412b7ed9f9f496ff8a9bcff665a88d1914c31 100644 (file)
@@ -17,7 +17,7 @@
 extern crate rustc;
 extern crate rustc_plugin;
 
-use syntax::ast::{self, Item, MetaItem, ImplItem, TraitItem, ItemKind};
+use syntax::ast::{self, Item, MetaItem, ItemKind};
 use syntax::ext::base::*;
 use syntax::parse::{self, token};
 use syntax::ptr::P;
@@ -62,8 +62,8 @@ fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree])
 }
 
 fn expand_into_foo_multi(cx: &mut ExtCtxt,
-                         sp: Span,
-                         attr: &MetaItem,
+                         _sp: Span,
+                         _attr: &MetaItem,
                          it: Annotatable) -> Annotatable {
     match it {
         Annotatable::Item(it) => {
@@ -72,7 +72,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
                 ..(*quote_item!(cx, enum Foo2 { Bar2, Baz2 }).unwrap()).clone()
             }))
         }
-        Annotatable::ImplItem(it) => {
+        Annotatable::ImplItem(_) => {
             quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| {
                 match i.node {
                     ItemKind::Impl(_, _, _, _, _, mut items) => {
@@ -82,7 +82,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
                 }
             })
         }
-        Annotatable::TraitItem(it) => {
+        Annotatable::TraitItem(_) => {
             quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| {
                 match i.node {
                     ItemKind::Trait(_, _, _, mut items) => {
@@ -97,15 +97,15 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
 
 // Create a duplicate of the annotatable, based on the MetaItem
 fn expand_duplicate(cx: &mut ExtCtxt,
-                    sp: Span,
+                    _sp: Span,
                     mi: &MetaItem,
                     it: &Annotatable,
                     push: &mut FnMut(Annotatable))
 {
     let copy_name = match mi.node {
         ast::MetaItemKind::List(_, ref xs) => {
-            if let ast::MetaItemKind::Word(ref w) = xs[0].node {
-                token::str_to_ident(&w)
+            if let Some(word) = xs[0].word() {
+                token::str_to_ident(&word.name())
             } else {
                 cx.span_err(mi.span, "Expected word");
                 return;
index 61a8ee88a70825e0c534447f51d151ea0055d5bf..75a025f064852309a740b177f0b527d34876e630 100644 (file)
 #![plugin(lint_plugin_test)]
 #![forbid(test_lint)]
 //~^ NOTE lint level defined here
-//~| NOTE `forbid` lint level set here
+//~| NOTE `forbid` level set here
 
 fn lintme() { } //~ ERROR item is named 'lintme'
 
-#[allow(test_lint)] //~ ERROR allow(test_lint) overruled by outer forbid(test_lint)
+#[allow(test_lint)]
+//~^ ERROR allow(test_lint) overruled by outer forbid(test_lint)
+//~| NOTE overruled by previous forbid
 pub fn main() {
     lintme();
 }
index 51f71ea10c9e4e41e290fe87b3db17942951f2fe..767fc0cc5dc07eb29abc9ba6ce6a83f8231df6a8 100644 (file)
@@ -12,7 +12,10 @@ fn main() {
     struct X { x: (), }
     let x = Some((X { x: () }, X { x: () }));
     match x {
-        Some((y, ref z)) => {}, //~ ERROR E0009
+        Some((y, ref z)) => {},
+        //~^ ERROR E0009
+        //~| NOTE by-move pattern here
+        //~| NOTE both by-ref and by-move used
         None => panic!()
     }
 }
index 1223a01cbcb6f29fc0d14d04215597b02c5cd58b..44d2f158d20bbeadad7b5c28d289963c044e7258 100644 (file)
@@ -20,6 +20,7 @@
                                               //~| ERROR E0017
                                               //~| NOTE statics require immutable values
                                               //~| ERROR E0388
+                                              //~| NOTE cannot write data in a static definition
 static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
                                              //~| NOTE statics require immutable values
                                              //~| ERROR E0017
index 946600013f33dbf536a9faebf9d1f199d5a3f339..d320bcd4d0f5536924c86f666d02a18426e07a77 100644 (file)
@@ -13,7 +13,13 @@ trait SomeTrait {
 }
 
 fn main() {
-    let trait_obj: &SomeTrait = SomeTrait; //~ ERROR E0425
-                                           //~^ ERROR E0038
-    let &invalid = trait_obj; //~ ERROR E0033
+    let trait_obj: &SomeTrait = SomeTrait;
+    //~^ ERROR E0425
+    //~| ERROR E0038
+    //~| method `foo` has no receiver
+    //~| NOTE the trait `SomeTrait` cannot be made into an object
+
+    let &invalid = trait_obj;
+    //~^ ERROR E0033
+    //~| NOTE type `&SomeTrait` cannot be dereferenced
 }
index 669bece0f7d175cf7121c54d70cfb23c20ca28bc..136a74f7a8b74272f51fd9f7b6d33e2e8ca23bec 100644 (file)
@@ -18,9 +18,17 @@ trait Trait2 {
     fn foo();
 }
 
-impl Trait1 for Test { fn foo() {} }
-impl Trait2 for Test { fn foo() {} }
+impl Trait1 for Test {
+    fn foo() {}
+    //~^ NOTE candidate #1 is defined in an impl of the trait `Trait1` for the type `Test`
+}
+
+impl Trait2 for Test {
+    fn foo() {}
+    //~^ NOTE candidate #2 is defined in an impl of the trait `Trait2` for the type `Test`
+}
 
 fn main() {
-    Test::foo() //~ ERROR E0034
+    Test::foo() //~ ERROR multiple applicable items in scope
+    //~| NOTE multiple `foo` found
 }
index 80ff57c36359561f28aac3410823d551f6afe16e..edfe22186e1622aba61df39b3028b5f762725f76 100644 (file)
@@ -22,5 +22,5 @@ fn main() {
     let mut x = Foo { x: -7 };
     x.drop();
     //~^ ERROR E0040
-    //~| NOTE call to destructor method
+    //~| NOTE explicit destructor calls not allowed
 }
index 4effda3c49e8e6c4e0c7f65d677f851377130fe4..933462e553e3b6db5afd3120201397d5d5307c9c 100644 (file)
@@ -9,15 +9,21 @@
 // except according to those terms.
 
 trait Foo {
-    fn foo(x: u16);
-    fn bar(&self);
+    fn foo(x: u16); //~ NOTE type in trait
+    fn bar(&self); //~ NOTE type in trait
 }
 
 struct Bar;
 
 impl Foo for Bar {
-    fn foo(x: i16) { } //~ ERROR E0053
-    fn bar(&mut self) { } //~ ERROR E0053
+    fn foo(x: i16) { }
+    //~^ ERROR method `foo` has an incompatible type for trait
+    //~| NOTE expected u16
+    fn bar(&mut self) { }
+    //~^ ERROR method `bar` has an incompatible type for trait
+    //~| NOTE types differ in mutability
+    //~| NOTE expected type `fn(&Bar)`
+    //~| NOTE found type `fn(&mut Bar)`
 }
 
 fn main() {
index b0f02a03e00518c71850695e0a1e289aa36b4083..c31dc62eb666bc1b5961153eee5fa5cc98f245f0 100644 (file)
@@ -11,7 +11,9 @@
 #![feature(repr_simd)]
 
 #[repr(simd)]
-struct Bad(u16, u32, u32); //~ ERROR E0076
+struct Bad(u16, u32, u32);
+//~^ ERROR E0076
+//~| NOTE SIMD elements must have the same type
 
 fn main() {
 }
index c579101325f5de2d49fef02dd2510f4a2b3a2d06..c7c5662f1feda8978b60d148d2f338e76fdf0728 100644 (file)
@@ -9,7 +9,9 @@
 // except according to those terms.
 
 #[repr(i32)]
-enum Foo {} //~ ERROR E0084
+enum Foo {}
+//~^ ERROR E0084
+//~| unsupported enum representation
 
 fn main() {
 }
index 437ad3698a20664a2f4792e0e28cb67e97a5fc2e..7c98de59e27972f71860b5de9d63ac4ea346dcce 100644 (file)
@@ -12,5 +12,5 @@ fn foo<T>() {}
 
 fn main() {
     foo::<f64, bool>(); //~ ERROR E0087
-    //~^ NOTE expected
+    //~^ NOTE too many type parameters
 }
index 3b52f76bf09cc11a47aa42f6a80efba845c37c33..9ce36523709e504f5581576be17c2f74cdc6f3df 100644 (file)
@@ -11,5 +11,7 @@
 fn foo<T, U>() {}
 
 fn main() {
-    foo::<f64>(); //~ ERROR E0089
+    foo::<f64>();
+//~^ ERROR E0089
+//~| NOTE expected 2 type parameters
 }
index 9b23f6d984ee1c9207873fd30f0197f52869f37f..fdc48455a679c03c028e73958b8e2f53cdbc56d1 100644 (file)
@@ -10,7 +10,9 @@
 
 #![feature(intrinsics)]
 extern "rust-intrinsic" {
-    fn foo(); //~ ERROR E0093
+    fn foo();
+    //~^ ERROR E0093
+    //~| NOTE unrecognized intrinsic
 }
 
 fn main() {
index 1a33fb24ca1a1a0eee3d3dac51f6620ffc602910..91ff6b85a42ce071efb3077f2e3a3bb46eb87ec7 100644 (file)
@@ -11,7 +11,7 @@
 #![feature(start)]
 
 #[start]
-fn f<T>() {} //~ ERROR E0132
+fn f< T >() {} //~ ERROR E0132
              //~| NOTE start function cannot have type parameters
 
 fn main() {
index b8a4476fc59671b2b5e4f6b769ce5bad5ad9bfd9..f60d9a5083f6fd526c9cdb9a810165b16398069b 100644 (file)
@@ -13,5 +13,5 @@
 fn main() {
     f();
     //~^ ERROR E0133
-    //~| NOTE unsafe call requires unsafe function or block
+    //~| NOTE call to unsafe function
 }
index 491b2e9e5b246ed9d888a9c0ffd3d4a61ab9d91d..1665a80bead770dc7293ff67486a1e22953b5b78 100644 (file)
@@ -13,6 +13,7 @@ enum Foo { B { i: u32 } }
 fn bar(foo: Foo) -> u32 {
     match foo {
         Foo::B(i) => i, //~ ERROR E0164
+                        //~| NOTE not a tuple variant or struct
     }
 }
 
index cca714bbcc1bf369700c40fc8d381297126742a8..142635fc6ee4543adc577f8e4aacd2d410991dcc 100644 (file)
@@ -13,6 +13,7 @@
 fn main() {
     let irr = Irrefutable(0);
     while let Irrefutable(x) = irr { //~ ERROR E0165
+                                     //~| irrefutable pattern
         // ...
     }
 }
index 5d72d00ffe8765bb7ade9cda1f14eb4afa4ccd2d..9ec2eeba5cc5f5a0ff49c0383d0dc1de0bd9466e 100644 (file)
@@ -9,6 +9,8 @@
 // except according to those terms.
 
 #[derive(Copy)] //~ ERROR E0184
+                //~| NOTE Copy not allowed on types with destructors
+                //~| NOTE in this expansion of #[derive(Copy)]
 struct Foo;
 
 impl Drop for Foo {
index 96b3062cacb78d6af758a25d7b54a20e0b6a1d9e..6b1f718dd76c5542e4cf5bf58edc078c32e75308 100644 (file)
@@ -8,9 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-trait Foo<T> {
+trait Foo<T> { //~ NOTE first `T` declared here
     fn do_something(&self) -> T;
-    fn do_something_else<T: Clone>(&self, bar: T); //~ ERROR E0194
+    fn do_something_else<T: Clone>(&self, bar: T);
+    //~^ ERROR E0194
+    //~| NOTE shadows another type parameter
 }
 
 fn main() {
index 0630dfea5e64b4e09d007147be9c4b500d2b9a3b..06dd903b23db83925187cd1b49838c15f8468884 100644 (file)
@@ -16,6 +16,7 @@ trait Trait {
 
 impl Trait for Foo {
     fn bar<'a,'b>(x: &'a str, y: &'b str) { //~ ERROR E0195
+                                            //~^ lifetimes do not match trait
     }
 }
 
index 213ec5a0488802960ce291c4547781f96dbd0fc6..651054580408dc7cbf2c57bed36369ceefa62b8f 100644 (file)
@@ -18,7 +18,11 @@ trait Foo {
 trait Bar : Foo {
     type A: T2;
     fn do_something() {
-        let _: Self::A; //~ ERROR E0221
+        let _: Self::A;
+        //~^ ERROR E0221
+        //~| NOTE ambiguous associated type `A`
+        //~| NOTE associated type `Self` could derive from `Foo`
+        //~| NOTE associated type `Self` could derive from `Bar`
     }
 }
 
index efeb869d71fa5ab8cc0dda6fa7c90569d1937c18..ce4f4638dac59c6bdb4396856f45326c72ce23f7 100644 (file)
 
 #![feature(on_unimplemented)]
 
-#[rustc_on_unimplemented] //~ ERROR E0232
+#[rustc_on_unimplemented]
+//~^ ERROR E0232
+//~| NOTE attribute requires a value
+//~| NOTE eg `#[rustc_on_unimplemented = "foo"]`
 trait Bar {}
 
 fn main() {
index 6b7e86138594be7898d38b28a2b260495437c665..d3e876e2527fe4b2f6132a7c8dd5a7f22ef5c446 100644 (file)
@@ -9,6 +9,10 @@
 // except according to those terms.
 
 extern crate collections;
-extern crate libc as collections; //~ ERROR E0259
+//~^ NOTE previous import of `collections` here
+
+extern crate libc as collections;
+//~^ ERROR E0259
+//~| NOTE `collections` was already imported
 
 fn main() {}
index d20829bf4d415165e59e170e185a2938fcfd221e..63647cb41035afe096744489482b66202b8f87d2 100644 (file)
@@ -9,8 +9,11 @@
 // except according to those terms.
 
 extern crate collections;
+//~^ NOTE previous import of `collections` here
 
-mod collections { //~ ERROR E0260
+mod collections {
+//~^ ERROR `collections` has already been imported in this module [E0260]
+//~| NOTE `collections` already imported
     pub trait MyTrait {
         fn do_something();
     }
index 7737f12ac371400c5f8e372475b70591b16198f5..12f9417f944cded5ea6f4cc4d3c9817b5efad5c6 100644 (file)
@@ -17,5 +17,8 @@ fn some_func<T: Foo>(foo: T) {
 }
 
 fn main() {
-    some_func(5i32); //~ ERROR E0277
+    some_func(5i32);
+    //~^ ERROR the trait bound `i32: Foo` is not satisfied
+    //~| NOTE trait `i32: Foo` not satisfied
+    //~| NOTE required by `some_func`
 }
index 445831bf8d7f7d4ba885c791d534d8cab90f6191..584dfd5fa440cd4a8f7436b98971f5487c830d8b 100644 (file)
@@ -16,5 +16,6 @@ fn main() {
     let mut fancy = FancyNum{ num: 5 };
     let fancy_ref = &(&mut fancy);
     fancy_ref.num = 6; //~ ERROR E0389
+                       //~^ NOTE assignment into an immutable reference
     println!("{}", fancy_ref.num);
 }
index 1b89555c8ced16fcc7995c899397ed9573e55e2a..f045e873519cd44f6d8286737040676974a5fdee 100644 (file)
 
 trait A<T=Self> {}
 
-fn together_we_will_rule_the_galaxy(son: &A) {} //~ ERROR E0393
+fn together_we_will_rule_the_galaxy(son: &A) {}
+//~^ ERROR E0393
+//~| NOTE missing reference to `T`
+//~| NOTE because of the default `Self` reference, type parameters must be specified on object types
 
 fn main() {
 }
index 6ab66313a0472f7a1a2ccb3a6ed45949f2bde348..98f08cd68c22de81691347133e21ccd16e1d4384 100644 (file)
@@ -12,6 +12,6 @@
 static BAR: i32 = 42;
 
 static BAZ: bool = { (&FOO as *const i32) == (&BAR as *const i32) }; //~ ERROR E0395
-
+                   //~| NOTE comparing raw pointers in static
 fn main() {
 }
index 7f34acdfb90075f32480553b877b6573c223ab06..47080fb6e9ef754f64b7fd2d86d59c8f1d68b280 100644 (file)
@@ -11,6 +11,7 @@
 const REG_ADDR: *const u8 = 0x5f3759df as *const u8;
 
 const VALUE: u8 = unsafe { *REG_ADDR }; //~ ERROR E0396
+                  //~| NOTE dereference of raw pointer in constant
 
 fn main() {
 }
index 6a68013dc6ffe3c675751599d2b55c8625370d06..cd8532fc4c305bebf8cb399d9747010fb3f4d651 100644 (file)
@@ -9,6 +9,8 @@
 // except according to those terms.
 
 fn foo<T, T>(s: T, u: T) {} //~ ERROR E0403
+                            //~| NOTE already used
+                            //~| NOTE first use of `T`
 
 fn main() {
 }
index b861cf1b37817828098884ea95f848e789db833c..2a150b7451210a7a380c98b19a80c0a6857958ca 100644 (file)
@@ -16,7 +16,9 @@ trait Foo {
 
 impl Foo for Bar {
     fn a() {}
-    fn b() {} //~ ERROR E0407
+    fn b() {}
+    //~^ ERROR E0407
+    //~| NOTE not a member of `Foo`
 }
 
 fn main() {
diff --git a/src/test/compile-fail/E0423.rs b/src/test/compile-fail/E0423.rs
new file mode 100644 (file)
index 0000000..98b7009
--- /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.
+
+fn main () {
+    struct Foo { a: bool };
+
+    let f = Foo(); //~ ERROR E0423
+                   //~^ struct called like a function
+}
diff --git a/src/test/compile-fail/E0424.rs b/src/test/compile-fail/E0424.rs
new file mode 100644 (file)
index 0000000..9110071
--- /dev/null
@@ -0,0 +1,25 @@
+// 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.
+
+struct Foo;
+
+impl Foo {
+    fn bar(self) {}
+
+    fn foo() {
+        self.bar();
+        //~^ ERROR `self` is not available in a static method [E0424]
+        //~| NOTE not available in static method
+        //~| NOTE maybe a `self` argument is missing?
+    }
+}
+
+fn main () {
+}
diff --git a/src/test/compile-fail/E0425.rs b/src/test/compile-fail/E0425.rs
new file mode 100644 (file)
index 0000000..70f4b11
--- /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.
+
+trait Foo {
+    fn bar() {
+        Self; //~ ERROR E0425
+    }
+}
+
+fn main () {
+}
diff --git a/src/test/compile-fail/E0426.rs b/src/test/compile-fail/E0426.rs
new file mode 100644 (file)
index 0000000..be21421
--- /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.
+
+fn main () {
+    loop {
+        break 'a;
+        //~^ ERROR E0426
+        //~| NOTE undeclared label `'a`
+    }
+}
diff --git a/src/test/compile-fail/E0428.rs b/src/test/compile-fail/E0428.rs
new file mode 100644 (file)
index 0000000..63b4efb
--- /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.
+
+struct Bar; //~ previous definition of `Bar` here
+            //~| previous definition of `Bar` here
+struct Bar; //~ ERROR E0428
+            //~| NOTE already defined
+            //~| ERROR E0428
+            //~| NOTE already defined
+
+fn main () {
+}
diff --git a/src/test/compile-fail/E0429.rs b/src/test/compile-fail/E0429.rs
new file mode 100644 (file)
index 0000000..a7d1974
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::fmt::self; //~ ERROR E0429
+                    //~^ ERROR E0432
+
+fn main () {
+}
diff --git a/src/test/compile-fail/E0430.rs b/src/test/compile-fail/E0430.rs
new file mode 100644 (file)
index 0000000..992876d
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::fmt::{self, self}; //~ ERROR E0430
+                            //~^ ERROR E0252
+
+fn main () {
+}
diff --git a/src/test/compile-fail/E0431.rs b/src/test/compile-fail/E0431.rs
new file mode 100644 (file)
index 0000000..09ddc1e
--- /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.
+
+use {self}; //~ ERROR E0431
+
+fn main () {
+}
diff --git a/src/test/compile-fail/E0432.rs b/src/test/compile-fail/E0432.rs
new file mode 100644 (file)
index 0000000..08d699e
--- /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.
+
+use something::Foo; //~ ERROR E0432
+
+fn main () {
+}
diff --git a/src/test/compile-fail/E0433.rs b/src/test/compile-fail/E0433.rs
new file mode 100644 (file)
index 0000000..916d622
--- /dev/null
@@ -0,0 +1,13 @@
+// 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 () {
+    let map = HashMap::new(); //~ ERROR E0433
+}
diff --git a/src/test/compile-fail/E0434.rs b/src/test/compile-fail/E0434.rs
new file mode 100644 (file)
index 0000000..747d9f7
--- /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.
+
+fn foo() {
+    let y = 5;
+    fn bar() -> u32 {
+        y //~ ERROR E0434
+    }
+}
+
+fn main () {
+}
diff --git a/src/test/compile-fail/E0435.rs b/src/test/compile-fail/E0435.rs
new file mode 100644 (file)
index 0000000..f687633
--- /dev/null
@@ -0,0 +1,15 @@
+// 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 () {
+    let foo = 42u32;
+    const FOO : u32 = foo; //~ ERROR E0435
+    //~| NOTE non-constant used with constant
+}
diff --git a/src/test/compile-fail/E0437.rs b/src/test/compile-fail/E0437.rs
new file mode 100644 (file)
index 0000000..62ee8dc
--- /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.
+
+trait Foo {}
+
+impl Foo for i32 {
+    type Bar = bool; //~ ERROR E0437
+    //~| NOTE not a member of trait `Foo`
+}
+
+fn main () {
+}
diff --git a/src/test/compile-fail/E0438.rs b/src/test/compile-fail/E0438.rs
new file mode 100644 (file)
index 0000000..f549d62
--- /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(associated_consts)]
+
+trait Foo {}
+
+impl Foo for i32 {
+    const BAR: bool = true; //~ ERROR E0438
+        //~| NOTE not a member of trait `Foo`
+}
+
+fn main () {
+}
diff --git a/src/test/compile-fail/E0439.rs b/src/test/compile-fail/E0439.rs
new file mode 100644 (file)
index 0000000..5244343
--- /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.
+
+#![feature(platform_intrinsics)]
+
+extern "platform-intrinsic" {
+    fn simd_shuffle<A,B>(a: A, b: A, c: [u32; 8]) -> B; //~ ERROR E0439
+}
+
+fn main () {
+}
diff --git a/src/test/compile-fail/E0440.rs b/src/test/compile-fail/E0440.rs
new file mode 100644 (file)
index 0000000..04e7584
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(repr_simd)]
+#![feature(platform_intrinsics)]
+
+#[repr(simd)]
+struct f64x2(f64, f64);
+
+extern "platform-intrinsic" {
+    fn x86_mm_movemask_pd<T>(x: f64x2) -> i32; //~ ERROR E0440
+}
+
+fn main () {
+}
diff --git a/src/test/compile-fail/E0441.rs b/src/test/compile-fail/E0441.rs
new file mode 100644 (file)
index 0000000..967ff64
--- /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(repr_simd)]
+#![feature(platform_intrinsics)]
+
+#[repr(simd)]
+struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16);
+
+extern "platform-intrinsic" {
+    fn x86_mm_adds_ep16(x: i16x8, y: i16x8) -> i16x8; //~ ERROR E0441
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/E0442.rs b/src/test/compile-fail/E0442.rs
new file mode 100644 (file)
index 0000000..ddd9270
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(repr_simd)]
+#![feature(platform_intrinsics)]
+
+#[repr(simd)]
+struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8,
+             i8, i8, i8, i8, i8, i8, i8, i8);
+#[repr(simd)]
+struct i32x4(i32, i32, i32, i32);
+#[repr(simd)]
+struct i64x2(i64, i64);
+
+extern "platform-intrinsic" {
+    fn x86_mm_adds_epi16(x: i8x16, y: i32x4) -> i64x2;
+    //~^ ERROR E0442
+    //~| ERROR E0442
+    //~| ERROR E0442
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/E0443.rs b/src/test/compile-fail/E0443.rs
new file mode 100644 (file)
index 0000000..24d1ee0
--- /dev/null
@@ -0,0 +1,23 @@
+// 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(repr_simd)]
+#![feature(platform_intrinsics)]
+
+#[repr(simd)]
+struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16);
+#[repr(simd)]
+struct i64x8(i64, i64, i64, i64, i64, i64, i64, i64);
+
+extern "platform-intrinsic" {
+    fn x86_mm_adds_epi16(x: i16x8, y: i16x8) -> i64x8; //~ ERROR E0443
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/E0444.rs b/src/test/compile-fail/E0444.rs
new file mode 100644 (file)
index 0000000..a424a3c
--- /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(repr_simd)]
+#![feature(platform_intrinsics)]
+
+#[repr(simd)]
+struct f64x2(f64, f64);
+
+extern "platform-intrinsic" {
+    fn x86_mm_movemask_pd(x: f64x2, y: f64x2, z: f64x2) -> i32; //~ ERROR E0444
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/E0445.rs b/src/test/compile-fail/E0445.rs
new file mode 100644 (file)
index 0000000..7c5c862
--- /dev/null
@@ -0,0 +1,25 @@
+// 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.
+
+trait Foo {
+    fn dummy(&self) { }
+}
+
+pub trait Bar : Foo {}
+//~^ ERROR private trait in public interface [E0445]
+//~| NOTE private trait can't be public
+pub struct Bar2<T: Foo>(pub T);
+//~^ ERROR private trait in public interface [E0445]
+//~| NOTE private trait can't be public
+pub fn foo<T: Foo> (t: T) {}
+//~^ ERROR private trait in public interface [E0445]
+//~| NOTE private trait can't be public
+
+fn main() {}
diff --git a/src/test/compile-fail/E0446.rs b/src/test/compile-fail/E0446.rs
new file mode 100644 (file)
index 0000000..c576661
--- /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.
+
+mod Foo {
+    struct Bar(u32);
+
+    pub fn bar() -> Bar { //~ ERROR E0446
+        Bar(0)
+    }
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/E0449.rs b/src/test/compile-fail/E0449.rs
new file mode 100644 (file)
index 0000000..ac365db
--- /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.
+
+struct Bar;
+
+trait Foo {
+    fn foo();
+}
+
+pub impl Bar {} //~ ERROR E0449
+
+pub impl Foo for Bar { //~ ERROR E0449
+    pub fn foo() {} //~ ERROR E0449
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0450.rs b/src/test/compile-fail/E0450.rs
new file mode 100644 (file)
index 0000000..200b58a
--- /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.
+
+mod Bar {
+    pub struct Foo( bool, pub i32, f32, bool);
+    //~^ NOTE private field declared here
+    //~| NOTE private field declared here
+    //~| NOTE private field declared here
+}
+
+fn main() {
+    let f = Bar::Foo(false,1,0.1, true); //~ ERROR E0450
+                         //~^ NOTE cannot construct with a private field
+}
diff --git a/src/test/compile-fail/E0451.rs b/src/test/compile-fail/E0451.rs
new file mode 100644 (file)
index 0000000..f7b106d
--- /dev/null
@@ -0,0 +1,36 @@
+// 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.
+
+mod Bar {
+    pub struct Foo {
+        pub a: isize,
+        b: isize,
+    }
+
+    pub struct FooTuple (
+        pub isize,
+        isize,
+    );
+}
+
+fn pat_match(foo: Bar::Foo) {
+    let Bar::Foo{a:a, b:b} = foo; //~ ERROR E0451
+                                  //~^ NOTE field `b` is private
+}
+
+fn pat_match_tuple(foo: Bar::FooTuple) {
+    let Bar::FooTuple(a,b) = foo; //~ ERROR E0451
+                                  //~^ NOTE field `1` is private
+}
+
+fn main() {
+    let f = Bar::Foo{ a: 0, b: 0 }; //~ ERROR E0451
+                                    //~^ NOTE field `b` is private
+}
diff --git a/src/test/compile-fail/E0452.rs b/src/test/compile-fail/E0452.rs
new file mode 100644 (file)
index 0000000..1665bbd
--- /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.
+
+#![allow(foo = "")] //~ ERROR E0452
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0453.rs b/src/test/compile-fail/E0453.rs
new file mode 100644 (file)
index 0000000..6fed3dc
--- /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.
+
+#![forbid(non_snake_case)]
+//~^ NOTE `forbid` level set here
+
+#[allow(non_snake_case)]
+//~^ ERROR allow(non_snake_case) overruled by outer forbid(non_snake_case)
+//~| NOTE overruled by previous forbid
+fn main() {
+}
diff --git a/src/test/compile-fail/E0454.rs b/src/test/compile-fail/E0454.rs
new file mode 100644 (file)
index 0000000..3988792
--- /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.
+
+#[link(name = "")] extern {}
+//~^ ERROR E0454
+//~| NOTE empty name given
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0458.rs b/src/test/compile-fail/E0458.rs
new file mode 100644 (file)
index 0000000..21bedc6
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[link(kind = "wonderful_unicorn")] extern {} //~ ERROR E0458
+                                              //~^ ERROR E0459
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0459.rs b/src/test/compile-fail/E0459.rs
new file mode 100644 (file)
index 0000000..dc7ac71
--- /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.
+
+#[link(kind = "dylib")] extern {} //~ ERROR E0459
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0463.rs b/src/test/compile-fail/E0463.rs
new file mode 100644 (file)
index 0000000..3ce5b83
--- /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.
+
+#![feature(plugin)]
+#![plugin(cookie_monster)]
+//~^ ERROR E0463
+//~| NOTE can't find crate
+extern crate cake_is_a_lie;
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0478.rs b/src/test/compile-fail/E0478.rs
new file mode 100644 (file)
index 0000000..8eb4003
--- /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.
+
+trait Wedding<'t>: 't { }
+
+struct Prince<'kiss, 'SnowWhite> {
+    child: Box<Wedding<'kiss> + 'SnowWhite>, //~ ERROR E0478
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0492.rs b/src/test/compile-fail/E0492.rs
new file mode 100644 (file)
index 0000000..8e4964c
--- /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.
+
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
+
+const A: AtomicUsize = ATOMIC_USIZE_INIT;
+static B: &'static AtomicUsize = &A; //~ ERROR E0492
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0493.rs b/src/test/compile-fail/E0493.rs
new file mode 100644 (file)
index 0000000..689f469
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo {
+    a: u32
+}
+
+impl Drop for Foo {
+    fn drop(&mut self) {}
+}
+
+const F : Foo = Foo { a : 0 }; //~ ERROR E0493
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0494.rs b/src/test/compile-fail/E0494.rs
new file mode 100644 (file)
index 0000000..5f8632a
--- /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.
+
+struct Foo {
+    a: u32
+}
+
+static S : Foo = Foo { a : 0 };
+static A : &'static u32 = &S.a; //~ ERROR E0494
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0496.rs b/src/test/compile-fail/E0496.rs
new file mode 100644 (file)
index 0000000..4ca3cd9
--- /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.
+
+struct Foo<'a> {
+    a: &'a i32,
+}
+
+impl<'a> Foo<'a> {
+    fn f<'a>(x: &'a i32) { //~ ERROR E0496
+    }
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0499.rs b/src/test/compile-fail/E0499.rs
new file mode 100644 (file)
index 0000000..9a64bfe
--- /dev/null
@@ -0,0 +1,15 @@
+// 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() {
+    let mut i = 0;
+    let mut x = &mut i;
+    let mut a = &mut i; //~ ERROR E0499
+}
diff --git a/src/test/compile-fail/E0501.rs b/src/test/compile-fail/E0501.rs
new file mode 100644 (file)
index 0000000..04678b9
--- /dev/null
@@ -0,0 +1,25 @@
+// 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 inside_closure(x: &mut i32) {
+}
+
+fn outside_closure(x: &mut i32) {
+}
+
+fn foo(a: &mut i32) {
+    let bar = || {
+        inside_closure(a)
+    };
+    outside_closure(a); //~ ERROR E0501
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0502.rs b/src/test/compile-fail/E0502.rs
new file mode 100644 (file)
index 0000000..fce8513
--- /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.
+
+fn bar(x: &mut i32) {}
+fn foo(a: &mut i32) {
+    let ref y = a;
+    bar(a); //~ ERROR E0502
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0503.rs b/src/test/compile-fail/E0503.rs
new file mode 100644 (file)
index 0000000..810eb8d
--- /dev/null
@@ -0,0 +1,15 @@
+// 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() {
+    let mut value = 3;
+    let _borrow = &mut value;
+    let _sum = value + 1; //~ ERROR E0503
+}
diff --git a/src/test/compile-fail/E0504.rs b/src/test/compile-fail/E0504.rs
new file mode 100644 (file)
index 0000000..c594f24
--- /dev/null
@@ -0,0 +1,25 @@
+// 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.
+
+struct FancyNum {
+    num: u8,
+}
+
+fn main() {
+    let fancy_num = FancyNum { num: 5 };
+    let fancy_ref = &fancy_num;
+
+    let x = move || {
+        println!("child function: {}", fancy_num.num); //~ ERROR E0504
+    };
+
+    x();
+    println!("main function: {}", fancy_ref.num);
+}
diff --git a/src/test/compile-fail/E0505.rs b/src/test/compile-fail/E0505.rs
new file mode 100644 (file)
index 0000000..2d534b8
--- /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.
+
+struct Value {}
+
+fn eat(val: Value) {}
+
+fn main() {
+    let x = Value{};
+    {
+        let _ref_to_val: &Value = &x;
+        eat(x); //~ ERROR E0505
+    }
+}
diff --git a/src/test/compile-fail/E0506.rs b/src/test/compile-fail/E0506.rs
new file mode 100644 (file)
index 0000000..ddaffd4
--- /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.
+
+struct FancyNum {
+    num: u8,
+}
+
+fn main() {
+    let mut fancy_num = FancyNum { num: 5 };
+    let fancy_ref = &fancy_num;
+    fancy_num = FancyNum { num: 6 }; //~ ERROR E0506
+
+    println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num);
+}
diff --git a/src/test/compile-fail/E0507.rs b/src/test/compile-fail/E0507.rs
new file mode 100644 (file)
index 0000000..87b1bf5
--- /dev/null
@@ -0,0 +1,23 @@
+// 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::cell::RefCell;
+
+struct TheDarkKnight;
+
+impl TheDarkKnight {
+    fn nothing_is_true(self) {}
+}
+
+fn main() {
+    let x = RefCell::new(TheDarkKnight);
+
+    x.borrow().nothing_is_true(); //~ ERROR E0507
+}
diff --git a/src/test/compile-fail/E0508.rs b/src/test/compile-fail/E0508.rs
new file mode 100644 (file)
index 0000000..a72c29c
--- /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.
+
+struct NonCopy;
+
+fn main() {
+    let array = [NonCopy; 1];
+    let _value = array[0]; //~ ERROR E0508
+}
diff --git a/src/test/compile-fail/E0509.rs b/src/test/compile-fail/E0509.rs
new file mode 100644 (file)
index 0000000..b92024c
--- /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.
+
+struct FancyNum {
+    num: usize
+}
+
+struct DropStruct {
+    fancy: FancyNum
+}
+
+impl Drop for DropStruct {
+    fn drop(&mut self) {
+    }
+}
+
+fn main() {
+    let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
+    let fancy_field = drop_struct.fancy; //~ ERROR E0509
+    println!("Fancy: {}", fancy_field.num);
+}
diff --git a/src/test/compile-fail/E0511.rs b/src/test/compile-fail/E0511.rs
new file mode 100644 (file)
index 0000000..c5c03f8
--- /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.
+
+#![feature(platform_intrinsics)]
+
+extern "platform-intrinsic" {
+    fn simd_add<T>(a: T, b: T) -> T;
+}
+
+fn main() {
+    unsafe { simd_add(0, 1); } //~ ERROR E0511
+}
diff --git a/src/test/compile-fail/E0512.rs b/src/test/compile-fail/E0512.rs
new file mode 100644 (file)
index 0000000..25f9627
--- /dev/null
@@ -0,0 +1,15 @@
+// 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 takes_u8(_: u8) {}
+
+fn main() {
+    unsafe { takes_u8(::std::mem::transmute(0u16)); } //~ ERROR E0512
+}
diff --git a/src/test/compile-fail/E0516.rs b/src/test/compile-fail/E0516.rs
new file mode 100644 (file)
index 0000000..a5f609d
--- /dev/null
@@ -0,0 +1,13 @@
+// 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() {
+    let x: typeof(92) = 92; //~ ERROR E0516
+}
diff --git a/src/test/compile-fail/E0517.rs b/src/test/compile-fail/E0517.rs
new file mode 100644 (file)
index 0000000..be06e80
--- /dev/null
@@ -0,0 +1,25 @@
+// 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.
+
+#[repr(C)] //~ ERROR E0517
+type Foo = u8;
+
+#[repr(packed)] //~ ERROR E0517
+enum Foo2 {Bar, Baz}
+
+#[repr(u8)] //~ ERROR E0517
+struct Foo3 {bar: bool, baz: bool}
+
+#[repr(C)] //~ ERROR E0517
+impl Foo3 {
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0518.rs b/src/test/compile-fail/E0518.rs
new file mode 100644 (file)
index 0000000..8518bb4
--- /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.
+
+#[inline(always)] //~ ERROR E0518
+struct Foo;
+
+#[inline(never)] //~ ERROR E0518
+impl Foo {
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0520.rs b/src/test/compile-fail/E0520.rs
new file mode 100644 (file)
index 0000000..0bb8fae
--- /dev/null
@@ -0,0 +1,34 @@
+// 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(specialization)]
+
+trait SpaceLlama {
+    fn fly(&self);
+}
+
+impl<T> SpaceLlama for T {
+    default fn fly(&self) {}
+}
+
+impl<T: Clone> SpaceLlama for T {
+//~^ NOTE parent `impl` is here
+    fn fly(&self) {}
+}
+
+impl SpaceLlama for i32 {
+    default fn fly(&self) {}
+    //~^ ERROR E0520
+    //~| NOTE cannot specialize default item `fly`
+    //~| NOTE either the parent `impl` or `fly` in the parent `impl` must be marked `default`
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/E0522.rs b/src/test/compile-fail/E0522.rs
new file mode 100644 (file)
index 0000000..5103c83
--- /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(lang_items)]
+
+#[lang = "cookie"]
+fn cookie() -> ! { //~ E0522
+    loop {}
+}
diff --git a/src/test/compile-fail/E0527.rs b/src/test/compile-fail/E0527.rs
new file mode 100644 (file)
index 0000000..f03f35a
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(slice_patterns)]
+
+fn main() {
+    let r = &[1, 2, 3, 4];
+    match r {
+        &[a, b] => { //~ ERROR E0527
+            println!("a={}, b={}", a, b);
+        }
+    }
+}
diff --git a/src/test/compile-fail/E0528.rs b/src/test/compile-fail/E0528.rs
new file mode 100644 (file)
index 0000000..e912650
--- /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(slice_patterns)]
+
+fn main() {
+    let r = &[1, 2];
+    match r {
+        &[a, b, c, rest..] => {
+        //~^ ERROR E0528
+        //~| NOTE pattern cannot match array of 2 elements
+        }
+    }
+}
diff --git a/src/test/compile-fail/E0529.rs b/src/test/compile-fail/E0529.rs
new file mode 100644 (file)
index 0000000..18d3e68
--- /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(slice_patterns)]
+
+fn main() {
+    let r: f32 = 1.0;
+    match r {
+        [a, b] => {
+        //~^ ERROR E0529
+        //~| NOTE pattern cannot match with input type `f32`
+        }
+    }
+}
diff --git a/src/test/compile-fail/E0530.rs b/src/test/compile-fail/E0530.rs
new file mode 100644 (file)
index 0000000..4f674d0
--- /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.
+
+fn main() {
+    static TEST: i32 = 0;
+
+    let r: (i32, i32) = (0, 0);
+    match r {
+        TEST => {} //~ ERROR E0530
+    }
+}
diff --git a/src/test/compile-fail/E0534.rs b/src/test/compile-fail/E0534.rs
new file mode 100644 (file)
index 0000000..8c036e6
--- /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.
+
+#[inline()] //~ ERROR E0534
+pub fn something() {}
+
+fn main() {}
diff --git a/src/test/compile-fail/E0535.rs b/src/test/compile-fail/E0535.rs
new file mode 100644 (file)
index 0000000..17558cc
--- /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.
+
+#[inline(unknown)] //~ ERROR E0535
+pub fn something() {}
+
+fn main() {}
diff --git a/src/test/compile-fail/E0536.rs b/src/test/compile-fail/E0536.rs
new file mode 100644 (file)
index 0000000..127bdc2
--- /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.
+
+#[cfg(not())] //~ ERROR E0536
+pub fn something() {}
+
+pub fn main() {}
diff --git a/src/test/compile-fail/E0537.rs b/src/test/compile-fail/E0537.rs
new file mode 100644 (file)
index 0000000..497936f
--- /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.
+
+#[cfg(unknown())] //~ ERROR E0537
+pub fn something() {}
+
+pub fn main() {}
diff --git a/src/test/compile-fail/E0558.rs b/src/test/compile-fail/E0558.rs
new file mode 100644 (file)
index 0000000..0c2ca69
--- /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.
+
+#[export_name]
+//~^ ERROR E0558
+//~| NOTE did you mean #[export_name="*"]?
+
+pub fn something() {}
+
+fn main() {}
diff --git a/src/test/compile-fail/E0559.rs b/src/test/compile-fail/E0559.rs
new file mode 100644 (file)
index 0000000..80eeb20
--- /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.
+
+enum Field {
+    Fool { x: u32 },
+}
+
+fn main() {
+    let s = Field::Fool { joke: 0 }; //~ ERROR E0559
+}
diff --git a/src/test/compile-fail/E0565-1.rs b/src/test/compile-fail/E0565-1.rs
new file mode 100644 (file)
index 0000000..d3e68c7
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(attr_literals)]
+
+// deprecated doesn't currently support literals
+#[deprecated("since")] //~ ERROR E0565
+fn f() {  }
+
+fn main() {  }
diff --git a/src/test/compile-fail/E0565.rs b/src/test/compile-fail/E0565.rs
new file mode 100644 (file)
index 0000000..b2d3692
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(attr_literals)]
+
+// repr currently doesn't support literals
+#[repr("C")] //~ ERROR E0565
+struct A {  }
+
+fn main() {  }
diff --git a/src/test/compile-fail/E560.rs b/src/test/compile-fail/E560.rs
new file mode 100644 (file)
index 0000000..ec9b86e
--- /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.
+
+struct Simba {
+    mother: u32,
+}
+
+fn main() {
+    let s = Simba { mother: 1, father: 0 }; //~ ERROR E0560
+}
index b3776091682da18b3f149c01f8786e830657df6d..ec495c87b1a3f70e1c56d8d715fd92bad73502da 100644 (file)
@@ -11,7 +11,7 @@
 #![feature(associated_consts)]
 
 trait Foo {
-    const BAR: u32; //~ NOTE original trait requirement
+    const BAR: u32; //~ NOTE type in trait
 }
 
 struct SignedBar;
index 48bfa84fa8666cb6a5e29db6c3c5d2d18b1554b0..084616964674f3ab85423beb904fb9d12b16ac61 100644 (file)
@@ -31,5 +31,6 @@ trait Add<RHS=Self> {
 fn ice<A>(a: A) {
     let r = loop {};
     r = r + a;
-    //~^ ERROR E0277
+    //~^ ERROR the trait bound `(): Add<A>` is not satisfied
+    //~| NOTE trait `(): Add<A>` not satisfied
 }
diff --git a/src/test/compile-fail/attr-literals.rs b/src/test/compile-fail/attr-literals.rs
new file mode 100644 (file)
index 0000000..b542880
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that literals in attributes parse just fine.
+
+#![feature(rustc_attrs, attr_literals)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+#[fake_attr] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(100)] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(1, 2, 3)] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr("hello")] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(name = "hello")] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(key = "hello", val = 10)] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(key("hello"), val(10))] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(enabled = true, disabled = false)] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(true)] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(pi = 3.14159)] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(b"hi")] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_doc(r"doc")] //~ ERROR attribute `fake_doc` is currently unknown
+struct Q {  }
+
+#[rustc_error]
+fn main() { }
diff --git a/src/test/compile-fail/bad-format-args.rs b/src/test/compile-fail/bad-format-args.rs
deleted file mode 100644 (file)
index 8c58c8c..0000000
+++ /dev/null
@@ -1,22 +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.
-
-// error-pattern: requires at least a format string argument
-// error-pattern: in this expansion
-
-// error-pattern: expected token: `,`
-// error-pattern: in this expansion
-// error-pattern: in this expansion
-
-fn main() {
-    format!();
-    format!("" 1);
-    format!("", 1 1);
-}
index 0cd3a8853185fade135c0916d475447724a754d7..6987d06ef12c3b40d0a504345ad8cc173e00cd79 100644 (file)
@@ -8,6 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: failed to resolve. Use of undeclared type or module `thing`
+fn main() {
+    let foo = thing::len(Vec::new());
+    //~^ ERROR failed to resolve. Use of undeclared type or module `thing`
 
-fn main() { let foo = thing::len(Vec::new()); }
+    let foo = foo::bar::baz();
+    //~^ ERROR failed to resolve. Use of undeclared type or module `foo`
+}
index 8aaf752125690d829c7e40518d6032191e8e8969..e9d0b986c11767915ff6d7842e99de01b2f26340 100644 (file)
@@ -13,5 +13,7 @@ trait Trait {}
 pub fn main() {
     let x: Vec<Trait + Sized> = Vec::new();
     //~^ ERROR `Trait + Sized: std::marker::Sized` is not satisfied
+    //~| ERROR the trait `std::marker::Sized` cannot be made into an object
     //~| ERROR `Trait + Sized: std::marker::Sized` is not satisfied
+    //~| ERROR the trait `std::marker::Sized` cannot be made into an object
 }
index 3fd71f715647dc83379b51e0839aefff1f951b4d..530822f6c5bafb1c387cae483b780d8536be33e8 100644 (file)
@@ -71,6 +71,7 @@ fn copy_after_mut_borrow() {
     let _x = &mut a.x;
     //~^ NOTE borrow of `a.x` occurs here
     let _y = a.y; //~ ERROR cannot use
+    //~^ NOTE use of borrowed `a.x`
 }
 
 fn move_after_mut_borrow() {
@@ -141,6 +142,7 @@ fn copy_after_mut_borrow_nested() {
     let _x = &mut a.x.x;
     //~^ NOTE borrow of `a.x.x` occurs here
     let _y = a.y; //~ ERROR cannot use
+    //~^ NOTE use of borrowed `a.x.x`
 }
 
 fn move_after_mut_borrow_nested() {
index 02aa771c787897209d1f19a37f893ea4bb93597f..95c74348e788bd1c7bebe746c21038d24347fdc2 100644 (file)
@@ -13,47 +13,48 @@ fn f() {
     let mut v1 = Vec::new(); // statement 1
 
     let mut v2 = Vec::new(); // statement 2
-    //~^ NOTE reference must be valid for the block suffix following statement 2
 
     let young = ['y'];       // statement 3
-    //~^ NOTE ...but borrowed value is only valid for the block suffix following statement 3
 
     v2.push(&young[0]);      // statement 4
     //~^ ERROR `young[..]` does not live long enough
+    //~| NOTE does not live long enough
+    //~| NOTE values in a scope are dropped in the opposite order they are created
 
     let mut v3 = Vec::new(); // statement 5
-    //~^ NOTE reference must be valid for the block suffix following statement 5
 
     v3.push(&'x');           // statement 6
     //~^ ERROR borrowed value does not live long enough
-    //~| does not live long enough
-    //~| NOTE ...but borrowed value is only valid for the statement
-    //~| HELP consider using a `let` binding to increase its lifetime
+    //~| NOTE temporary value created here
+    //~| NOTE temporary value only lives until here
+    //~| NOTE consider using a `let` binding to increase its lifetime
 
     {
 
         let mut v4 = Vec::new(); // (sub) statement 0
-        //~^ NOTE reference must be valid for the block suffix following statement 0
 
         v4.push(&'y');
         //~^ ERROR borrowed value does not live long enough
-        //~| does not live long enough
-        //~| NOTE ...but borrowed value is only valid for the statement
-        //~| HELP consider using a `let` binding to increase its lifetime
+        //~| NOTE temporary value created here
+        //~| NOTE temporary value only lives until here
+        //~| NOTE consider using a `let` binding to increase its lifetime
 
     }                       // (statement 7)
+    //~^ NOTE temporary value needs to live until here
 
     let mut v5 = Vec::new(); // statement 8
-    //~^ NOTE reference must be valid for the block suffix following statement 8
 
     v5.push(&'z');
     //~^ ERROR borrowed value does not live long enough
-    //~| does not live long enough
-    //~| NOTE ...but borrowed value is only valid for the statement
-    //~| HELP consider using a `let` binding to increase its lifetime
+    //~| NOTE temporary value created here
+    //~| NOTE temporary value only lives until here
+    //~| NOTE consider using a `let` binding to increase its lifetime
 
     v1.push(&old[0]);
 }
+//~^ NOTE borrowed value dropped before borrower
+//~| NOTE temporary value needs to live until here
+//~| NOTE temporary value needs to live until here
 
 fn main() {
     f();
diff --git a/src/test/compile-fail/borrowck/borrowck-let-suggestion.rs b/src/test/compile-fail/borrowck/borrowck-let-suggestion.rs
deleted file mode 100644 (file)
index 866e72f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn f() {
-    let x = [1].iter();
-    //~^ ERROR borrowed value does not live long enough
-    //~|does not live long enough
-    //~| NOTE reference must be valid for the block suffix following statement
-    //~| HELP consider using a `let` binding to increase its lifetime
-    //~| NOTE ...but borrowed value is only valid for the statement at 12:4
-}
-
-fn main() {
-    f();
-}
index 05c531e91f128e66e025da7150d503a8cc06f297..b6e81504a9d24a2b1ac587145a84bae2809e595d 100644 (file)
@@ -59,10 +59,12 @@ fn main()
     //~^ ERROR casting
     //~^^ HELP through a usize first
     let _ = 3_i32 as bool;
-    //~^ ERROR cannot cast as `bool`
+    //~^ ERROR cannot cast as `bool` [E0054]
+    //~| unsupported cast
     //~| HELP compare with zero
     let _ = E::A as bool;
-    //~^ ERROR cannot cast as `bool`
+    //~^ ERROR cannot cast as `bool` [E0054]
+    //~| unsupported cast
     //~| HELP compare with zero
     let _ = 0x61u32 as char; //~ ERROR only `u8` can be cast
 
@@ -90,6 +92,7 @@ fn main()
     let _ = v as *const [u8]; //~ ERROR cannot cast
     let _ = fat_v as *const Foo;
     //~^ ERROR the trait bound `[u8]: std::marker::Sized` is not satisfied
+    //~| NOTE trait `[u8]: std::marker::Sized` not satisfied
     //~| NOTE `[u8]` does not have a constant size known at compile-time
     //~| NOTE required for the cast to the object type `Foo`
     let _ = foo as *const str; //~ ERROR casting
@@ -104,6 +107,7 @@ fn main()
     let a : *const str = "hello";
     let _ = a as *const Foo;
     //~^ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+    //~| NOTE trait `str: std::marker::Sized` not satisfied
     //~| NOTE `str` does not have a constant size known at compile-time
     //~| NOTE required for the cast to the object type `Foo`
 
index 86702a7463fd0872957e6f96f79c4462c512d3ec..bc3d58ef33db08cf49aac1e38511d7a2bbee3037 100644 (file)
@@ -16,5 +16,5 @@ fn main() {
     //~^ ERROR mismatched types
     //~| expected type `&mut i32`
     //~| found type `&{integer}`
-    //~| values differ in mutability
+    //~| types differ in mutability
 }
diff --git a/src/test/compile-fail/conflicting-repr-hints.rs b/src/test/compile-fail/conflicting-repr-hints.rs
new file mode 100644 (file)
index 0000000..9e0c0d8
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+#[repr(C)]
+enum A { A }
+
+#[repr(u64)]
+enum B { B }
+
+#[repr(C, u64)] //~ WARNING conflicting representation hints
+enum C { C }
+
+#[repr(u32, u64)] //~ WARNING conflicting representation hints
+enum D { D }
+
+#[repr(C, packed)]
+struct E(i32);
+
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
index fa15f3e87c6947a4083579f9fe5d27afacf227d3..c626801d48c03e8dd066282e5e868e6c1ea33228 100644 (file)
@@ -12,5 +12,6 @@
 
 fn main() {
     static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; //~ ERROR E0396
+                    //~| NOTE dereference of raw pointer in constant
     println!("{}", C);
 }
index 92568b27f7c1da143e24a4fd2a982f3df13026d7..7ea72e23779ec5f40871851c233fc0a401aff4c8 100644 (file)
@@ -21,7 +21,7 @@ trait Foo {
 
 impl Foo for u32 {
     const fn f() -> u32 { 22 }
-    //~^ ERROR E0379
+    //~^ ERROR trait fns cannot be declared const
     //~| NOTE trait fns cannot be const
 }
 
index 191f3e025270fd7c23b2911c3a7790a296ea059e..257d4d5ee99210fbe514ba571378836f23fa51a4 100644 (file)
 #![feature(const_fn)]
 
 trait Foo {
-    const fn f() -> u32; //~ ERROR trait fns cannot be declared const
-    const fn g() -> u32 { 0 } //~ ERROR trait fns cannot be declared const
+    const fn f() -> u32;
+    //~^ ERROR trait fns cannot be declared const
+    //~| NOTE trait fns cannot be const
+    const fn g() -> u32 { 0 }
+    //~^ ERROR trait fns cannot be declared const
+    //~| NOTE trait fns cannot be const
 }
 
 fn main() { }
index 72a5c5fff608457b2d5770316c4ba62b6a9cf341..a73164b957c831a8896859fb196858d2b3fb493d 100644 (file)
 
 const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync));
 //~^ ERROR `std::fmt::Debug + Sync + 'static: std::marker::Sized` is not satisfied
+//~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied
 //~| NOTE does not have a constant size known at compile-time
 //~| NOTE constant expressions must have a statically known size
 
 const CONST_FOO: str = *"foo";
 //~^ ERROR `str: std::marker::Sized` is not satisfied
+//~| NOTE `str: std::marker::Sized` not satisfied
 //~| NOTE does not have a constant size known at compile-time
 //~| NOTE constant expressions must have a statically known size
 
 static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync));
 //~^ ERROR `std::fmt::Debug + Sync + 'static: std::marker::Sized` is not satisfied
+//~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied
 //~| NOTE does not have a constant size known at compile-time
 //~| NOTE constant expressions must have a statically known size
 
 static STATIC_BAR: str = *"bar";
 //~^ ERROR `str: std::marker::Sized` is not satisfied
+//~| NOTE `str: std::marker::Sized` not satisfied
 //~| NOTE does not have a constant size known at compile-time
 //~| NOTE constant expressions must have a statically known size
 
diff --git a/src/test/compile-fail/diverging-fn-tail-35849.rs b/src/test/compile-fail/diverging-fn-tail-35849.rs
new file mode 100644 (file)
index 0000000..6dc447b
--- /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.
+
+fn _converge() -> ! { //~ ERROR computation may converge
+    42
+}
+
+fn main() { }
+
diff --git a/src/test/compile-fail/enable-orbit-for-incr-comp.rs b/src/test/compile-fail/enable-orbit-for-incr-comp.rs
deleted file mode 100644 (file)
index eec6bad..0000000
+++ /dev/null
@@ -1,20 +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-pretty
-// compile-flags:-Zincremental=tmp/cfail-tests/enable-orbit-for-incr-comp -Zorbit=off
-// error-pattern:Automatically enabling `-Z orbit` because `-Z incremental` was specified
-
-#![deny(warnings)]
-
-fn main() {
-    FAIL! // We just need some compilation error. What we really care about is
-          // that the error pattern above is checked.
-}
index a6793ee8b9fbda001b64993f792666074de93db0..527ac7505a654b15c068ecd704390adee28932e8 100644 (file)
@@ -8,11 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-enum Foo { //~ NOTE previous definition
+enum Foo { //~ NOTE previous definition of `Foo` here
     X
 }
 
 mod Foo { //~ ERROR a type named `Foo` has already been defined
+          //~| NOTE already defined
     pub static X: isize = 42;
     fn f() { f() } // Check that this does not result in a resolution error
 }
diff --git a/src/test/compile-fail/feature-gate-abi-sysv64.rs b/src/test/compile-fail/feature-gate-abi-sysv64.rs
new file mode 100644 (file)
index 0000000..2a4aae8
--- /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.
+
+// Test that the sysv64 ABI cannot be used when abi-sysv64 feature
+// gate is not used.
+
+extern "sysv64" fn foo() {}
+//~^ ERROR sysv64 ABI is experimental and subject to change
+
+fn main() {
+    foo();
+}
index e9dd1cb719dbcc88455cab8a61d517fa6e37e77d..d0d911b6eb93600ae4af8f5351e4a66bfd968bab 100644 (file)
@@ -19,9 +19,9 @@ fn apply<T, F>(t: T, f: F) where F: FnOnce(T) {
 fn main() {
     apply(&3, takes_imm);
     apply(&3, takes_mut);
-    //~^ ERROR (values differ in mutability)
+    //~^ ERROR (types differ in mutability)
 
     apply(&mut 3, takes_mut);
     apply(&mut 3, takes_imm);
-    //~^ ERROR (values differ in mutability)
+    //~^ ERROR (types differ in mutability)
 }
diff --git a/src/test/compile-fail/gated-attr-literals.rs b/src/test/compile-fail/gated-attr-literals.rs
new file mode 100644 (file)
index 0000000..f3132d5
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that literals in attributes don't parse without the feature gate.
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+#[fake_attr] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(100)] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes
+#[fake_attr(1, 2, 3)] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes
+#[fake_attr("hello")] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR string literals in top-level positions, are experimental
+#[fake_attr(name = "hello")] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes, or string literals in top-level positions
+#[fake_attr(key = "hello", val = 10)] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes
+#[fake_attr(key("hello"), val(10))] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes, or string literals in top-level positions
+#[fake_attr(enabled = true, disabled = false)] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes
+#[fake_attr(true)] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes
+#[fake_attr(pi = 3.14159)] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes
+#[fake_attr(b"hi")] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR string literals in top-level positions, are experimental
+#[fake_doc(r"doc")] //~ ERROR attribute `fake_doc` is currently unknown
+    //~^ ERROR string literals in top-level positions, are experimental
+struct Q {  }
+
+#[rustc_error]
+fn main() { }
index 2c78ce2db29afe76ebf64ff08ea381c4e4f45e47..60ad266e7f7daaaf7857c03dc2f4d2c9cffa8dc3 100644 (file)
@@ -26,6 +26,7 @@ fn send<T: Send>(_: T) {}
 fn main() {
     send(before());
     //~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
+    //~| NOTE trait `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` not satisfied
     //~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
     //~| NOTE required because it appears within the type `[closure
     //~| NOTE required because it appears within the type `impl std::ops::Fn<(i32,)>`
@@ -33,6 +34,7 @@ fn main() {
 
     send(after());
     //~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
+    //~| NOTE trait `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` not satisfied
     //~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
     //~| NOTE required because it appears within the type `[closure
     //~| NOTE required because it appears within the type `impl std::ops::Fn<(i32,)>`
@@ -52,6 +54,7 @@ fn after() -> impl Fn(i32) {
 fn cycle1() -> impl Clone {
     send(cycle2().clone());
     //~^ ERROR the trait bound `std::rc::Rc<std::string::String>: std::marker::Send` is not satisfied
+    //~| NOTE trait `std::rc::Rc<std::string::String>: std::marker::Send` not satisfied
     //~| NOTE `std::rc::Rc<std::string::String>` cannot be sent between threads safely
     //~| NOTE required because it appears within the type `impl std::clone::Clone`
     //~| NOTE required by `send`
@@ -62,6 +65,7 @@ fn cycle1() -> impl Clone {
 fn cycle2() -> impl Clone {
     send(cycle1().clone());
     //~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
+    //~| NOTE trait `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` not satisfied
     //~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
     //~| NOTE required because it appears within the type `impl std::clone::Clone`
     //~| NOTE required by `send`
index ceaa8f4eed72348dfa1e34e2db89c42b261c22eb..8dfcb08cff339b4153037ec430e0aa462a871b78 100644 (file)
 fn borrow<'a, T>(_: &'a mut T) -> impl Copy { () }
 
 fn main() {
-    //~^ NOTE reference must be valid for the block
     let long;
     let mut short = 0;
-    //~^ NOTE but borrowed value is only valid for the block suffix following statement 1
     long = borrow(&mut short);
     //~^ ERROR `short` does not live long enough
-}
+    //~| NOTE does not live long enough
+    //~| NOTE values in a scope are dropped in the opposite order they are created
+} //~ borrowed value dropped before borrower
index e0ea1a4cac58bb83102cacf447fb478961897928..388c9a1729cca08e5a8a510807bcf516b87fd1ba 100644 (file)
@@ -12,9 +12,9 @@
 
 trait Foo {
     fn bar(&self);
-    //~^ NOTE original trait requirement
-    //~| NOTE original trait requirement
-    const MY_CONST: u32; //~ NOTE original trait requirement
+    //~^ NOTE item in trait
+    //~| NOTE item in trait
+    const MY_CONST: u32; //~ NOTE item in trait
 }
 
 pub struct FooConstForMethod;
index bcd2cd816ed4560817dd23a21d682fc710f0567d..220b255bde419e9371f58c092c2f31e63cd15ed3 100644 (file)
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use spam::{ham, eggs};
-//~^ ERROR unresolved import `spam::eggs`. There is no `eggs` in `spam`
+use spam::{ham, eggs}; //~ ERROR unresolved import `spam::eggs` [E0432]
+                       //~^ no `eggs` in `spam`
 
 mod spam {
     pub fn ham() { }
index ff93cd0f0662436c00efd1e4e9946102c46eb0df..1ca1c060410adb1b44fecc132103d2fc78680000 100644 (file)
@@ -9,13 +9,14 @@
 // except according to those terms.
 
 use zed::bar;
-use zed::baz;
-//~^ ERROR unresolved import `zed::baz`. There is no `baz` in `zed`
+use zed::baz; //~ ERROR unresolved import `zed::baz` [E0432]
+              //~^ no `baz` in `zed`. Did you mean to use `bar`?
 
 
 mod zed {
     pub fn bar() { println!("bar"); }
-    use foo; //~ ERROR unresolved import
+    use foo; //~ ERROR unresolved import `foo` [E0432]
+             //~^ no `foo` in the root
 }
 
 fn main() {
index 1f25bce209314e6fe5fb4b2ce31d6daa700c8cd9..f5b03f9b2e97158ec104827b6d7ed94ef9687cf4 100644 (file)
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use baz::zed::bar;
-//~^ ERROR unresolved import `baz::zed::bar`. Could not find `zed` in `baz`
+use baz::zed::bar; //~ ERROR unresolved import `baz::zed::bar` [E0432]
+                   //~^ Could not find `zed` in `baz`
 
 mod baz {}
 mod zed {
diff --git a/src/test/compile-fail/imports/duplicate.rs b/src/test/compile-fail/imports/duplicate.rs
new file mode 100644 (file)
index 0000000..fb61bb8
--- /dev/null
@@ -0,0 +1,70 @@
+// 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(item_like_imports)]
+
+mod a {
+    pub fn foo() {}
+}
+
+mod b {
+    pub fn foo() {}
+}
+
+mod c {
+    pub use a::foo;
+}
+
+mod d {
+    use a::foo; //~ NOTE previous import
+    use a::foo; //~ ERROR `foo` has already been imported
+                //~| NOTE already imported
+}
+
+mod e {
+    pub use a::*;
+    pub use c::*; // ok
+}
+
+mod f {
+    pub use a::*; //~ NOTE `foo` could resolve to the name imported here
+    pub use b::*; //~ NOTE `foo` could also resolve to the name imported here
+}
+
+mod g {
+    pub use a::*; //~ NOTE `foo` could resolve to the name imported here
+    pub use f::*; //~ NOTE `foo` could also resolve to the name imported here
+}
+
+fn main() {
+    e::foo();
+    f::foo(); //~ ERROR `foo` is ambiguous
+              //~| NOTE Consider adding an explicit import of `foo` to disambiguate
+    g::foo(); //~ ERROR `foo` is ambiguous
+              //~| NOTE Consider adding an explicit import of `foo` to disambiguate
+}
+
+mod ambiguous_module_errors {
+    pub mod m1 { pub use super::m1 as foo; }
+    pub mod m2 { pub use super::m2 as foo; }
+
+    use self::m1::*; //~ NOTE
+                     //~| NOTE
+    use self::m2::*; //~ NOTE
+                     //~| NOTE
+
+    use self::foo::bar; //~ ERROR `foo` is ambiguous
+                        //~| NOTE
+
+    fn f() {
+        foo::bar(); //~ ERROR `foo` is ambiguous
+                    //~| NOTE
+    }
+}
diff --git a/src/test/compile-fail/imports/reexports.rs b/src/test/compile-fail/imports/reexports.rs
new file mode 100644 (file)
index 0000000..fc46b23
--- /dev/null
@@ -0,0 +1,44 @@
+// 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(item_like_imports)]
+
+mod a {
+    fn foo() {}
+    mod foo {}
+
+    mod a {
+        pub use super::foo; //~ ERROR cannot be reexported
+        pub use super::*; //~ ERROR must import something with the glob's visibility
+    }
+}
+
+mod b {
+    pub fn foo() {}
+    mod foo { pub struct S; }
+
+    pub mod a {
+        pub use super::foo; // This is OK since the value `foo` is visible enough.
+        fn f(_: foo::S) {} // `foo` is imported in the type namespace (but not `pub` reexported).
+    }
+
+    pub mod b {
+        pub use super::*; // This is also OK since the value `foo` is visible enough.
+        fn f(_: foo::S) {} // Again, the module `foo` is imported (but not `pub` reexported).
+    }
+}
+
+mod c {
+    // Test that `foo` is not reexported.
+    use b::a::foo::S; //~ ERROR `foo`
+    use b::b::foo::S as T; //~ ERROR `foo`
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-11004.rs b/src/test/compile-fail/issue-11004.rs
new file mode 100644 (file)
index 0000000..308be46
--- /dev/null
@@ -0,0 +1,39 @@
+// 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;
+
+struct A { x: i32, y: f64 }
+
+#[cfg(not(works))]
+unsafe fn access(n:*mut A) -> (i32, f64) {
+    let x : i32 = n.x; //~ ERROR attempted access of field `x`
+                       //~| NOTE `n` is a native pointer; perhaps you need to deref with `(*n).x`
+    let y : f64 = n.y; //~ ERROR attempted access of field `y`
+                       //~| NOTE `n` is a native pointer; perhaps you need to deref with `(*n).y`
+    (x, y)
+}
+
+#[cfg(works)]
+unsafe fn access(n:*mut A) -> (i32, f64) {
+    let x : i32 = (*n).x;
+    let y : f64 = (*n).y;
+    (x, y)
+}
+
+fn main() {
+    let a :  A = A { x: 3, y: 3.14 };
+    let p : &A = &a;
+    let (x,y) = unsafe {
+        let n : *mut A = mem::transmute(p);
+        access(n)
+    };
+    println!("x: {}, y: {}", x, y);
+}
diff --git a/src/test/compile-fail/issue-11925.rs b/src/test/compile-fail/issue-11925.rs
deleted file mode 100644 (file)
index 7bd072c..0000000
+++ /dev/null
@@ -1,23 +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.
-
-#![feature(box_syntax, unboxed_closures)]
-
-fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
-
-fn main() {
-    let r = {
-        let x: Box<_> = box 42;
-        let f = to_fn_once(move|| &x); //~ ERROR: `x` does not live long enough
-        f()
-    };
-
-    drop(r);
-}
index f76d12d93fdf68cf9227aa2c3a5e97bb792861d9..20943bd0ea0773f8737ad45f264f81af41f89756 100644 (file)
@@ -15,8 +15,8 @@
 use foo::bar;
 
 mod test {
-    use bar::foo;
-    //~^ ERROR unresolved import `bar::foo`. Maybe a missing `extern crate bar`?
+    use bar::foo; //~ ERROR unresolved import `bar::foo` [E0432]
+                  //~^ Maybe a missing `extern crate bar`?
 }
 
 fn main() {}
index 355be1562df2bdb555c5acaff7d0ee4d76ce5283..0059e92e07f07a8aa29ae13cfb8ff78e6395509e 100644 (file)
@@ -9,8 +9,8 @@
 // except according to those terms.
 
 use a::f;
-use b::f;
-//~^ ERROR: unresolved import `b::f`. There is no `f` in `b`
+use b::f; //~ ERROR: unresolved import `b::f` [E0432]
+          //~^ no `f` in `b`
 
 mod a { pub fn f() {} }
 mod b { }
index ceac7e968f65c1bceaa43574b75712d3ccd8e7ec..5012556dedddc3c98c3fc1e0a912243f97568a89 100644 (file)
@@ -29,6 +29,7 @@ fn new(buf: &'a mut [u8]) -> Foo<'a> {
 impl<'a> NoLifetime for Foo<'a> {
     fn get<'p, T : Test<'a>>(&self) -> T {
 //~^ ERROR E0195
+//~| lifetimes do not match trait
         return *self as T;
     }
 }
index f2d858391cea2ae5b10f0d298ec7318e5ef92ba1..dc09af0ada66f0cb03285baf96f3d8e2eeabbc61 100644 (file)
@@ -10,6 +10,7 @@
 
 // Testing that we don't fail abnormally after hitting the errors
 
-use unresolved::*; //~ ERROR unresolved import `unresolved::*`. Maybe a missing `extern crate unres
+use unresolved::*; //~ ERROR unresolved import `unresolved::*` [E0432]
+                   //~^ Maybe a missing `extern crate unresolved`?
 
 fn main() {}
index e3e56c7f97ad5ba400b76d5c622f5c694873b6db..8e3faca02b7d1cef64a9a6a1f959859f915f29c6 100644 (file)
@@ -13,5 +13,7 @@ enum Foo {
 }
 
 fn main() {
-    let f = Foo::Variant(42); //~ ERROR uses it like a function
+    let f = Foo::Variant(42);
+    //~^ ERROR uses it like a function
+    //~| struct called like a function
 }
index 2270ba594ad2bfc5439f1be512f89054bcad6648..15d5d2b80c31d0053eeb75ae2915cefecbce8a19 100644 (file)
@@ -13,5 +13,7 @@ enum Homura {
 }
 
 fn main() {
-    let homura = Homura::Madoka; //~ ERROR uses it like a function
+    let homura = Homura::Madoka;
+    //~^ ERROR uses it like a function
+    //~| struct called like a function
 }
diff --git a/src/test/compile-fail/issue-20433.rs b/src/test/compile-fail/issue-20433.rs
new file mode 100644 (file)
index 0000000..d1a139e
--- /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.
+
+fn main() {}
+
+struct The;
+
+impl The {
+    fn iceman(c: Vec<[i32]>) {}
+    //~^ ERROR the trait bound `[i32]: std::marker::Sized` is not satisfied
+}
index 11d05ceb9a019d220e4fab6f23fffe374e779945..d103d45bc4cb75bb4b6ecf714f0ce572e87fdb6d 100644 (file)
@@ -17,6 +17,7 @@ mod Foo { }
 #[allow(dead_code)]
 struct Foo;
 //~^ ERROR a module named `Foo` has already been defined in this module
+//~| NOTE already defined
 
 #[allow(non_snake_case)]
 mod Bar { }
@@ -25,6 +26,7 @@ mod Bar { }
 #[allow(dead_code)]
 struct Bar(i32);
 //~^ ERROR a module named `Bar` has already been defined
+//~| NOTE already defined
 
 
 #[allow(dead_code)]
@@ -34,6 +36,7 @@ mod Bar { }
 #[allow(non_snake_case)]
 mod Baz { }
 //~^ ERROR a type named `Baz` has already been defined
+//~| NOTE already defined
 
 
 #[allow(dead_code)]
@@ -43,6 +46,7 @@ struct Qux { x: bool }
 #[allow(non_snake_case)]
 mod Qux { }
 //~^ ERROR a type named `Qux` has already been defined
+//~| NOTE already defined
 
 
 #[allow(dead_code)]
@@ -52,6 +56,7 @@ mod Qux { }
 #[allow(non_snake_case)]
 mod Quux { }
 //~^ ERROR a type named `Quux` has already been defined
+//~| NOTE already defined
 
 
 #[allow(dead_code)]
@@ -61,5 +66,6 @@ enum Corge { A, B }
 #[allow(non_snake_case)]
 mod Corge { }
 //~^ ERROR a type named `Corge` has already been defined
+//~| NOTE already defined
 
 fn main() { }
index 1028923ec82fd6464ae20c12711b55d012b66703..935f3480db24abfd6cd3d845e1e757fcbc06f679 100644 (file)
@@ -15,6 +15,9 @@
 fn main() {
     let x = &10 as
             &Add;
-            //~^ ERROR the type parameter `RHS` must be explicitly specified in an object type because its default value `Self` references the type `Self`
-            //~| ERROR the value of the associated type `Output` (from the trait `std::ops::Add`) must be specified
+            //~^ ERROR E0393
+            //~| NOTE missing reference to `RHS`
+            //~| NOTE because of the default `Self` reference, type parameters must be specified on object types
+            //~| ERROR E0191
+            //~| NOTE missing associated type `Output` value
 }
index 4c6652d812c8c7d0f9e4a9f5a619ca3acdda4263..51f342e3f0a435dc79a650a955ed204babe18cfa 100644 (file)
@@ -13,6 +13,8 @@
 trait A<T=Self> {}
 
 fn f(a: &A) {}
-//~^ ERROR the type parameter `T` must be explicitly specified in an object type because its default value `Self` references the type `Self`
+//~^ ERROR E0393
+//~| NOTE missing reference to `T`
+//~| NOTE because of the default `Self` reference, type parameters must be specified on object types
 
 fn main() {}
index 20ec2d64ae6a8ee0b78fa6813bfae74a131eac74..45b110bf5631ddcb251bae2f69f6bfd517be8997 100644 (file)
 use std::ops::{Add, Sub};
 
 type Test = Add +
-            //~^ ERROR the type parameter `RHS` must be explicitly specified in an object type because its default value `Self` references the type `Self`
-            //~^^ ERROR the value of the associated type `Output` (from the trait `std::ops::Add`) must be specified [E0191]
+            //~^ ERROR E0393
+            //~| NOTE missing reference to `RHS`
+            //~| NOTE because of the default `Self` reference, type parameters must be specified on object types
+            //~| ERROR E0191
+            //~| NOTE missing associated type `Output` value
             Sub;
-            //~^ ERROR only the builtin traits can be used as closure or object bounds
+            //~^ ERROR E0225
+            //~| NOTE non-builtin trait used as bounds
 
 fn main() { }
index 7ac8cf45edbefe8d443d7336666f7db41ca0421a..35f32d16a9a2a7470ba98647c4e073749e9093d3 100644 (file)
 // the appropriate error (rather than, say, blowing the stack).
 enum X {
     A = X::A as isize, //~ ERROR E0265
+                       //~^ NOTE recursion not allowed in constant
 }
 
 // Since `Y::B` here defaults to `Y::A+1`, this is also a
 // recursive definition.
 enum Y {
     A = Y::B as isize, //~ ERROR E0265
+                       //~^ NOTE recursion not allowed in constant
     B,
 }
 
+const A: i32 = B; //~ ERROR E0265
+                  //~^ NOTE recursion not allowed in constant
+
+const B: i32 = A; //~ ERROR E0265
+                  //~^ NOTE recursion not allowed in constant
+
 fn main() { }
index d7ec1ed67397fe939d1585dc32b60f535a8958f2..da92161967dbdc98921c9684174cbc913b757b45 100644 (file)
@@ -59,7 +59,9 @@ fn purr_louder() {
 impl cat {
   fn meow() {
     if self.whiskers > 3 {
-        //~^ ERROR: `self` is not available in a static method. Maybe a `self` argument is missing?
+        //~^ ERROR `self` is not available in a static method [E0424]
+        //~| NOTE not available in static method
+        //~| NOTE maybe a `self` argument is missing?
         println!("MEOW");
     }
   }
diff --git a/src/test/compile-fail/issue-24204.rs b/src/test/compile-fail/issue-24204.rs
new file mode 100644 (file)
index 0000000..2a012da
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+trait MultiDispatch<T> {
+    type O;
+}
+
+trait Trait: Sized {
+    type A: MultiDispatch<Self::B, O = Self>;
+    type B;
+
+    fn new<U>(u: U) -> <Self::A as MultiDispatch<U>>::O where Self::A : MultiDispatch<U>;
+}
+
+fn test<T: Trait<B=i32>>(b: i32) -> T where T::A: MultiDispatch<i32> { T::new(b) }
+//~^ ERROR type mismatch resolving
+
+fn main() {}
index 44b3ada97fea8c0de34029616bcd4a7101bfa23e..ceefd583a5ca6f1b22de8dd9c8403e625297ec08 100644 (file)
@@ -12,6 +12,7 @@ macro_rules! width(
     ($this:expr) => {
         $this.width.unwrap()
         //~^ ERROR cannot use `self.width` because it was mutably borrowed
+        //~| NOTE use of borrowed `*self`
     }
 );
 
index 00e1279d58a0eb850233acdd9967d7b975e6cb31..468282fa7cca9cfaa0997e52537f7eba34a3d8ae 100644 (file)
@@ -12,5 +12,6 @@ fn id<T>(t: T) -> T { t }
 fn main() {
     const A: bool = id::<u8> as *const () < id::<u16> as *const ();
     //~^ ERROR raw pointers cannot be compared in constants [E0395]
+    //~^^ NOTE comparing raw pointers in static
     println!("{}", A);
 }
diff --git a/src/test/compile-fail/issue-28308.rs b/src/test/compile-fail/issue-28308.rs
deleted file mode 100644 (file)
index b0c44b5..0000000
+++ /dev/null
@@ -1,17 +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.
-
-// this error is dispayed in `<std macros>`
-// error-pattern:cannot apply unary operator `!` to type `&'static str`
-// error-pattern:in this expansion of assert!
-
-fn main() {
-    assert!("foo");
-}
diff --git a/src/test/compile-fail/issue-28324.rs b/src/test/compile-fail/issue-28324.rs
new file mode 100644 (file)
index 0000000..13ce41f
--- /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.
+
+extern {
+    static error_message_count: u32;
+}
+
+pub static BAZ: u32 = *&error_message_count;
+//~^ ERROR cannot refer to other statics by value
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-28625.rs b/src/test/compile-fail/issue-28625.rs
new file mode 100644 (file)
index 0000000..c332e4e
--- /dev/null
@@ -0,0 +1,30 @@
+// 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.
+
+trait Bar {
+    type Bar;
+}
+
+struct ArrayPeano<T: Bar> {
+    data: T::Bar,
+}
+
+fn foo<T>(a: &ArrayPeano<T>) -> &[T] where T: Bar {
+    unsafe { std::mem::transmute(a) } //~ ERROR transmute called with differently sized types
+}
+
+impl Bar for () {
+    type Bar = ();
+}
+
+fn main() {
+    let x: ArrayPeano<()> = ArrayPeano { data: () };
+    foo(&x);
+}
index 52b0eba96cbdf59631f784bc662fe72f14cfc001..4a36bc88fa7d9d7aae7f5ca4daa8f703e0ccd88a 100644 (file)
@@ -13,5 +13,5 @@
 fn main() {
     (&ptr::write)(1 as *mut _, 42);
     //~^ ERROR E0133
-    //~| NOTE unsafe call requires unsafe function or block
+    //~| NOTE call to unsafe function
 }
index e4fae73b18991293ee9c9a7a1ada252ca7e276c5..0d684ec5ae19b4593f2a5b379857e62a989a09e1 100644 (file)
@@ -8,7 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use m::f as x; //~ ERROR unresolved import `m::f`. There is no `f` in `m`
+use m::f as x; //~ ERROR unresolved import `m::f` [E0432]
+               //~^ no `f` in `m`
 
 mod m {}
 
index 95a52cb232a490ddcb95106dd58139c02cb43b7c..fa0b75da999c29127d17e8f42b975f8dda479376 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(type_macros)]
-
 macro_rules! t {
     () => ( String ; );     //~ ERROR macro expansion ignores token `;`
 }
index 71c7e6009655b7e514eb7d0241e9b7ed182fdb90..b0cfd8714fc028969d84f8515ac3372c587f8f7b 100644 (file)
@@ -9,8 +9,12 @@
 // except according to those terms.
 
 type Alias = ();
-use Alias::*; //~ ERROR Not a module
-use std::io::Result::*; //~ ERROR Not a module
+use Alias::*;
+//~^ ERROR unresolved import `Alias::*` [E0432]
+//~| Not a module `Alias`
+use std::io::Result::*;
+//~^ ERROR unresolved import `std::io::Result::*` [E0432]
+//~| Not a module `Result`
 
 trait T {}
 use T::*; //~ ERROR items in traits are not importable
index 22261d98a128c98260eaaffaae6ab491ce2638d7..d610e8b483798af81cf2c1df4a57f5054a925b72 100644 (file)
@@ -8,9 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use bar::Foo; //~ ERROR There is no `Foo` in `bar` [E0432]
+use bar::Foo; //~ ERROR unresolved import `bar::Foo` [E0432]
+              //~^ no `Foo` in `bar`
 mod bar {
-    use Foo; //~ ERROR There is no `Foo` in the crate root [E0432]
+    use Foo; //~ ERROR unresolved import `Foo` [E0432]
+             //~^ no `Foo` in the root
 }
 
 fn main() {}
index e8ca1c1fa98ff4a99c755f274b3a7d3aa2c8f799..20e5b1d72d3d71a9f8ce4c9e716b1f1362db9f8c 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(type_macros, concat_idents)]
+#![feature(concat_idents)]
 
 #[derive(Debug)] //~ NOTE in this expansion
 struct Baz<T>(
index c4e8f7661175236022333fef3788f65467ccf9c9..8ba95d14931e0b335914711d808c144ad8f5efee 100644 (file)
@@ -17,4 +17,5 @@ fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
 fn main() {
     size_of_copy::<Misc+Copy>();
     //~^ ERROR `Misc + Copy: std::marker::Copy` is not satisfied
+    //~| ERROR the trait `std::marker::Copy` cannot be made into an object
 }
diff --git a/src/test/compile-fail/issue-35869.rs b/src/test/compile-fail/issue-35869.rs
new file mode 100644 (file)
index 0000000..8b7fc80
--- /dev/null
@@ -0,0 +1,37 @@
+// 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(conservative_impl_trait)]
+
+trait Foo {
+    fn foo(fn(u8) -> ()); //~ NOTE type in trait
+    fn bar(Option<u8>); //~ NOTE type in trait
+    fn baz((u8, u16)); //~ NOTE type in trait
+    fn qux() -> u8; //~ NOTE type in trait
+}
+
+struct Bar;
+
+impl Foo for Bar {
+    fn foo(_: fn(u16) -> ()) {}
+    //~^ ERROR method `foo` has an incompatible type for trait
+    //~| NOTE expected u8
+    fn bar(_: Option<u16>) {}
+    //~^ ERROR method `bar` has an incompatible type for trait
+    //~| NOTE expected u8
+    fn baz(_: (u16, u16)) {}
+    //~^ ERROR method `baz` has an incompatible type for trait
+    //~| NOTE expected u8
+    fn qux() -> u16 { 5u16 }
+    //~^ ERROR method `qux` has an incompatible type for trait
+    //~| NOTE expected u8
+}
+
+fn main() {}
index c2154e8a6c0b605ce78e135875aa19a2e414ecf9..7a36012925eed415f3c836f067946553e1bd9f33 100644 (file)
@@ -14,7 +14,8 @@ impl K for isize {} //~ ERROR: `K` is not a trait
                     //~| NOTE: not a trait
                     //~| NOTE: aliases cannot be used for traits
 
-use ImportError; //~ ERROR unresolved
+use ImportError; //~ ERROR unresolved import `ImportError` [E0432]
+                 //~^ no `ImportError` in the root
 impl ImportError for () {} // check that this is not an additional error (c.f. #35142)
 
 fn main() {}
index 318089b3030f613d227c84f4b4957a4194c7dc28..670b6bd46e7d82a88455b82ce017c47d8b7f590c 100644 (file)
@@ -8,14 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use self::*; //~ ERROR: unresolved import `self::*`. Cannot glob-import a module into itself.
+use self::*; //~ ERROR: unresolved import `self::*` [E0432]
+             //~^ Cannot glob-import a module into itself.
 
 mod foo {
-    use foo::*; //~ ERROR: unresolved import `foo::*`. Cannot glob-import a module into itself.
+    use foo::*; //~ ERROR: unresolved import `foo::*` [E0432]
+                //~^ Cannot glob-import a module into itself.
 
     mod bar {
         use super::bar::*;
-        //~^ ERROR: unresolved import `super::bar::*`. Cannot glob-import a module into itself.
+        //~^ ERROR: unresolved import `super::bar::*` [E0432]
+        //~| Cannot glob-import a module into itself.
     }
 
 }
index fd2513c5a066daaa728aef75e6392a73ce588c6f..a23083b5c8c11ef5a00fd29ea6a0351636bd63a3 100644 (file)
@@ -9,8 +9,10 @@
 // except according to those terms.
 
 #![forbid(deprecated)]
-//~^ NOTE `forbid` lint level set here
+//~^ NOTE `forbid` level set here
 
-#[allow(deprecated)] //~ ERROR allow(deprecated) overruled by outer forbid(deprecated)
+#[allow(deprecated)]
+//~^ ERROR allow(deprecated) overruled by outer forbid(deprecated)
+//~| NOTE overruled by previous forbid
 fn main() {
 }
diff --git a/src/test/compile-fail/lint-no-drop-on-repr-extern.rs b/src/test/compile-fail/lint-no-drop-on-repr-extern.rs
deleted file mode 100644 (file)
index 91e5065..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Check we reject structs that mix a `Drop` impl with `#[repr(C)]`.
-//
-// As a special case, also check that we do not warn on such structs
-// if they also are declared with `#[unsafe_no_drop_flag]`
-
-#![feature(unsafe_no_drop_flag)]
-#![deny(drop_with_repr_extern)]
-//~^ NOTE lint level defined here
-//~| NOTE lint level defined here
-
-#[repr(C)] struct As { x: Box<i8> }
-#[repr(C)] enum Ae { Ae(Box<i8>), _None }
-
-struct Bs { x: Box<i8> }
-enum Be { Be(Box<i8>), _None }
-
-#[repr(C)] struct Cs { x: Box<i8> }
-//~^ NOTE the `#[repr(C)]` attribute is attached here
-
-impl Drop for Cs { fn drop(&mut self) { } }
-//~^ ERROR implementing Drop adds hidden state to types, possibly conflicting with `#[repr(C)]`
-
-#[repr(C)] enum Ce { Ce(Box<i8>), _None }
-//~^ NOTE the `#[repr(C)]` attribute is attached here
-
-impl Drop for Ce { fn drop(&mut self) { } }
-//~^ ERROR implementing Drop adds hidden state to types, possibly conflicting with `#[repr(C)]`
-
-#[unsafe_no_drop_flag]
-#[repr(C)] struct Ds { x: Box<i8> }
-
-impl Drop for Ds { fn drop(&mut self) { } }
-
-#[unsafe_no_drop_flag]
-#[repr(C)] enum De { De(Box<i8>), _None }
-
-impl Drop for De { fn drop(&mut self) { } }
-
-fn main() {
-    let a = As { x: Box::new(3) };
-    let b = Bs { x: Box::new(3) };
-    let c = Cs { x: Box::new(3) };
-    let d = Ds { x: Box::new(3) };
-
-    println!("{:?}", (*a.x, *b.x, *c.x, *d.x));
-
-    let _a = Ae::Ae(Box::new(3));
-    let _b = Be::Be(Box::new(3));
-    let _c = Ce::Ce(Box::new(3));
-    let _d = De::De(Box::new(3));
-}
diff --git a/src/test/compile-fail/macro-backtrace-invalid-internals.rs b/src/test/compile-fail/macro-backtrace-invalid-internals.rs
deleted file mode 100644 (file)
index ebec204..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Macros in statement vs expression position handle backtraces differently.
-
-macro_rules! fake_method_stmt {
-     () => {
-          1.fake() //~ ERROR no method named `fake` found
-     }
-}
-
-macro_rules! fake_field_stmt {
-     () => {
-          1.fake //~ ERROR no field with that name
-     }
-}
-
-macro_rules! fake_anon_field_stmt {
-     () => {
-          (1).0 //~ ERROR type was not a tuple
-     }
-}
-
-macro_rules! fake_method_expr {
-     () => {
-          1.fake() //~ ERROR no method named `fake` found
-     }
-}
-
-macro_rules! fake_field_expr {
-     () => {
-          1.fake //~ ERROR no field with that name
-     }
-}
-
-macro_rules! fake_anon_field_expr {
-     () => {
-          (1).0 //~ ERROR type was not a tuple
-     }
-}
-
-fn main() {
-    fake_method_stmt!(); //~ NOTE in this expansion of
-    fake_field_stmt!(); //~ NOTE in this expansion of
-    fake_anon_field_stmt!(); //~ NOTE in this expansion of
-
-    let _ = fake_method_expr!(); //~ NOTE in this expansion of
-    let _ = fake_field_expr!(); //~ NOTE in this expansion of
-    let _ = fake_anon_field_expr!(); //~ NOTE in this expansion of
-}
diff --git a/src/test/compile-fail/macro-backtrace-nested.rs b/src/test/compile-fail/macro-backtrace-nested.rs
deleted file mode 100644 (file)
index c2a270e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// In expression position, but not statement position, when we expand a macro,
-// we replace the span of the expanded expression with that of the call site.
-
-macro_rules! nested_expr {
-    () => (fake) //~ ERROR unresolved name
-                 //~^ ERROR unresolved name
-}
-
-macro_rules! call_nested_expr {
-    () => (nested_expr!()) //~ NOTE in this expansion of nested_expr!
-}
-
-macro_rules! call_nested_expr_sum {
-    () => { 1 + nested_expr!(); } //~ NOTE in this expansion of nested_expr!
-}
-
-fn main() {
-    1 + call_nested_expr!(); //~ NOTE in this expansion of call_nested_expr!
-    call_nested_expr_sum!(); //~ NOTE in this expansion of
-}
diff --git a/src/test/compile-fail/macro-backtrace-println.rs b/src/test/compile-fail/macro-backtrace-println.rs
deleted file mode 100644 (file)
index 9d6da2a..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// The `format_args!` syntax extension issues errors before code expansion
-// has completed, but we still need a backtrace.
-
-// This test includes stripped-down versions of `print!` and `println!`,
-// because we can't otherwise verify the lines of the backtrace.
-
-fn print(_args: std::fmt::Arguments) {}
-
-macro_rules! myprint {
-    ($($arg:tt)*) => (print(format_args!($($arg)*)));   //~ NOTE in this expansion of
-}
-
-macro_rules! myprintln {
-    ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ ERROR invalid reference to argument `0`
-                                                    //~| NOTE in this expansion of concat!
-                                                    //~| NOTE in this expansion of myprint!
-}
-
-fn main() {
-    myprintln!("{}"); //~ NOTE in this expansion of
-}
index 5d07f0747ff435316db7367cd4ea210baa74e02d..4aa0a3023bb109ed5398458c65e258329a1e6928 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(type_macros)]
-
 // (typeof used because it's surprisingly hard to find an unparsed token after a stmt)
 macro_rules! m {
     () => ( i ; typeof );   //~ ERROR expected expression, found reserved keyword `typeof`
index a69188da58d1667686ab896b9d0d005805b76337..4a6dbf014a1cace35ae973c1daa5cf77ca3bade8 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(type_macros)]
-
 macro_rules! foo {
     ($a:expr) => $a; //~ ERROR macro rhs must be delimited
 }
diff --git a/src/test/compile-fail/missing-block-hint.rs b/src/test/compile-fail/missing-block-hint.rs
new file mode 100644 (file)
index 0000000..1f29ff4
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    {
+        if (foo) => {} //~ ERROR expected `{`, found `=>`
+    }
+    {
+        if (foo)
+            bar; //~ ERROR expected `{`, found `bar`
+                 //^ HELP try placing this code inside a block
+    }
+}
index 318d121e4c2df45f20ceaecc3fd512f7b00ba203..7685a5c0808a2dad39a3dd64c472617086d5ea1c 100644 (file)
@@ -16,7 +16,7 @@ fn main() {
      let &_ //~  ERROR mismatched types
             //~| expected type `&mut {integer}`
             //~| found type `&_`
-            //~| values differ in mutability
+            //~| types differ in mutability
         = foo;
     let &mut _ = foo;
 
@@ -25,6 +25,6 @@ fn main() {
     let &mut _ //~  ERROR mismatched types
                //~| expected type `&{integer}`
                //~| found type `&mut _`
-               //~| values differ in mutability
+               //~| types differ in mutability
          = bar;
 }
index 0df8c41ffe1a8e52ae7fa2f710305af478c78348..cc7c2f4f796d93bd0b8711aa566cc8073d7964ec 100644 (file)
@@ -42,14 +42,17 @@ fn index(&self, _index: Bar<usize>) -> &i32 {
 fn main() {
     Index::index(&[] as &[i32], 2u32);
     //~^ ERROR E0277
+    //~| NOTE not satisfied
     //~| NOTE trait message
     //~| NOTE required by
     Index::index(&[] as &[i32], Foo(2u32));
     //~^ ERROR E0277
+    //~| NOTE not satisfied
     //~| NOTE on impl for Foo
     //~| NOTE required by
     Index::index(&[] as &[i32], Bar(2u32));
     //~^ ERROR E0277
+    //~| NOTE not satisfied
     //~| NOTE on impl for Bar
     //~| NOTE required by
 }
index 4471b625d7912fd4b79ac1913aaaa3cb687e4774..c22e48bede4efdd61f87ee53f579125ffcb5b431 100644 (file)
@@ -30,6 +30,7 @@ fn index(&self, index: usize) -> &i32 {
 #[rustc_error]
 fn main() {
     Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32); //~ ERROR E0277
+                                                     //~| NOTE not satisfied
                                                      //~| NOTE a usize is required
                                                      //~| NOTE required by
 }
index 39ce1b33ca13122b275642f24761987f645aab0f..9ea2809374cd83adf601215bc52c3d23c5f996fb 100644 (file)
@@ -35,7 +35,9 @@ pub fn main() {
     //~^ ERROR
     //~^^ NOTE a collection of type `std::option::Option<std::vec::Vec<u8>>` cannot be built from an iterator over elements of type `&u8`
     //~^^^ NOTE required by `collect`
+    //~| NOTE trait `std::option::Option<std::vec::Vec<u8>>: MyFromIterator<&u8>` not satisfied
     let x: String = foobar(); //~ ERROR
     //~^ NOTE test error `std::string::String` with `u8` `_` `u32`
     //~^^ NOTE required by `foobar`
+    //~| NOTE trait `std::string::String: Foo<u8, _, u32>` not satisfied
 }
index 6a8f9d471e1692254619e788ed400abfec7299a3..5c548b5d5bf20760ad1d3c69f78c1f6da03a12a3 100644 (file)
@@ -18,7 +18,9 @@
 fn main() {
     let x = &[1, 2, 3] as &[i32];
     x[1i32]; //~ ERROR E0277
+             //~| NOTE trait `[i32]: std::ops::Index<i32>` not satisfied
              //~| NOTE slice indices are of type `usize`
     x[..1i32]; //~ ERROR E0277
+               //~| NOTE trait `[i32]: std::ops::Index<std::ops::RangeTo<i32>>` not satisfied
                //~| NOTE slice indices are of type `usize`
 }
index 9cc53386d465c50484f6e57d926a1a0ca96299b5..f3dcf405a68a6276abc0e99abc36df62e5baef40 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(pub_restricted, type_macros)]
+#![feature(pub_restricted)]
 
 mod foo {
     type T = ();
index 01466c6a85a5ae5c94e7887bd22c68e308668b3e..3bf8ca30a6c3fe42df1b46936704d56cdce21c24 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(pub_restricted, type_macros)]
+#![feature(pub_restricted)]
 
 macro_rules! define_struct {
     ($t:ty) => {
index ef187a1daed37106f6529f2df1a46deeb012cfe6..febe224fb84dcf14ce2294d6b1940109b13e9843 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(pub_restricted, type_macros)]
+#![feature(pub_restricted)]
 
 macro_rules! define_struct {
     ($t:ty) => {
index abf702204d16baef221f412b22dd0e3ecc0b8004..376e95312b8fbf6b1cc7df7034e1bf42cbae3edc 100644 (file)
@@ -25,12 +25,14 @@ pub fn foo() {}
 
 fn test1() {
     use bar::foo;
-    //~^ ERROR unresolved import `bar::foo`. There is no `foo` in `bar`
+    //~^ ERROR unresolved import `bar::foo` [E0432]
+    //~| no `foo` in `bar`
 }
 
 fn test2() {
     use bar::glob::foo;
-    //~^ ERROR unresolved import `bar::glob::foo`. There is no `foo` in `bar::glob`
+    //~^ ERROR unresolved import `bar::glob::foo` [E0432]
+    //~| no `foo` in `bar::glob`
 }
 
 #[start] fn main(_: isize, _: *const *const u8) -> isize { 3 }
index 89f38fa14344580d230d84e46deade7c27e52e32..b841717bd11d8c24675b93ae3d93d521e0228e20 100644 (file)
@@ -26,7 +26,8 @@ pub fn foo() {}
 
 fn test1() {
     use bar::gpriv;
-    //~^ ERROR unresolved import `bar::gpriv`. There is no `gpriv` in `bar`
+    //~^ ERROR unresolved import `bar::gpriv` [E0432]
+    //~| no `gpriv` in `bar`
 
     // This should pass because the compiler will insert a fake name binding
     // for `gpriv`
index ff627e69d4c58f6d4d521a25030f895329ec2a59..1390c9507c1c2fd640b53a8bc65efdbd30dc9629 100644 (file)
@@ -17,17 +17,17 @@ pub fn main() {
     let x: *mut isize = x; //~  ERROR mismatched types
                            //~| expected type `*mut isize`
                            //~| found type `*const isize`
-                           //~| values differ in mutability
+                           //~| types differ in mutability
 
     // & -> *mut
     let x: *mut isize = &42; //~  ERROR mismatched types
                              //~| expected type `*mut isize`
                              //~| found type `&isize`
-                             //~| values differ in mutability
+                             //~| types differ in mutability
 
     let x: *const isize = &42;
     let x: *mut isize = x; //~  ERROR mismatched types
                            //~| expected type `*mut isize`
                            //~| found type `*const isize`
-                           //~| values differ in mutability
+                           //~| types differ in mutability
 }
diff --git a/src/test/compile-fail/question-mark-type-infer.rs b/src/test/compile-fail/question-mark-type-infer.rs
new file mode 100644 (file)
index 0000000..e15c9af
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(question_mark, question_mark_carrier)]
+
+// Test that type inference fails where there are multiple possible return types
+// for the `?` operator.
+
+fn f(x: &i32) -> Result<i32, ()> {
+    Ok(*x)
+}
+
+fn g() -> Result<Vec<i32>, ()> {
+    let l = [1, 2, 3, 4];
+    l.iter().map(f).collect()? //~ ERROR type annotations required: cannot resolve
+}
+
+fn main() {
+    g();
+}
index 6be2adbe2a0d1ac0eb200159b11af647bc1f875b..18206a68515fe9c4503322588f7cd635582d5336 100644 (file)
 
 fn escaping_borrow_of_closure_params_1() {
     let g = |x: usize, y:usize| {
-        //~^ NOTE reference must be valid for the scope of call-site for function
-        //~| NOTE ...but borrowed value is only valid for the scope of function body
-        //~| NOTE reference must be valid for the scope of call-site for function
-        //~| NOTE ...but borrowed value is only valid for the scope of function body
         let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
         //~^ ERROR `x` does not live long enough
         //~| ERROR `y` does not live long enough
+        //~| NOTE capture occurs here
+        //~| NOTE capture occurs here
+        //~| NOTE does not live long enough
+        //~| NOTE does not live long enough
+        //~| NOTE values in a scope are dropped in the opposite order they are created
+        //~| NOTE values in a scope are dropped in the opposite order they are created
         return f;
     };
+    //~^ NOTE borrowed value dropped before borrower
+    //~| NOTE borrowed value dropped before borrower
 
     // We delberately do not call `g`; this small version of the test,
     // after adding such a call, was (properly) rejected even when the
@@ -35,15 +39,19 @@ fn escaping_borrow_of_closure_params_1() {
 
 fn escaping_borrow_of_closure_params_2() {
     let g = |x: usize, y:usize| {
-        //~^ NOTE reference must be valid for the scope of call-site for function
-        //~| NOTE ...but borrowed value is only valid for the scope of function body
-        //~| NOTE reference must be valid for the scope of call-site for function
-        //~| NOTE ...but borrowed value is only valid for the scope of function body
         let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
         //~^ ERROR `x` does not live long enough
         //~| ERROR `y` does not live long enough
+        //~| NOTE capture occurs here
+        //~| NOTE capture occurs here
+        //~| NOTE does not live long enough
+        //~| NOTE does not live long enough
+        //~| NOTE values in a scope are dropped in the opposite order they are created
+        //~| NOTE values in a scope are dropped in the opposite order they are created
         f
     };
+    //~^ NOTE borrowed value dropped before borrower
+    //~| NOTE borrowed value dropped before borrower
 
     // (we don't call `g`; see above)
 }
index 89350f16167603f3b9ae01c8409623e2f405feea..f5ea7a2108e79b207539a967dea677fdcea92b9a 100644 (file)
 fn broken() {
     let mut x = 3;
     let mut _y = vec!(&mut x);
+    //~^ NOTE borrow of `x` occurs here
+    //~| NOTE borrow of `x` occurs here
+    //~| NOTE borrow of `x` occurs here
     while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed
+        //~^ NOTE use of borrowed `x`
         let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed
+        //~^ NOTE use of borrowed `x`
         _y.push(&mut z); //~ ERROR `z` does not live long enough
+        //~^ NOTE does not live long enough
         x += 1; //~ ERROR cannot assign
+        //~^ NOTE assignment to borrowed `x` occurs here
     }
+    //~^ NOTE borrowed value only lives until here
 }
+//~^ NOTE borrowed value needs to live until here
 
 fn main() { }
diff --git a/src/test/compile-fail/regions-in-consts.rs b/src/test/compile-fail/regions-in-consts.rs
deleted file mode 100644 (file)
index 8d0829a..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-static c_y: &isize = &22; //~ ERROR missing lifetime specifier
-static c_z: &'static isize = &22;
-
-fn main() {
-}
index ed143fdff687f1098c884bcd077446c1d591938a..a23ac80fca62071490dc4cd51f015a08b94cffdb 100644 (file)
 mod a {
     extern crate collections;
     use collections::HashMap;
-//~^ ERROR unresolved import `collections::HashMap`. Did you mean `self::collections`?
+    //~^ ERROR unresolved import `collections::HashMap` [E0432]
+    //~| Did you mean `self::collections`?
     mod b {
         use collections::HashMap;
-//~^ ERROR unresolved import `collections::HashMap`. Did you mean `a::collections`?
+        //~^ ERROR unresolved import `collections::HashMap` [E0432]
+        //~| Did you mean `a::collections`?
         mod c {
             use collections::HashMap;
-//~^ ERROR unresolved import `collections::HashMap`. Did you mean `a::collections`?
+            //~^ ERROR unresolved import `collections::HashMap` [E0432]
+            //~| Did you mean `a::collections`?
             mod d {
                 use collections::HashMap;
-//~^ ERROR unresolved import `collections::HashMap`. Did you mean `a::collections`?
+                //~^ ERROR unresolved import `collections::HashMap` [E0432]
+                //~| Did you mean `a::collections`?
             }
         }
     }
diff --git a/src/test/compile-fail/rfc1592-deprecated.rs b/src/test/compile-fail/rfc1592-deprecated.rs
deleted file mode 100644 (file)
index e766f97..0000000
+++ /dev/null
@@ -1,32 +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.
-
-use std::fmt;
-
-#[deny(warnings)] trait Foo { fn foo(&self) -> (Self, Self); }
-//~^ ERROR the trait bound `Self: std::marker::Sized` is not satisfied
-//~| WARNING hard error
-
-impl<T: Copy> Foo for T {
-    fn foo(&self) -> (Self, Self) {
-        (*self, *self)
-    }
-}
-
-#[deny(warnings)]
-fn main() {
-    assert_eq!((11).foo(), (11, 11));
-
-    let junk: Box<fmt::Debug+Sized> = Box::new(42);
-    //~^ ERROR the trait cannot require that `Self : Sized`
-    //~| WARNING hard error
-    let f = format!("{:?}", junk);
-    assert_eq!(f, "42");
-}
diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs
new file mode 100644 (file)
index 0000000..1d8fc7f
--- /dev/null
@@ -0,0 +1,101 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 {
+    a
+}
+
+// the boundaries of elision
+static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = &(non_elidable as fn(&u8, &u8) -> &u8);
+//~^ ERROR missing lifetime specifier [E0106]
+
+struct SomeStruct<'x, 'y, 'z: 'x> {
+    foo: &'x Foo<'z>,
+    bar: &'x Bar<'z>,
+    f: &'y for<'a, 'b: 'a> Fn(&'a Foo<'b>) -> &'a Bar<'b>,
+}
+
+fn id<T>(t: T) -> T {
+    t
+}
+
+static SOME_STRUCT: &SomeStruct = SomeStruct {
+    foo: &Foo { bools: &[false, true] },
+    bar: &Bar { bools: &[true, true] },
+    f: &id,
+};
+
+// very simple test for a 'static static with default lifetime
+static STATIC_STR: &'static str = "&'static str";
+const CONST_STR: &'static str = "&'static str";
+
+// this should be the same as without default:
+static EXPLICIT_STATIC_STR: &'static str = "&'static str";
+const EXPLICIT_CONST_STR: &'static str = "&'static str";
+
+// a function that elides to an unbound lifetime for both in- and output
+fn id_u8_slice(arg: &[u8]) -> &[u8] {
+    arg
+}
+
+// one with a function, argument elided
+static STATIC_SIMPLE_FN: &'static fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]);
+const CONST_SIMPLE_FN: &'static fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]);
+
+// this should be the same as without elision
+static STATIC_NON_ELIDED_fN: &'static for<'a> fn(&'a [u8]) -> &'a [u8] =
+    &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]);
+const CONST_NON_ELIDED_fN: &'static for<'a> fn(&'a [u8]) -> &'a [u8] =
+    &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]);
+
+// another function that elides, each to a different unbound lifetime
+fn multi_args(a: &u8, b: &u8, c: &u8) {}
+
+static STATIC_MULTI_FN: &'static fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8));
+const CONST_MULTI_FN: &'static fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8));
+
+struct Foo<'a> {
+    bools: &'a [bool],
+}
+
+static STATIC_FOO: Foo<'static> = Foo { bools: &[true, false] };
+const CONST_FOO: Foo<'static> = Foo { bools: &[true, false] };
+
+type Bar<'a> = Foo<'a>;
+
+static STATIC_BAR: Bar<'static> = Bar { bools: &[true, false] };
+const CONST_BAR: Bar<'static> = Bar { bools: &[true, false] };
+
+type Baz<'a> = fn(&'a [u8]) -> Option<u8>;
+
+fn baz(e: &[u8]) -> Option<u8> {
+    e.first().map(|x| *x)
+}
+
+static STATIC_BAZ: &'static Baz<'static> = &(baz as Baz);
+const CONST_BAZ: &'static Baz<'static> = &(baz as Baz);
+
+static BYTES: &'static [u8] = &[1, 2, 3];
+
+fn main() {
+    let x = &[1u8, 2, 3];
+    let y = x;
+
+    // this works, so lifetime < `'static` is valid
+    assert_eq!(Some(1), STATIC_BAZ(y));
+    assert_eq!(Some(1), CONST_BAZ(y));
+
+    let y = &[1u8, 2, 3];
+
+    STATIC_BAZ(BYTES); // BYTES has static lifetime
+    CONST_BAZ(y); // interestingly this does not get reported
+}
diff --git a/src/test/compile-fail/rfc1623.rs.bk b/src/test/compile-fail/rfc1623.rs.bk
new file mode 100644 (file)
index 0000000..abdcc02
--- /dev/null
@@ -0,0 +1,98 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a }
+
+// the boundaries of elision
+static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 =
+//~^ ERROR: missing lifetime specifier
+        &(non_elidable as fn(&u8, &u8) -> &u8);
+
+struct SomeStruct<'x, 'y, 'z: 'x> {
+    foo: &'x Foo<'z>,
+    bar: &'x Bar<'z>,
+    f: &'y for<'a, 'b: 'a> Fn(&'a Foo<'b>) -> &'a Bar<'b>,
+}
+
+fn id<T>(t: T) -> T { t }
+
+static SOME_STRUCT : &SomeStruct = SomeStruct {
+    foo: &Foo { bools: &[false, true] },
+    bar: &Bar { bools: &[true, true] },
+    f: &id,
+};
+
+// very simple test for a 'static static with default lifetime
+static STATIC_STR : &'static str = "&'static str";
+const CONST_STR : &'static str = "&'static str";
+
+// this should be the same as without default:
+static EXPLICIT_STATIC_STR : &'static str = "&'static str";
+const EXPLICIT_CONST_STR : &'static str = "&'static str";
+
+// a function that elides to an unbound lifetime for both in- and output
+fn id_u8_slice(arg: &[u8]) -> &[u8] { arg }
+
+// one with a function, argument elided
+static STATIC_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] =
+        &(id_u8_slice as fn(&[u8]) -> &[u8]);
+const CONST_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] =
+        &(id_u8_slice as fn(&[u8]) -> &[u8]);
+
+// this should be the same as without elision
+static STATIC_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] =
+        &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]);
+const CONST_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] =
+        &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]);
+
+// another function that elides, each to a different unbound lifetime
+fn multi_args(a: &u8, b: &u8, c: &u8) { }
+
+static STATIC_MULTI_FN : &'static fn(&u8, &u8, &u8) =
+        &(multi_args as fn(&u8, &u8, &u8));
+const CONST_MULTI_FN : &'static fn(&u8, &u8, &u8) =
+        &(multi_args as fn(&u8, &u8, &u8));
+
+struct Foo<'a> {
+    bools: &'a [bool]
+}
+
+static STATIC_FOO : Foo<'static> = Foo { bools: &[true, false] };
+const CONST_FOO : Foo<'static> = Foo { bools: &[true, false] };
+
+type Bar<'a> = Foo<'a>;
+
+static STATIC_BAR : Bar<'static> = Bar { bools: &[true, false] };
+const CONST_BAR : Bar<'static> = Bar { bools: &[true, false] };
+
+type Baz<'a> = fn(&'a [u8]) -> Option<u8>;
+
+fn baz(e: &[u8]) -> Option<u8> { e.first().map(|x| *x) }
+
+static STATIC_BAZ : &'static Baz<'static> = &(baz as Baz);
+const CONST_BAZ : &'static Baz<'static> = &(baz as Baz);
+
+static BYTES : &'static [u8] = &[1, 2, 3];
+
+fn main() {
+    let x = &[1u8, 2, 3];
+    let y = x;
+
+    //this works, so lifetime < `'static` is valid
+    assert_eq!(Some(1), STATIC_BAZ(y));
+    assert_eq!(Some(1), CONST_BAZ(y));
+
+    let y = &[1u8, 2, 3];
+    //^~ ERROR: borrowed values does not live long enough
+    STATIC_BAZ(BYTES); // BYTES has static lifetime
+    CONST_BAZ(y); // This forces static lifetime, which y has not
+}
index 2e401ba6e9085929d1621640eee1214b74798667..1b7718d2283a7bfd6a617c112f8a5d19bdd209a6 100644 (file)
@@ -26,8 +26,8 @@ fn main() {
         let y = &x; //~ ERROR `x` does not live long enough
 
         scoped(|| {
-            //~^ ERROR `y` does not live long enough
             let _z = y;
+            //~^ ERROR `y` does not live long enough
         })
     };
 
index 874cca8cb3fd03c709282a7712e8a29fe1c6b650..bee3704a353d3b1d4051b83cbfe57f727e55dca7 100644 (file)
@@ -18,5 +18,5 @@ fn main() {
     //~^ ERROR mismatched types
     //~| expected type `&mut [_]`
     //~| found type `&[isize]`
-    //~| values differ in mutability
+    //~| types differ in mutability
 }
index f59caef4631361f546e077efd37784b1362605d9..7d11ff6c9b54dae32081a2b2dbce8192af15b75c 100644 (file)
@@ -8,7 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use super::f; //~ ERROR unresolved import `super::f`. There are too many initial `super`s.
+use super::f; //~ ERROR unresolved import `super::f` [E0432]
+              //~^ There are too many initial `super`s.
 
 fn main() {
 }
index 3e36b126523a7f84828dd5fd7180ae54724c5aaf..f06e3544e575dec1874a39eb9dc1eeb2b735aae0 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(concat_idents, type_macros)]
+#![feature(concat_idents)]
 
 pub fn main() {
     struct Foo;
index a11df776e06d3ba1e2dc6f0add3390d80a92da6b..c987d9f2f4e1b0c185530d6b4c560c258c7b59db 100644 (file)
 
 // ensure that the ThreadRng isn't/doesn't become accidentally sendable.
 
-use std::rand; //~ ERROR: module `rand` is private
+use std::__rand::ThreadRng;
 
 fn test_send<S: Send>() {}
 
 pub fn main() {
-    test_send::<rand::ThreadRng>();
-    //~^ ERROR : std::marker::Send` is not satisfied
+    test_send::<ThreadRng>(); //~ ERROR std::marker::Send` is not satisfied
 }
index 41700b25bbb726798de48eca9d0544c393220b56..7bcab1f6ac56b9da9e828b45fefc604a6ac67fb3 100644 (file)
@@ -11,6 +11,7 @@
 trait Foo {
     fn orange(&self); //~ NOTE previous definition of `orange` here
     fn orange(&self); //~ ERROR a value named `orange` has already been defined in this trait
+                      //~| NOTE already define
 }
 
 fn main() {}
index 0df7ee8cabed21a4adb3db8a14e1d1962127f669..65732a8ff69e54ac117d0c0a213f728b0931617c 100644 (file)
@@ -20,7 +20,7 @@ fn foo(self) {
         // Unsafe actions are not made legal by taking place in an unsafe trait:
         *self += 1;
         //~^ ERROR E0133
-        //~| NOTE unsafe call requires unsafe function or block
+        //~| NOTE dereference of raw pointer
     }
 }
 
index a8ff1bae7a71a7ebe1a114721776811cf99bc7ba..d15e3536d60ca0633cf5a91ed390e1da4e4cd376 100644 (file)
@@ -16,11 +16,13 @@ fn check<T: Iterator, U: ?Sized>() {
     // suggest a where-clause, if needed
     mem::size_of::<U>();
     //~^ ERROR `U: std::marker::Sized` is not satisfied
+    //~| NOTE trait `U: std::marker::Sized` not satisfied
     //~| HELP consider adding a `where U: std::marker::Sized` bound
     //~| NOTE required by `std::mem::size_of`
 
     mem::size_of::<Misc<U>>();
     //~^ ERROR `U: std::marker::Sized` is not satisfied
+    //~| NOTE trait `U: std::marker::Sized` not satisfied
     //~| HELP consider adding a `where U: std::marker::Sized` bound
     //~| NOTE required because it appears within the type `Misc<U>`
     //~| NOTE required by `std::mem::size_of`
@@ -29,11 +31,13 @@ fn check<T: Iterator, U: ?Sized>() {
 
     <u64 as From<T>>::from;
     //~^ ERROR `u64: std::convert::From<T>` is not satisfied
+    //~| NOTE trait `u64: std::convert::From<T>` not satisfied
     //~| HELP consider adding a `where u64: std::convert::From<T>` bound
     //~| NOTE required by `std::convert::From::from`
 
     <u64 as From<<T as Iterator>::Item>>::from;
     //~^ ERROR `u64: std::convert::From<<T as std::iter::Iterator>::Item>` is not satisfied
+    //~| NOTE trait `u64: std::convert::From<<T as std::iter::Iterator>::Item>` not satisfied
     //~| HELP consider adding a `where u64:
     //~| NOTE required by `std::convert::From::from`
 
@@ -41,17 +45,20 @@ fn check<T: Iterator, U: ?Sized>() {
 
     <Misc<_> as From<T>>::from;
     //~^ ERROR `Misc<_>: std::convert::From<T>` is not satisfied
+    //~| NOTE trait `Misc<_>: std::convert::From<T>` not satisfied
     //~| NOTE required by `std::convert::From::from`
 
     // ... and also not if the error is not related to the type
 
     mem::size_of::<[T]>();
     //~^ ERROR `[T]: std::marker::Sized` is not satisfied
+    //~| NOTE `[T]: std::marker::Sized` not satisfied
     //~| NOTE `[T]` does not have a constant size
     //~| NOTE required by `std::mem::size_of`
 
     mem::size_of::<[&U]>();
     //~^ ERROR `[&U]: std::marker::Sized` is not satisfied
+    //~| NOTE `[&U]: std::marker::Sized` not satisfied
     //~| NOTE `[&U]` does not have a constant size
     //~| NOTE required by `std::mem::size_of`
 }
diff --git a/src/test/compile-fail/type-macros-fail.rs b/src/test/compile-fail/type-macros-fail.rs
deleted file mode 100644 (file)
index 4712e2b..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-macro_rules! Id {
-    ($T:tt) => ($T);
-}
-
-struct Foo<T> {
-    x: Id!(T)
-    //~^ ERROR: type macros are experimental (see issue #27245)
-}
-
-fn main() {
-    let foo = Foo { x: i32 };
-}
index 09b97dfb30f24f8063084a32e847f26ca15499e4..4d71517e06058fde9f39628a694afe1cd5dc99d7 100644 (file)
@@ -10,7 +10,6 @@
 
 #![feature(optin_builtin_traits)]
 
-impl Copy for .. {}
-//~^ ERROR E0318
-
+impl Copy for .. {} //~ ERROR E0318
+     //~^ NOTE `Copy` trait not defined in this crate
 fn main() {}
index f73b06653012afd294d024861c13acbc9ca49975..ce60521034ee7cc89b8dc89bbda548497297de34 100644 (file)
@@ -22,8 +22,8 @@ fn a() {
     let mut factorial: Option<Box<Fn(u32) -> u32>> = None;
 
     let f = |x: u32| -> u32 {
-        //~^ ERROR `factorial` does not live long enough
         let g = factorial.as_ref().unwrap();
+        //~^ ERROR `factorial` does not live long enough
         if x == 0 {1} else {x * g(x-1)}
     };
 
index b60d19fcab4aac6152f28133e3d10ed40bded478..d1254f3f5241b98c134cb9136cfcaf37702c329c 100644 (file)
 
 // ignore-tidy-linelength
 
-use foo::bar; //~ ERROR unresolved import `foo::bar`. Maybe a missing `extern crate foo`?
+use foo::bar; //~ ERROR unresolved import `foo::bar` [E0432]
+              //~^ Maybe a missing `extern crate foo`?
 
-use bar::Baz as x; //~ ERROR unresolved import `bar::Baz`. There is no `Baz` in `bar`. Did you mean to use `Bar`?
+use bar::Baz as x; //~ ERROR unresolved import `bar::Baz` [E0432]
+                   //~^ no `Baz` in `bar`. Did you mean to use `Bar`?
 
-use food::baz; //~ ERROR unresolved import `food::baz`. There is no `baz` in `food`. Did you mean to use `bag`?
+use food::baz; //~ ERROR unresolved import `food::baz`
+               //~^ no `baz` in `food`. Did you mean to use `bag`?
 
-use food::{beens as Foo}; //~ ERROR unresolved import `food::beens`. There is no `beens` in `food`. Did you mean to use `beans`?
+use food::{beens as Foo}; //~ ERROR unresolved import `food::beens` [E0432]
+                          //~^ no `beens` in `food`. Did you mean to use `beans`?
 
 mod bar {
     pub struct Bar;
index 174939b09009cbd3ef0bef677506f6a3191146c8..91e16592be4729364d82be8f2b8035f966ac8ea3 100644 (file)
@@ -18,7 +18,7 @@
 
 const VAL: u32 = dummy(0xFFFF);
 //~^ ERROR E0133
-//~| NOTE unsafe call requires unsafe function or block
+//~| NOTE call to unsafe function
 
 fn main() {
     assert_eq!(VAL, 0xFFFF0000);
diff --git a/src/test/compile-fail/unsafe_no_drop_flag-gate.rs b/src/test/compile-fail/unsafe_no_drop_flag-gate.rs
deleted file mode 100644 (file)
index 542698f..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-pub struct T;
-
-#[unsafe_no_drop_flag]
-//~^ ERROR unsafe_no_drop_flag has unstable semantics and may be removed
-pub struct S {
-    pub x: T,
-}
-
-impl Drop for S {
-    fn drop(&mut self) {}
-}
-
-pub fn main() {}
index d40c12f67a08da43a38d3eadf754ab8a5601c78e..462d760a60ceb99647f5c5a7a3f08dcd15a37e32 100644 (file)
@@ -14,9 +14,9 @@ trait T {}
 
 fn f1<X: ?Sized>(x: &X) {
     let _: X; // <-- this is OK, no bindings created, no initializer.
-    let _: (isize, (X, isize));
+    let _: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfie
     let y: X; //~ERROR `X: std::marker::Sized` is not satisfied
-    let y: (isize, (X, usize)); //~ERROR `X: std::marker::Sized` is not satisfied
+    let y: (isize, (X, usize));
 }
 fn f2<X: ?Sized + T>(x: &X) {
     let y: X; //~ERROR `X: std::marker::Sized` is not satisfied
index 687cdba1542bdce4c9be2889ac2bd453bb5f7da9..a40fa2337214ee8f135294ad88c3c8672f463496 100644 (file)
 use use_from_trait_xc::Trait::CONST;
 //~^ ERROR `CONST` is not directly importable
 
-use use_from_trait_xc::Foo::new;
+use use_from_trait_xc::Foo::new; //~ ERROR struct `Foo` is private
 //~^ ERROR unresolved import `use_from_trait_xc::Foo::new`
 
-use use_from_trait_xc::Foo::C;
+use use_from_trait_xc::Foo::C; //~ ERROR struct `Foo` is private
 //~^ ERROR unresolved import `use_from_trait_xc::Foo::C`
 
 use use_from_trait_xc::Bar::new as bnew;
index 28e933bc7aa0a2d180e874f4e25c173214acfeff..58e37bbfa3ea7c7729d56545777f2aff02527e81 100644 (file)
 //~^ ERROR `C` is not directly importable
 
 use Foo::new;
-//~^ ERROR unresolved import `Foo::new`. Not a module `Foo`
+//~^ ERROR unresolved import `Foo::new` [E0432]
+//~| Not a module `Foo`
 
 use Foo::C2;
-//~^ ERROR unresolved import `Foo::C2`. Not a module `Foo`
+//~^ ERROR unresolved import `Foo::C2` [E0432]
+//~| Not a module `Foo`
 
 pub trait Trait {
     fn foo();
index 040db0255678d23e53830588314c9d3c861bb926..6df20d414a788f919f0744ecc45d00a67de60791 100644 (file)
 mod a {
     mod b {
         use self as A; //~ ERROR `self` imports are only allowed within a { } list
-        //~^ ERROR unresolved import `self`. There is no `self` in the crate root
-        use super as B; //~ ERROR unresolved import `super`. There is no `super` in the crate root
-        use super::{self as C}; //~ERROR unresolved import `super`. There is no `super` in the crate
+        //~^ ERROR unresolved import `self` [E0432]
+        //~| no `self` in the root
+        use super as B;
+        //~^ ERROR unresolved import `super` [E0432]
+        //~| no `super` in the root
+        use super::{self as C};
+        //~^ ERROR unresolved import `super` [E0432]
+        //~| no `super` in the root
     }
 }
 
index f2384912cdba31c924d5723f55a25a1a82d031dd..5f8842a521abd80d940d04e31a350abed4d6dcb5 100644 (file)
 
 mod foo {
     use self::{self};
-    //~^ ERROR unresolved import `self`. There is no `self` in the crate root
+    //~^ ERROR unresolved import `self` [E0432]
+    //~| no `self` in the root
 
     use super::{self};
-    //~^ ERROR unresolved import `super`. There is no `super` in the crate root
+    //~^ ERROR unresolved import `super` [E0432]
+    //~| no `super` in the root
 }
 
 fn main() {}
index 5539a26d2a1702df997d0457a511c76c9ea8ae67..7dbfc6ac1257d082732d314232599c32c460cef8 100644 (file)
@@ -20,12 +20,12 @@ fn method(&'a self) { }
 }
 
 #[rustc_variance]
-struct Foo<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[+], regions=[-])
+struct Foo<'a, T : Trait<'a>> { //~ ERROR [-, +]
     field: (T, &'a ())
 }
 
 #[rustc_variance]
-struct Bar<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[o], regions=[o])
+struct Bar<'a, T : Trait<'a>> { //~ ERROR [o, o]
     field: <T as Trait<'a>>::Type
 }
 
index 2f422bfd38cc7fcb340f3068b8a109e6faf3221e..1f54771e3676abd00677dc05b75672c2d619a1ec 100644 (file)
@@ -18,7 +18,7 @@
 // For better or worse, associated types are invariant, and hence we
 // get an invariant result for `'a`.
 #[rustc_variance]
-struct Foo<'a> { //~ ERROR regions=[o]
+struct Foo<'a> { //~ ERROR [o]
     x: Box<Fn(i32) -> &'a i32 + 'static>
 }
 
index 99416057b25408341ea5b60582dbaf79de2376b2..41d204a541b5ad9b4481dd1fe51abff1d3afb359 100644 (file)
 #![feature(rustc_attrs)]
 
 #[rustc_variance]
-trait Foo: 'static { //~ ERROR types=[o]
+trait Foo: 'static { //~ ERROR [o]
 }
 
 #[rustc_variance]
-trait Bar<T> { //~ ERROR types=[o, o]
+trait Bar<T> { //~ ERROR [o, o]
     fn do_it(&self)
         where T: 'static;
 }
index 78591063de8abc4db2094b6a42a1c1dd63562bd1..bf46edcfab8b172ffc4affd0eff34f98625e62af 100644 (file)
@@ -16,7 +16,7 @@
 // Regions that just appear in normal spots are contravariant:
 
 #[rustc_variance]
-struct Test2<'a, 'b, 'c> { //~ ERROR regions=[-, -, -]
+struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -]
     x: &'a isize,
     y: &'b [isize],
     c: &'c str
@@ -25,7 +25,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR regions=[-, -, -]
 // Those same annotations in function arguments become covariant:
 
 #[rustc_variance]
-struct Test3<'a, 'b, 'c> { //~ ERROR regions=[+, +, +]
+struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +]
     x: extern "Rust" fn(&'a isize),
     y: extern "Rust" fn(&'b [isize]),
     c: extern "Rust" fn(&'c str),
@@ -34,7 +34,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR regions=[+, +, +]
 // Mutability induces invariance:
 
 #[rustc_variance]
-struct Test4<'a, 'b:'a> { //~ ERROR regions=[-, o]
+struct Test4<'a, 'b:'a> { //~ ERROR [-, o]
     x: &'a mut &'b isize,
 }
 
@@ -42,7 +42,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR regions=[-, o]
 // contravariant context:
 
 #[rustc_variance]
-struct Test5<'a, 'b:'a> { //~ ERROR regions=[+, o]
+struct Test5<'a, 'b:'a> { //~ ERROR [+, o]
     x: extern "Rust" fn(&'a mut &'b isize),
 }
 
@@ -52,14 +52,14 @@ struct Test5<'a, 'b:'a> { //~ ERROR regions=[+, o]
 // argument list occurs in an invariant context.
 
 #[rustc_variance]
-struct Test6<'a, 'b:'a> { //~ ERROR regions=[-, o]
+struct Test6<'a, 'b:'a> { //~ ERROR [-, o]
     x: &'a mut extern "Rust" fn(&'b isize),
 }
 
 // No uses at all is bivariant:
 
 #[rustc_variance]
-struct Test7<'a> { //~ ERROR regions=[*]
+struct Test7<'a> { //~ ERROR [*]
     //~^ ERROR parameter `'a` is never used
     x: isize
 }
@@ -67,7 +67,7 @@ struct Test7<'a> { //~ ERROR regions=[*]
 // Try enums too.
 
 #[rustc_variance]
-enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[+, -, o]
+enum Test8<'a, 'b, 'c:'b> { //~ ERROR [+, -, o]
     Test8A(extern "Rust" fn(&'a isize)),
     Test8B(&'b [isize]),
     Test8C(&'b mut &'c str),
index d8af30da163bf8a735550357ce20257c5d865525..e28828f62e52d655f4b65e7888ac9b7d17131b2d 100644 (file)
@@ -15,7 +15,7 @@
 #![feature(rustc_attrs)]
 
 #[rustc_variance]
-enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[+, -, o, *]
+enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [+, -, o, *]
     //~^ ERROR parameter `'d` is never used
     Test8A(extern "Rust" fn(&'a isize)),
     Test8B(&'b [isize]),
@@ -23,25 +23,25 @@ enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[+, -, o, *]
 }
 
 #[rustc_variance]
-struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[*, o, -, +]
+struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, -, +]
     //~^ ERROR parameter `'w` is never used
     f: Base<'z, 'y, 'x, 'w>
 }
 
 #[rustc_variance] // Combine - and + to yield o
-struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[o, o, *]
+struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *]
     //~^ ERROR parameter `'c` is never used
     f: Base<'a, 'a, 'b, 'c>
 }
 
 #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here)
-struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[o, -, *]
+struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, -, *]
     //~^ ERROR parameter `'c` is never used
     f: Base<'a, 'b, 'a, 'c>
 }
 
 #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here)
-struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[+, -, o]
+struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [+, -, o]
     f: Base<'a, 'b, 'c, 'a>
 }
 
index 150a1aa56fe721e956614328416e07c1b0eff0ca..4c737a7594d260125b4486e257d6820ff89aaed7 100644 (file)
 // influence variance.
 
 #[rustc_variance]
-trait Getter<T> { //~ ERROR types=[o, o]
+trait Getter<T> { //~ ERROR [o, o]
     fn get(&self) -> T;
 }
 
 #[rustc_variance]
-trait Setter<T> { //~ ERROR types=[o, o]
+trait Setter<T> { //~ ERROR [o, o]
     fn get(&self, T);
 }
 
 #[rustc_variance]
-struct TestStruct<U,T:Setter<U>> { //~ ERROR types=[+, +]
+struct TestStruct<U,T:Setter<U>> { //~ ERROR [+, +]
     t: T, u: U
 }
 
 #[rustc_variance]
-enum TestEnum<U,T:Setter<U>> {//~ ERROR types=[*, +]
+enum TestEnum<U,T:Setter<U>> {//~ ERROR [*, +]
     //~^ ERROR parameter `U` is never used
     Foo(T)
 }
 
 #[rustc_variance]
-trait TestTrait<U,T:Setter<U>> { //~ ERROR types=[o, o, o]
+trait TestTrait<U,T:Setter<U>> { //~ ERROR [o, o, o]
     fn getter(&self, u: U) -> T;
 }
 
 #[rustc_variance]
-trait TestTrait2<U> : Getter<U> { //~ ERROR types=[o, o]
+trait TestTrait2<U> : Getter<U> { //~ ERROR [o, o]
 }
 
 #[rustc_variance]
-trait TestTrait3<U> { //~ ERROR types=[o, o]
+trait TestTrait3<U> { //~ ERROR [o, o]
     fn getter<T:Getter<U>>(&self);
 }
 
 #[rustc_variance]
-struct TestContraStruct<U,T:Setter<U>> { //~ ERROR types=[*, +]
+struct TestContraStruct<U,T:Setter<U>> { //~ ERROR [*, +]
     //~^ ERROR parameter `U` is never used
     t: T
 }
 
 #[rustc_variance]
-struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR types=[*, +]
+struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR [*, +]
     //~^ ERROR parameter `U` is never used
     t: T
 }
index 4244b0e1d8b8b27104150a40cd03449694e724b0..b120588ecab52318f4d014f6ed4230d38dc72246 100644 (file)
@@ -21,7 +21,7 @@
 trait T { fn foo(&self); }
 
 #[rustc_variance]
-struct TOption<'a> { //~ ERROR regions=[-]
+struct TOption<'a> { //~ ERROR [-]
     v: Option<Box<T + 'a>>,
 }
 
index c47710d6d376d0e2bcdf1354fd62cf2c7411687e..2df94cc907a9cf88517497712bb4218e90caca3b 100644 (file)
 #![feature(rustc_attrs)]
 
 #[rustc_variance]
-struct TestImm<A, B> { //~ ERROR types=[+, +]
+struct TestImm<A, B> { //~ ERROR [+, +]
     x: A,
     y: B,
 }
 
 #[rustc_variance]
-struct TestMut<A, B:'static> { //~ ERROR types=[+, o]
+struct TestMut<A, B:'static> { //~ ERROR [+, o]
     x: A,
     y: &'static mut B,
 }
 
 #[rustc_variance]
-struct TestIndirect<A:'static, B:'static> { //~ ERROR types=[+, o]
+struct TestIndirect<A:'static, B:'static> { //~ ERROR [+, o]
     m: TestMut<A, B>
 }
 
 #[rustc_variance]
-struct TestIndirect2<A:'static, B:'static> { //~ ERROR types=[o, o]
+struct TestIndirect2<A:'static, B:'static> { //~ ERROR [o, o]
     n: TestMut<A, B>,
     m: TestMut<B, A>
 }
 
 #[rustc_variance]
-trait Getter<A> { //~ ERROR types=[o, o]
+trait Getter<A> { //~ ERROR [o, o]
     fn get(&self) -> A;
 }
 
 #[rustc_variance]
-trait Setter<A> { //~ ERROR types=[o, o]
+trait Setter<A> { //~ ERROR [o, o]
     fn set(&mut self, a: A);
 }
 
 #[rustc_variance]
-trait GetterSetter<A> { //~ ERROR types=[o, o]
+trait GetterSetter<A> { //~ ERROR [o, o]
     fn get(&self) -> A;
     fn set(&mut self, a: A);
 }
 
 #[rustc_variance]
-trait GetterInTypeBound<A> { //~ ERROR types=[o, o]
+trait GetterInTypeBound<A> { //~ ERROR [o, o]
     // Here, the use of `A` in the method bound *does* affect
     // variance.  Think of it as if the method requested a dictionary
     // for `T:Getter<A>`.  Since this dictionary is an input, it is
@@ -63,12 +63,12 @@ trait GetterInTypeBound<A> { //~ ERROR types=[o, o]
 }
 
 #[rustc_variance]
-trait SetterInTypeBound<A> { //~ ERROR types=[o, o]
+trait SetterInTypeBound<A> { //~ ERROR [o, o]
     fn do_it<T:Setter<A>>(&self);
 }
 
 #[rustc_variance]
-struct TestObject<A, R> { //~ ERROR types=[o, o]
+struct TestObject<A, R> { //~ ERROR [o, o]
     n: Box<Setter<A>+Send>,
     m: Box<Getter<R>+Send>,
 }
index d5164412358fc4dbba312b0e7dab4858ee6f61d5..7667972c9d251edcd9d8e85115fb05b848c1e4fc 100644 (file)
 // not considered bivariant.
 
 #[rustc_variance]
-struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR types=[o, o], regions=[-]
+struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [-, o, o]
     t: &'a mut (A,B)
 }
 
 #[rustc_variance]
-struct InvariantCell<A> { //~ ERROR types=[o]
+struct InvariantCell<A> { //~ ERROR [o]
     t: Cell<A>
 }
 
 #[rustc_variance]
-struct InvariantIndirect<A> { //~ ERROR types=[o]
+struct InvariantIndirect<A> { //~ ERROR [o]
     t: InvariantCell<A>
 }
 
 #[rustc_variance]
-struct Covariant<A> { //~ ERROR types=[+]
+struct Covariant<A> { //~ ERROR [+]
     t: A, u: fn() -> A
 }
 
 #[rustc_variance]
-struct Contravariant<A> { //~ ERROR types=[-]
+struct Contravariant<A> { //~ ERROR [-]
     t: fn(A)
 }
 
 #[rustc_variance]
-enum Enum<A,B,C> { //~ ERROR types=[+, -, o]
+enum Enum<A,B,C> { //~ ERROR [+, -, o]
     Foo(Covariant<A>),
     Bar(Contravariant<B>),
     Zed(Covariant<C>,Contravariant<C>)
diff --git a/src/test/debuginfo/auxiliary/macro-stepping.rs b/src/test/debuginfo/auxiliary/macro-stepping.rs
new file mode 100644 (file)
index 0000000..1006b68
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2013-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:-g
+
+#![crate_type = "rlib"]
+
+#[macro_export]
+macro_rules! new_scope {
+    () => {
+        let x = 1;
+    }
+}
index a00d0f74f1e4e45771e9d166c1b8fae1f8cbdb7c..eb5798dc7cc486746d250e2ca2481ea0eabeaab6 100644 (file)
@@ -10,7 +10,7 @@
 
 // min-lldb-version: 310
 
-// compile-flags:-g
+// compile-flags:-g -Zdebug-macros
 
 // === GDB TESTS ===================================================================================
 
diff --git a/src/test/debuginfo/macro-stepping.rs b/src/test/debuginfo/macro-stepping.rs
new file mode 100644 (file)
index 0000000..52a2a58
--- /dev/null
@@ -0,0 +1,103 @@
+// Copyright 2013-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-windows
+// ignore-android
+// min-lldb-version: 310
+
+// aux-build:macro-stepping.rs
+
+#![allow(unused)]
+
+#[macro_use]
+extern crate macro_stepping; // exports new_scope!()
+
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#loc1[...]
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#loc2[...]
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#loc3[...]
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#loc4[...]
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#loc5[...]
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#loc6[...]
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command:set set stop-line-count-before 0
+// lldb-command:set set stop-line-count-after 1
+// Can't set both to zero or lldb will stop printing source at all.  So it will output the current
+// line and the next.  We deal with this by having at least 2 lines between the #loc's
+
+// lldb-command:run
+// lldb-command:next
+// lldb-command:frame select
+// lldb-check:[...]#loc1[...]
+// lldb-command:next
+// lldb-command:frame select
+// lldb-check:[...]#loc2[...]
+// lldb-command:next
+// lldb-command:frame select
+// lldb-check:[...]#loc3[...]
+// lldb-command:next
+// lldb-command:frame select
+// lldb-check:[...]#loc4[...]
+// lldb-command:next
+// lldb-command:frame select
+// lldb-check:[...]#loc5[...]
+
+macro_rules! foo {
+    () => {
+        let a = 1;
+        let b = 2;
+        let c = 3;
+    }
+}
+
+macro_rules! foo2 {
+    () => {
+        foo!();
+        let x = 1;
+        foo!();
+    }
+}
+
+fn main() {
+    zzz(); // #break
+
+    foo!(); // #loc1
+
+    foo2!(); // #loc2
+
+    let x = vec![42]; // #loc3
+
+    new_scope!(); // #loc4
+
+    println!("Hello {}", // #loc5
+             "world");
+
+    zzz(); // #loc6
+}
+
+fn zzz() {()}
diff --git a/src/test/incremental/crate_hash_reorder.rs b/src/test/incremental/crate_hash_reorder.rs
new file mode 100644 (file)
index 0000000..3f1bdb7
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the crate hash is not affected by reordering items.
+
+// revisions:rpass1 rpass2 rpass3
+// compile-flags: -Z query-dep-graph
+
+#![feature(rustc_attrs)]
+
+// Check that reordering otherwise identical items is not considered a
+// change at all.
+#[rustc_clean(label="Krate", cfg="rpass2")]
+
+// But removing an item, naturally, is.
+#[rustc_dirty(label="Krate", cfg="rpass3")]
+
+#[cfg(rpass1)]
+pub struct X {
+    pub x: u32,
+}
+
+pub struct Y {
+    pub x: u32,
+}
+
+#[cfg(rpass2)]
+pub struct X {
+    pub x: u32,
+}
+
+pub fn main() { }
diff --git a/src/test/incremental/issue-35593.rs b/src/test/incremental/issue-35593.rs
new file mode 100644 (file)
index 0000000..51e04dd
--- /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.
+
+// Regression test for #35593. Check that we can reuse this trivially
+// equal example.
+
+// revisions:rpass1 rpass2
+
+#![feature(rustc_attrs)]
+#![rustc_partition_reused(module="issue_35593", cfg="rpass2")]
+
+fn main() {
+    println!("hello world");
+}
index 72072248ec05f2990c2bfe1e026e882319b32b6c..ba8d3cc934bfc253e6f23651c57ded089f5a66e4 100644 (file)
 // Here the only thing which changes is the string constant in `x`.
 // Therefore, the compiler deduces (correctly) that typeck is not
 // needed even for callers of `x`.
-//
-// It is not entirely clear why `TransCrateItem` invalidates `y` and
-// `z`, actually, I think it's because of the structure of
-// trans. -nmatsakis
 
 fn main() { }
 
@@ -41,10 +37,8 @@ pub fn x() {
 mod y {
     use x;
 
-    // FIXME(#35078) -- when body of `x` changes, we treat it as
-    // though signature changed.
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
-    #[rustc_dirty(label="TransCrateItem", cfg="rpass2")]
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TransCrateItem", cfg="rpass2")]
     pub fn y() {
         x::x();
     }
diff --git a/src/test/parse-fail/doc-after-struct-field.rs b/src/test/parse-fail/doc-after-struct-field.rs
new file mode 100644 (file)
index 0000000..1aa6af5
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z continue-parse-after-error
+struct X {
+    a: u8 /** document a */,
+    //~^ ERROR found a documentation comment that doesn't document anything
+    //~| HELP maybe a comment was intended
+}
+
+fn main() {
+    let y = X {a = 1};
+}
index 9e825193dc0d830ac8df1d78df84ae4952424823..70da47ba9b4f05305020f6e4a1428ed800687986 100644 (file)
@@ -12,5 +12,5 @@
 
 extern {
     /// hi
+    //~^ ERROR expected item after doc comment
 }
-//~^^ ERROR expected item after doc comment
diff --git a/src/test/parse-fail/doc-before-fn-rbrace.rs b/src/test/parse-fail/doc-before-fn-rbrace.rs
new file mode 100644 (file)
index 0000000..bcf3261
--- /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.
+
+// compile-flags: -Z continue-parse-after-error
+fn main() {
+    /// document
+    //~^ ERROR found a documentation comment that doesn't document anything
+    //~| HELP maybe a comment was intended
+}
diff --git a/src/test/parse-fail/doc-before-identifier.rs b/src/test/parse-fail/doc-before-identifier.rs
new file mode 100644 (file)
index 0000000..8f1fad9
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z continue-parse-after-error
+fn /// document
+foo() {}
+//~^^ ERROR expected identifier, found `/// document`
+
+fn main() {
+    foo();
+}
diff --git a/src/test/parse-fail/doc-before-mod-rbrace.rs b/src/test/parse-fail/doc-before-mod-rbrace.rs
new file mode 100644 (file)
index 0000000..d38d187
--- /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.
+
+// compile-flags: -Z continue-parse-after-error
+mod Foo {
+    /// document
+    //~^ ERROR expected item after doc comment
+}
index 295d5ae432ecb3f48f1c3a1216c115582919daaf..48ea2b5aea12c92d26d3cd2e4f115b77d1c9bf34 100644 (file)
@@ -12,5 +12,6 @@
 
 fn main() {
     println!("Hi"); /// hi
+    //~^ ERROR found a documentation comment that doesn't document anything
+    //~| HELP maybe a comment was intended
 }
-//~^ ERROR expected statement
index 6a8906953be091ade684055cd72cf09527813445..71104b8caae1952f8cebbcdbb8478075efa6d08a 100644 (file)
@@ -12,6 +12,7 @@
 
 fn main() {
     /// hi
+    //~^ ERROR found a documentation comment that doesn't document anything
+    //~| HELP maybe a comment was intended
     ;
-    //~^ ERROR expected statement
 }
diff --git a/src/test/parse-fail/doc-before-struct-rbrace-1.rs b/src/test/parse-fail/doc-before-struct-rbrace-1.rs
new file mode 100644 (file)
index 0000000..5ba8319
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z continue-parse-after-error
+struct X {
+    a: u8,
+    /// document
+    //~^ ERROR found a documentation comment that doesn't document anything
+    //~| HELP maybe a comment was intended
+}
+
+fn main() {
+    let y = X {a = 1};
+}
diff --git a/src/test/parse-fail/doc-before-struct-rbrace-2.rs b/src/test/parse-fail/doc-before-struct-rbrace-2.rs
new file mode 100644 (file)
index 0000000..643e4aa
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z continue-parse-after-error
+struct X {
+    a: u8 /// document
+    //~^ ERROR found a documentation comment that doesn't document anything
+    //~| HELP maybe a comment was intended
+}
+
+fn main() {
+    let y = X {a = 1};
+}
diff --git a/src/test/parse-fail/non-str-meta.rs b/src/test/parse-fail/non-str-meta.rs
deleted file mode 100644 (file)
index 3e2e69d..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-// Issue #623 - non-string meta items are not serialized correctly;
-// for now just forbid them
-
-#[foo = 1] //~ ERROR: non-string literals are not allowed in meta-items
-fn main() { }
diff --git a/src/test/parse-fail/suffixed-literal-meta.rs b/src/test/parse-fail/suffixed-literal-meta.rs
new file mode 100644 (file)
index 0000000..0e2840c
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z parse-only
+
+#[foo = 1usize] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1u8] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1u16] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1u32] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1u64] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1isize] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1i8] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1i16] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1i32] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1i64] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes
+fn main() { }
diff --git a/src/test/pretty/attr-literals.rs b/src/test/pretty/attr-literals.rs
new file mode 100644 (file)
index 0000000..ba8c580
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// pp-exact
+// Tests literals in attributes.
+
+#![feature(custom_attribute, attr_literals)]
+
+fn main() {
+    #![hello("hi", 1, 2, 1.012, pi = 3.14, bye, name("John"))]
+    #[align = 8]
+    fn f() { }
+
+    #[vec(1, 2, 3)]
+    fn g() { }
+}
index e1461c7847e4ca5050cc33ad598533cce26096da..47e97abbbaa47ef441ed1344e170279f0412f236 100644 (file)
@@ -40,8 +40,10 @@ fn main() {
     });
     let cx = &mut cx;
 
+    println!("{}", pprust::expr_to_string(&*quote_expr!(&cx, 23)));
     assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23");
 
     let expr = quote_expr!(&cx, let x isize = 20;);
+    println!("{}", pprust::expr_to_string(&*expr));
     assert_eq!(pprust::expr_to_string(&*expr), "let x isize = 20;");
 }
index 95101e70db95192aae510e6593b4a6175cbfa902..b1aa76cd9bfe50aa92797c3906b442aafc588956 100644 (file)
@@ -10,6 +10,7 @@
 
 // Test that we can use a ! for an argument of type !
 
+// ignore-test FIXME(durka) can't be done with the current liveness code
 // error-pattern:wowzers!
 
 #![feature(never_type)]
index eb668517bdf348ba514bfa4b9f437ed740b9bbec..7bd9adcba9bd1eebd3ef3fceb2d73d1f3237860d 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
 // check that panics in destructors during assignment do not leave
 // destroyed values lying around for other destructors to observe.
 
@@ -35,7 +33,6 @@ fn drop(&mut self) {
     }
 }
 
-#[rustc_mir]
 fn foo(b: &mut Observer) {
     *b.0 = FilledOnDrop(1);
 }
index 1a4330523babe968b889fe6e5721278f8fd675c9..98311525ad0f26b77a61c473654fdd7996b82bb3 100644 (file)
@@ -7,7 +7,6 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
-#![feature(rustc_attrs)]
 
 // error-pattern:panic 1
 // error-pattern:drop 2
@@ -24,7 +23,6 @@ fn drop(&mut self) {
     }
 }
 
-#[rustc_mir]
 fn mir() {
     let x = Droppable(2);
     let y = Droppable(1);
index 16160a1496ff9d1dc20eb2824e7cd9bbbbd9bdb4..6cf2851d93d472b664a1e6999e74b9c963252cdd 100644 (file)
@@ -7,7 +7,6 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
-#![feature(rustc_attrs)]
 // error-pattern:drop 1
 // error-pattern:drop 2
 use std::io::{self, Write};
@@ -26,7 +25,6 @@ fn drop(&mut self) {
     }
 }
 
-#[rustc_mir]
 fn mir() {
     let (mut xv, mut yv) = (false, false);
     let x = Droppable(&mut xv, 1);
index 803ca53bf7a848c00aa4b13a4653b4d237950ff7..7a90298e4225323ab81633d0796bb61b68db9fc1 100644 (file)
@@ -7,7 +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.
-#![feature(rustc_attrs)]
+
 // error-pattern:drop 1
 use std::io::{self, Write};
 
@@ -25,7 +25,6 @@ fn drop(&mut self) {
     }
 }
 
-#[rustc_mir]
 fn mir<'a>(d: Droppable<'a>) {
     loop {
         let x = d;
index afc037f48aa43723b04e29454062927dde1416c6..79ecbbb35bc56cc7f2082bc73759d9577c5c2cbf 100644 (file)
@@ -7,7 +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.
-#![feature(rustc_attrs)]
+
 // error-pattern:unwind happens
 // error-pattern:drop 3
 // error-pattern:drop 2
@@ -32,7 +32,6 @@ fn may_panic<'a>() -> Droppable<'a> {
     panic!("unwind happens");
 }
 
-#[rustc_mir]
 fn mir<'a>(d: Droppable<'a>) {
     let (mut a, mut b) = (false, false);
     let y = Droppable(&mut a, 2);
index e0d20a20577a8bfe8ec0999fd9c9822908b6140c..41ff466f810ea262d8cd9237e50b0f7172c4e9ac 100644 (file)
@@ -9,11 +9,9 @@
 // except according to those terms.
 
 // error-pattern:index out of bounds: the len is 5 but the index is 10
-#![feature(rustc_attrs)]
 
 const C: [u32; 5] = [0; 5];
 
-#[rustc_mir]
 fn test() -> u32 {
     C[10]
 }
index 6c65be5769f2d4bec1baeb277d458288a64c9013..c5c823428bc94edfcf26095d60614c990252e7f1 100644 (file)
@@ -9,11 +9,9 @@
 // except according to those terms.
 
 // error-pattern:index out of bounds: the len is 5 but the index is 10
-#![feature(rustc_attrs)]
 
 const C: &'static [u8; 5] = b"hello";
 
-#[rustc_mir]
 fn test() -> u8 {
     C[10]
 }
index 5f3fc9376b0d3ec69b367203c9a5fc8033f3c654..9bc4b0025e55ad46f604fddd34a0438430a48d85 100644 (file)
@@ -9,11 +9,9 @@
 // except according to those terms.
 
 // error-pattern:index out of bounds: the len is 5 but the index is 10
-#![feature(rustc_attrs)]
 
 const C: &'static [u8; 5] = b"hello";
 
-#[rustc_mir]
 fn mir() -> u8 {
     C[10]
 }
index 5927d802b4560a913a38ddc797ec233e98be6b51..7a7526c5fc1d37d220ab8c8d6aa98cbd8602b03e 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
 // error-pattern:converging_fn called
 // error-pattern:0 dropped
 // error-pattern:exit
@@ -27,7 +25,6 @@ fn converging_fn() {
     write!(io::stderr(), "converging_fn called\n");
 }
 
-#[rustc_mir]
 fn mir(d: Droppable) {
     converging_fn();
 }
index 96a46f47eb565ed2b70239e77446970fe0e63111..1301630cc85ea64b52ff3653fd8256e4d792c792 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
 // error-pattern:complex called
 // error-pattern:dropped
 // error-pattern:exit
@@ -30,7 +28,6 @@ fn complex() -> u64 {
 }
 
 
-#[rustc_mir]
 fn mir() -> u64 {
     let x = Droppable;
     return complex();
index fcd8ab26a0a8831c46508569d4de9023d2687f48..9dbf7de0d2d4988d6a9dc0e5c01641107a3b66e2 100644 (file)
@@ -7,14 +7,13 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
-#![feature(rustc_attrs)]
+
 // error-pattern:diverging_fn called
 
 fn diverging_fn() -> ! {
     panic!("diverging_fn called")
 }
 
-#[rustc_mir]
 fn mir() {
     diverging_fn();
 }
index 89b53b18f0619decc280777b09a3a880542b0b97..c191870492969628b96bcc86bf39c1254b6bbdd1 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
 // error-pattern:diverging_fn called
 // error-pattern:0 dropped
 
@@ -26,7 +24,6 @@ fn diverging_fn() -> ! {
     panic!("diverging_fn called")
 }
 
-#[rustc_mir]
 fn mir(d: Droppable) {
     diverging_fn();
 }
index bc913fdab1c07da5bf7b57517a57ded3389359eb..dacb039d89dc5c0e6694b84a65899ca152ca08a4 100644 (file)
@@ -7,7 +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.
-#![feature(rustc_attrs)]
+
 // compile-flags: -Z no-landing-pads
 // error-pattern:converging_fn called
 use std::io::{self, Write};
@@ -23,7 +23,6 @@ fn converging_fn() {
     panic!("converging_fn called")
 }
 
-#[rustc_mir]
 fn mir(d: Droppable) {
     let x = Droppable;
     converging_fn();
index d97eb8c89e3e0ce01d54da852e132c74214b5264..87037c1efed9e02e3db69003f8e6f72f3189fa13 100644 (file)
@@ -7,7 +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.
-#![feature(rustc_attrs)]
+
 // compile-flags: -Z no-landing-pads
 // error-pattern:diverging_fn called
 use std::io::{self, Write};
@@ -23,7 +23,6 @@ fn diverging_fn() -> ! {
     panic!("diverging_fn called")
 }
 
-#[rustc_mir]
 fn mir(d: Droppable) {
     let x = Droppable;
     diverging_fn();
index 42135703b75a4e9f3f9576ad71dc28f5c55bf109..6b688b006bd4a675c8478cb5c64b3bcc0be103f2 100644 (file)
@@ -24,7 +24,6 @@
 use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable};
 use syntax::ext::build::AstBuilder;
 use syntax::parse::token;
-use syntax::ptr::P;
 use syntax_ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure};
 use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self};
 use syntax_pos::Span;
@@ -50,6 +49,7 @@ fn expand(cx: &mut ExtCtxt,
         generics: LifetimeBounds::empty(),
         associated_types: vec![],
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![
             MethodDef {
                 name: "total_sum",
index eeecd0b24e29ee60ef314c8c8a4b8b8e88279f5c..c6174745bfc0626574ab13d210fb39f0879190ed 100644 (file)
 extern crate rustc_plugin;
 
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable};
 use syntax::ext::build::AstBuilder;
 use syntax::parse::token;
 use syntax::ptr::P;
-use syntax_ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure};
+use syntax_ext::deriving::generic::{TraitDef, MethodDef, combine_substructure};
 use syntax_ext::deriving::generic::{Substructure, Struct, EnumMatching};
 use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self};
 use syntax_pos::Span;
@@ -52,6 +51,7 @@ fn expand(cx: &mut ExtCtxt,
         generics: LifetimeBounds::empty(),
         associated_types: vec![],
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![
             MethodDef {
                 name: "total_sum",
index 604933d40a12c688d4ee26a13033dbbc8eb2c24c..f7b046b30cad7397c1652726fe6824e9b508d8bd 100644 (file)
@@ -19,7 +19,7 @@
 extern crate syntax;
 
 use rustc::mir::transform::{self, MirPass, MirSource};
-use rustc::mir::repr::{Mir, Literal};
+use rustc::mir::repr::{Mir, Literal, Location};
 use rustc::mir::visit::MutVisitor;
 use rustc::ty::TyCtxt;
 use rustc::middle::const_val::ConstVal;
@@ -40,7 +40,7 @@ fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>,
 struct Visitor;
 
 impl<'tcx> MutVisitor<'tcx> for Visitor {
-    fn visit_literal(&mut self, literal: &mut Literal<'tcx>) {
+    fn visit_literal(&mut self, literal: &mut Literal<'tcx>, _: Location) {
         if let Literal::Value { ref mut value } = *literal {
             if let ConstVal::Integral(ConstInt::I32(ref mut i @ 11)) = *value {
                 *i = 42;
index 3f50811f826e07e83a37bd50d8b0fbfac40fc665..46fdf911258456e685643c9c2ec0ead5d2536986 100644 (file)
 extern crate rustc_plugin;
 extern crate syntax_pos;
 
-use syntax::ast::{self, Item, MetaItem, ImplItem, TraitItem, ItemKind};
+use syntax::ast::{self, Item, MetaItem, ItemKind};
+use syntax::codemap::DUMMY_SP;
 use syntax::ext::base::*;
+use syntax::ext::quote::rt::ToTokens;
 use syntax::parse::{self, token};
 use syntax::ptr::P;
 use syntax::tokenstream::TokenTree;
@@ -41,10 +43,13 @@ pub fn plugin_registrar(reg: &mut Registry) {
         token::intern("duplicate"),
         // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
         MultiDecorator(Box::new(expand_duplicate)));
+    reg.register_syntax_extension(
+        token::intern("caller"),
+        // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
+        MultiDecorator(Box::new(expand_caller)));
 }
 
-fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
-                   -> Box<MacResult+'static> {
+fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
     if !tts.is_empty() {
         cx.span_fatal(sp, "make_a_1 takes no arguments");
     }
@@ -52,19 +57,18 @@ fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
 }
 
 // See Issue #15750
-fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree])
-                   -> Box<MacResult+'static> {
+fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
     // Parse an expression and emit it unchanged.
-    let mut parser = parse::new_parser_from_tts(cx.parse_sess(),
-        cx.cfg(), tts.to_vec());
+    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_vec());
     let expr = parser.parse_expr().unwrap();
     MacEager::expr(quote_expr!(&mut *cx, $expr))
 }
 
 fn expand_into_foo_multi(cx: &mut ExtCtxt,
-                         sp: Span,
-                         attr: &MetaItem,
-                         it: Annotatable) -> Vec<Annotatable> {
+                         _sp: Span,
+                         _attr: &MetaItem,
+                         it: Annotatable)
+                         -> Vec<Annotatable> {
     match it {
         Annotatable::Item(it) => vec![
             Annotatable::Item(P(Item {
@@ -74,7 +78,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
             Annotatable::Item(quote_item!(cx, enum Foo3 { Bar }).unwrap()),
             Annotatable::Item(quote_item!(cx, #[cfg(any())] fn foo2() {}).unwrap()),
         ],
-        Annotatable::ImplItem(it) => vec![
+        Annotatable::ImplItem(_it) => vec![
             quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| {
                 match i.node {
                     ItemKind::Impl(_, _, _, _, _, mut items) => {
@@ -84,7 +88,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
                 }
             })
         ],
-        Annotatable::TraitItem(it) => vec![
+        Annotatable::TraitItem(_it) => vec![
             quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| {
                 match i.node {
                     ItemKind::Trait(_, _, _, mut items) => {
@@ -99,15 +103,14 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
 
 // Create a duplicate of the annotatable, based on the MetaItem
 fn expand_duplicate(cx: &mut ExtCtxt,
-                    sp: Span,
+                    _sp: Span,
                     mi: &MetaItem,
                     it: &Annotatable,
-                    push: &mut FnMut(Annotatable))
-{
+                    push: &mut FnMut(Annotatable)) {
     let copy_name = match mi.node {
         ast::MetaItemKind::List(_, ref xs) => {
-            if let ast::MetaItemKind::Word(ref w) = xs[0].node {
-                token::str_to_ident(&w)
+            if let Some(word) = xs[0].word() {
+                token::str_to_ident(&word.name())
             } else {
                 cx.span_err(mi.span, "Expected word");
                 return;
@@ -142,4 +145,69 @@ fn expand_duplicate(cx: &mut ExtCtxt,
     }
 }
 
+pub fn token_separate<T: ToTokens>(ecx: &ExtCtxt, things: &[T],
+                                   token: token::Token) -> Vec<TokenTree> {
+    let mut output: Vec<TokenTree> = vec![];
+    for (i, thing) in things.iter().enumerate() {
+        output.extend(thing.to_tokens(ecx));
+        if i < things.len() - 1 {
+            output.push(TokenTree::Token(DUMMY_SP, token.clone()));
+        }
+    }
+
+    output
+}
+
+fn expand_caller(cx: &mut ExtCtxt,
+                 sp: Span,
+                 mi: &MetaItem,
+                 it: &Annotatable,
+                 push: &mut FnMut(Annotatable)) {
+    let (orig_fn_name, ret_type) = match *it {
+        Annotatable::Item(ref item) => match item.node {
+            ItemKind::Fn(ref decl, _, _, _, _, _) => {
+                (item.ident, &decl.output)
+            }
+            _ => cx.span_fatal(item.span, "Only functions with return types can be annotated.")
+        },
+        _ => cx.span_fatal(sp, "Only functions can be annotated.")
+    };
+
+    let (caller_name, arguments) = if let Some(list) = mi.meta_item_list() {
+        if list.len() < 2 {
+            cx.span_fatal(mi.span(), "Need a function name and at least one parameter.");
+        }
+
+        let fn_name = match list[0].name() {
+            Some(name) => token::str_to_ident(&name),
+            None => cx.span_fatal(list[0].span(), "First parameter must be an ident.")
+        };
+
+        (fn_name, &list[1..])
+    } else {
+        cx.span_fatal(mi.span, "Expected list.");
+    };
+
+    let literals: Vec<ast::Lit> = arguments.iter().map(|arg| {
+        if let Some(lit) = arg.literal() {
+            lit.clone()
+        } else {
+            cx.span_fatal(arg.span(), "Expected literal.");
+        }
+    }).collect();
+
+    let arguments = token_separate(cx, literals.as_slice(), token::Comma);
+    if let ast::FunctionRetTy::Ty(ref rt) = *ret_type {
+        push(Annotatable::Item(quote_item!(cx,
+                                           fn $caller_name() -> $rt {
+                                               $orig_fn_name($arguments)
+                                           }).unwrap()))
+    } else {
+        push(Annotatable::Item(quote_item!(cx,
+                                           fn $caller_name() {
+                                               $orig_fn_name($arguments)
+                                           }).unwrap()))
+    }
+}
+
 pub fn foo() {}
index f0edc0f2b120f887dde338ce2b9ae1774a1c4f9a..f21c914a76c9c7406bee608dda9d53a7f7a1b5ef 100644 (file)
@@ -30,7 +30,7 @@
 use rustc_plugin::Registry;
 
 struct Expander {
-    args: Vec<P<ast::MetaItem>>,
+    args: Vec<ast::NestedMetaItem>,
 }
 
 impl TTMacroExpander for Expander {
@@ -38,7 +38,7 @@ fn expand<'cx>(&self,
                    ecx: &'cx mut ExtCtxt,
                    sp: Span,
                    _: &[tokenstream::TokenTree]) -> Box<MacResult+'cx> {
-        let args = self.args.iter().map(|i| pprust::meta_item_to_string(&*i))
+        let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i))
             .collect::<Vec<_>>().join(", ");
         let interned = token::intern_and_get_ident(&args[..]);
         MacEager::expr(ecx.expr_str(sp, interned))
index 69a7f888bbe09d49422cdc0e7a5a6fc723593d63..be2a45ca79abd9762de01cba088c980a47e2481e 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![feature(rustc_private)]
+#![allow(dead_code)]
 
 extern crate serialize;
 
index 8d19209208dc45f08fe2bfe76fd694416a4aa88c..66ffff94333e9fe19ed869c3739e105f6852c96f 100644 (file)
@@ -8,8 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// `#[derive(Trait)]` works for empty structs/variants with braces
+// `#[derive(Trait)]` works for empty structs/variants with braces or parens.
 
+#![feature(relaxed_adts)]
 #![feature(rustc_private)]
 
 extern crate serialize as rustc_serialize;
          Default, Debug, RustcEncodable, RustcDecodable)]
 struct S {}
 
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
+         Default, Debug, RustcEncodable, RustcDecodable)]
+struct Z();
+
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
          Debug, RustcEncodable, RustcDecodable)]
 enum E {
     V {},
     U,
+    W(),
 }
 
 fn main() {
@@ -34,6 +40,14 @@ fn main() {
     assert!(!(s < s1));
     assert_eq!(format!("{:?}", s), "S");
 
+    let z = Z();
+    let z1 = z;
+    let z2 = z.clone();
+    assert_eq!(z, z1);
+    assert_eq!(z, z2);
+    assert!(!(z < z1));
+    assert_eq!(format!("{:?}", z), "Z");
+
     let e = E::V {};
     let e1 = e;
     let e2 = e.clone();
@@ -41,4 +55,12 @@ fn main() {
     assert_eq!(e, e2);
     assert!(!(e < e1));
     assert_eq!(format!("{:?}", e), "V");
+
+    let e = E::W();
+    let e1 = e;
+    let e2 = e.clone();
+    assert_eq!(e, e1);
+    assert_eq!(e, e2);
+    assert!(!(e < e1));
+    assert_eq!(format!("{:?}", e), "W");
 }
index 1a639cdb9ddfa24e3edbd479e50f4f0b02250b4c..21942b84bff9c95261a4d6a39a5801f9932f739a 100644 (file)
@@ -14,6 +14,7 @@
 
 #![feature(plugin)]
 #![plugin(lint_group_plugin_test)]
+#![allow(dead_code)]
 
 fn lintme() { } //~ WARNING item is named 'lintme'
 fn pleaselintme() { } //~ WARNING item is named 'pleaselintme'
index 1af26094f231541f22054351f891398b6b31a633..2a6daa5040b7189456f32228e35f0d694f471daf 100644 (file)
@@ -13,6 +13,8 @@
 // ignore-pretty: Random space appears with the pretty test
 // compile-flags: -Z extra-plugins=lint_plugin_test
 
+#![allow(dead_code)]
+
 fn lintme() { } //~ WARNING item is named 'lintme'
 
 #[allow(test_lint)]
index 8311e188f922935c29517e1f74013c0c3bc01bce..b694a1c332079969040f7fa24830f3825bf49e43 100644 (file)
@@ -14,6 +14,7 @@
 
 #![feature(plugin)]
 #![plugin(lint_plugin_test)]
+#![allow(dead_code)]
 
 fn lintme() { } //~ WARNING item is named 'lintme'
 
diff --git a/src/test/run-pass-fulldeps/macro-crate-multi-decorator-literals.rs b/src/test/run-pass-fulldeps/macro-crate-multi-decorator-literals.rs
new file mode 100644 (file)
index 0000000..6dc651b
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// 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:macro_crate_test.rs
+// ignore-stage1
+
+#![feature(plugin, custom_attribute, attr_literals)]
+#![plugin(macro_crate_test)]
+
+#[macro_use]
+#[no_link]
+extern crate macro_crate_test;
+
+// The `caller(name, args...)` attribute emits a new nullary function named
+// `name` that calls the annotated function with `args`. As an example, consider
+// the following:
+//
+//     #[caller(simple, 1, "hello", 3.14)]
+//     fn f(num: isize, string: &'static str, float: f32) -> (isize, &'static str, float) {
+//         (num, string, float)
+//     }
+//
+// This results in a function named `simple` that calls `f(1, "hello", 3.14)`.
+// As a result, the expression `simple()` evaluates to `(1, "helllo", 3.14)`.
+
+#[caller(simple, 1, "hello", 3.14)]
+#[caller(simple1, 2, "bye", 6.28)]
+#[caller(simple2, 3, "hi", 1.01)]
+fn f(num: isize, string: &'static str, float: f32) -> (isize, &'static str, f32) {
+    (num, string, float)
+}
+
+#[caller(complex, true, 10)]
+#[caller(complex1, false, 15)]
+#[caller(complex2, true, 20)]
+fn g(emit: bool, num: i32) -> Option<i32> {
+    match emit {
+        true => Some(num),
+        false => None
+    }
+}
+
+fn main() {
+    assert_eq!(simple(), (1, "hello", 3.14));
+    assert_eq!(simple1(), (2, "bye", 6.28));
+    assert_eq!(simple2(), (3, "hi", 1.01));
+
+    assert_eq!(complex(), Some(10));
+    assert_eq!(complex1(), None);
+    assert_eq!(complex2(), Some(20));
+}
index acf11e241033cccf6ab5b8e4c8053555201d9943..8ac4bf9733757cc25a1af1da68c0d3b9d14f8300 100644 (file)
 // aux-build:dummy_mir_pass.rs
 // ignore-stage1
 
-#![feature(plugin, rustc_attrs)]
+#![feature(plugin)]
 #![plugin(dummy_mir_pass)]
 
-#[rustc_mir]
 fn math() -> i32 {
     11
 }
index 0de949471c68407cf66129e7aaa16d494d473d6d..7cf75924a28c0c7fd67bcb941694986bdeeda972 100644 (file)
@@ -13,7 +13,7 @@
 // no-prefer-dynamic
 
 #![allow(dead_code)]
-#![feature(const_fn, rustc_attrs)]
+#![feature(const_fn)]
 
 // check dtor calling order when casting enums.
 
@@ -38,7 +38,6 @@ fn drop(&mut self) {
     }
 }
 
-#[rustc_no_mir] // FIXME #27840 MIR miscompiles this.
 fn main() {
     assert_eq!(FLAG.load(Ordering::SeqCst), 0);
     {
@@ -46,5 +45,5 @@ fn main() {
         assert_eq!(e as u32, 2);
         assert_eq!(FLAG.load(Ordering::SeqCst), 0);
     }
-    assert_eq!(FLAG.load(Ordering::SeqCst), 1);
+    assert_eq!(FLAG.load(Ordering::SeqCst), 0);
 }
diff --git a/src/test/run-pass/abi-sysv64-arg-passing.rs b/src/test/run-pass/abi-sysv64-arg-passing.rs
new file mode 100644 (file)
index 0000000..989155b
--- /dev/null
@@ -0,0 +1,341 @@
+// 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.
+
+// Checks if the "sysv64" calling convention behaves the same as the
+// "C" calling convention on platforms where both should be the same
+
+// This file contains versions of the following run-pass tests with
+// the calling convention changed to "sysv64"
+
+// cabi-int-widening
+// extern-pass-char
+// extern-pass-u32
+// extern-pass-u64
+// extern-pass-double
+// extern-pass-empty
+// extern-pass-TwoU8s
+// extern-pass-TwoU16s
+// extern-pass-TwoU32s
+// extern-pass-TwoU64s
+// extern-return-TwoU8s
+// extern-return-TwoU16s
+// extern-return-TwoU32s
+// extern-return-TwoU64s
+// foreign-fn-with-byval
+// issue-28676
+// struct-return
+
+// ignore-android
+// ignore-arm
+// ignore-aarch64
+// ignore-windows
+
+// note: windows is ignored as rust_test_helpers does not have the sysv64 abi on windows
+
+#![feature(abi_sysv64)]
+#[allow(dead_code)]
+#[allow(improper_ctypes)]
+
+#[cfg(target_arch = "x86_64")]
+mod tests {
+    #[repr(C)]
+    #[derive(Copy, Clone, PartialEq, Debug)]
+    pub struct TwoU8s {
+        one: u8, two: u8
+    }
+
+    #[repr(C)]
+    #[derive(Copy, Clone, PartialEq, Debug)]
+    pub struct TwoU16s {
+        one: u16, two: u16
+    }
+
+    #[repr(C)]
+    #[derive(Copy, Clone, PartialEq, Debug)]
+    pub struct TwoU32s {
+        one: u32, two: u32
+    }
+
+    #[repr(C)]
+    #[derive(Copy, Clone, PartialEq, Debug)]
+    pub struct TwoU64s {
+        one: u64, two: u64
+    }
+
+    #[repr(C)]
+    pub struct ManyInts {
+        arg1: i8,
+        arg2: i16,
+        arg3: i32,
+        arg4: i16,
+        arg5: i8,
+        arg6: TwoU8s,
+    }
+
+    #[repr(C)]
+    pub struct Empty;
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct S {
+        x: u64,
+        y: u64,
+        z: u64,
+    }
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct Quad { a: u64, b: u64, c: u64, d: u64 }
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct Floats { a: f64, b: u8, c: f64 }
+
+    #[link(name = "rust_test_helpers")]
+    extern "sysv64" {
+        pub fn rust_int8_to_int32(_: i8) -> i32;
+        pub fn rust_dbg_extern_identity_u8(v: u8) -> u8;
+        pub fn rust_dbg_extern_identity_u32(v: u32) -> u32;
+        pub fn rust_dbg_extern_identity_u64(v: u64) -> u64;
+        pub fn rust_dbg_extern_identity_double(v: f64) -> f64;
+        pub fn rust_dbg_extern_empty_struct(v1: ManyInts, e: Empty, v2: ManyInts);
+        pub fn rust_dbg_extern_identity_TwoU8s(v: TwoU8s) -> TwoU8s;
+        pub fn rust_dbg_extern_identity_TwoU16s(v: TwoU16s) -> TwoU16s;
+        pub fn rust_dbg_extern_identity_TwoU32s(v: TwoU32s) -> TwoU32s;
+        pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s;
+        pub fn rust_dbg_extern_return_TwoU8s() -> TwoU8s;
+        pub fn rust_dbg_extern_return_TwoU16s() -> TwoU16s;
+        pub fn rust_dbg_extern_return_TwoU32s() -> TwoU32s;
+        pub fn rust_dbg_extern_return_TwoU64s() -> TwoU64s;
+        pub fn get_x(x: S) -> u64;
+        pub fn get_y(x: S) -> u64;
+        pub fn get_z(x: S) -> u64;
+        pub fn get_c_many_params(_: *const (), _: *const (),
+                                 _: *const (), _: *const (), f: Quad) -> u64;
+        pub fn rust_dbg_abi_1(q: Quad) -> Quad;
+        pub fn rust_dbg_abi_2(f: Floats) -> Floats;
+    }
+
+    pub fn cabi_int_widening() {
+        let x = unsafe {
+            rust_int8_to_int32(-1)
+        };
+
+        assert!(x == -1);
+    }
+
+    pub fn extern_pass_char() {
+        unsafe {
+            assert_eq!(22, rust_dbg_extern_identity_u8(22));
+        }
+    }
+
+    pub fn extern_pass_u32() {
+        unsafe {
+            assert_eq!(22, rust_dbg_extern_identity_u32(22));
+        }
+    }
+
+    pub fn extern_pass_u64() {
+        unsafe {
+            assert_eq!(22, rust_dbg_extern_identity_u64(22));
+        }
+    }
+
+    pub fn extern_pass_double() {
+        unsafe {
+            assert_eq!(22.0_f64, rust_dbg_extern_identity_double(22.0_f64));
+        }
+    }
+
+    pub fn extern_pass_empty() {
+        unsafe {
+            let x = ManyInts {
+                arg1: 2,
+                arg2: 3,
+                arg3: 4,
+                arg4: 5,
+                arg5: 6,
+                arg6: TwoU8s { one: 7, two: 8, }
+            };
+            let y = ManyInts {
+                arg1: 1,
+                arg2: 2,
+                arg3: 3,
+                arg4: 4,
+                arg5: 5,
+                arg6: TwoU8s { one: 6, two: 7, }
+            };
+            let empty = Empty;
+            rust_dbg_extern_empty_struct(x, empty, y);
+        }
+    }
+
+    pub fn extern_pass_twou8s() {
+        unsafe {
+            let x = TwoU8s {one: 22, two: 23};
+            let y = rust_dbg_extern_identity_TwoU8s(x);
+            assert_eq!(x, y);
+        }
+    }
+
+    pub fn extern_pass_twou16s() {
+        unsafe {
+            let x = TwoU16s {one: 22, two: 23};
+            let y = rust_dbg_extern_identity_TwoU16s(x);
+            assert_eq!(x, y);
+        }
+    }
+
+    pub fn extern_pass_twou32s() {
+        unsafe {
+            let x = TwoU32s {one: 22, two: 23};
+            let y = rust_dbg_extern_identity_TwoU32s(x);
+            assert_eq!(x, y);
+        }
+    }
+
+    pub fn extern_pass_twou64s() {
+        unsafe {
+            let x = TwoU64s {one: 22, two: 23};
+            let y = rust_dbg_extern_identity_TwoU64s(x);
+            assert_eq!(x, y);
+        }
+    }
+
+    pub fn extern_return_twou8s() {
+        unsafe {
+            let y = rust_dbg_extern_return_TwoU8s();
+            assert_eq!(y.one, 10);
+            assert_eq!(y.two, 20);
+        }
+    }
+
+    pub fn extern_return_twou16s() {
+        unsafe {
+            let y = rust_dbg_extern_return_TwoU16s();
+            assert_eq!(y.one, 10);
+            assert_eq!(y.two, 20);
+        }
+    }
+
+    pub fn extern_return_twou32s() {
+        unsafe {
+            let y = rust_dbg_extern_return_TwoU32s();
+            assert_eq!(y.one, 10);
+            assert_eq!(y.two, 20);
+        }
+    }
+
+    pub fn extern_return_twou64s() {
+        unsafe {
+            let y = rust_dbg_extern_return_TwoU64s();
+            assert_eq!(y.one, 10);
+            assert_eq!(y.two, 20);
+        }
+    }
+
+    #[inline(never)]
+    fn indirect_call(func: unsafe extern "sysv64" fn(s: S) -> u64, s: S) -> u64 {
+        unsafe {
+            func(s)
+        }
+    }
+
+    pub fn foreign_fn_with_byval() {
+        let s = S { x: 1, y: 2, z: 3 };
+        assert_eq!(s.x, indirect_call(get_x, s));
+        assert_eq!(s.y, indirect_call(get_y, s));
+        assert_eq!(s.z, indirect_call(get_z, s));
+    }
+
+    fn test() {
+        use std::ptr;
+        unsafe {
+            let null = ptr::null();
+            let q = Quad {
+                a: 1,
+                b: 2,
+                c: 3,
+                d: 4
+            };
+            assert_eq!(get_c_many_params(null, null, null, null, q), q.c);
+        }
+    }
+
+    pub fn issue_28676() {
+        test();
+    }
+
+    fn test1() {
+        unsafe {
+            let q = Quad { a: 0xaaaa_aaaa_aaaa_aaaa,
+                     b: 0xbbbb_bbbb_bbbb_bbbb,
+                     c: 0xcccc_cccc_cccc_cccc,
+                     d: 0xdddd_dddd_dddd_dddd };
+            let qq = rust_dbg_abi_1(q);
+            println!("a: {:x}", qq.a as usize);
+            println!("b: {:x}", qq.b as usize);
+            println!("c: {:x}", qq.c as usize);
+            println!("d: {:x}", qq.d as usize);
+            assert_eq!(qq.a, q.c + 1);
+            assert_eq!(qq.b, q.d - 1);
+            assert_eq!(qq.c, q.a + 1);
+            assert_eq!(qq.d, q.b - 1);
+        }
+    }
+
+    fn test2() {
+        unsafe {
+            let f = Floats { a: 1.234567890e-15_f64,
+                     b: 0b_1010_1010,
+                     c: 1.0987654321e-15_f64 };
+            let ff = rust_dbg_abi_2(f);
+            println!("a: {}", ff.a as f64);
+            println!("b: {}", ff.b as usize);
+            println!("c: {}", ff.c as f64);
+            assert_eq!(ff.a, f.c + 1.0f64);
+            assert_eq!(ff.b, 0xff);
+            assert_eq!(ff.c, f.a - 1.0f64);
+        }
+    }
+
+    pub fn struct_return() {
+        test1();
+        test2();
+    }
+}
+
+#[cfg(target_arch = "x86_64")]
+fn main() {
+    use tests::*;
+    cabi_int_widening();
+    extern_pass_char();
+    extern_pass_u32();
+    extern_pass_u64();
+    extern_pass_double();
+    extern_pass_empty();
+    extern_pass_twou8s();
+    extern_pass_twou16s();
+    extern_pass_twou32s();
+    extern_pass_twou64s();
+    extern_return_twou8s();
+    extern_return_twou16s();
+    extern_return_twou32s();
+    extern_return_twou64s();
+    foreign_fn_with_byval();
+    issue_28676();
+    struct_return();
+}
+
+#[cfg(not(target_arch = "x86_64"))]
+fn main() {
+
+}
diff --git a/src/test/run-pass/abi-sysv64-register-usage.rs b/src/test/run-pass/abi-sysv64-register-usage.rs
new file mode 100644 (file)
index 0000000..7e3b321
--- /dev/null
@@ -0,0 +1,106 @@
+// 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.
+
+// Checks if the correct registers are being used to pass arguments
+// when the sysv64 ABI is specified.
+
+// ignore-android
+// ignore-arm
+// ignore-aarch64
+
+#![feature(abi_sysv64)]
+#![feature(asm)]
+
+#[cfg(target_arch = "x86_64")]
+pub extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64,
+                                         rcx: i64, r8 : i64, r9 : i64,
+                                         xmm0: f32, xmm1: f32, xmm2: f32,
+                                         xmm3: f32, xmm4: f32, xmm5: f32,
+                                         xmm6: f32, xmm7: f32) -> i64 {
+    assert_eq!(rdi, 1);
+    assert_eq!(rsi, 2);
+    assert_eq!(rdx, 3);
+    assert_eq!(rcx, 4);
+    assert_eq!(r8,  5);
+    assert_eq!(r9,  6);
+    assert_eq!(xmm0, 1.0f32);
+    assert_eq!(xmm1, 2.0f32);
+    assert_eq!(xmm2, 4.0f32);
+    assert_eq!(xmm3, 8.0f32);
+    assert_eq!(xmm4, 16.0f32);
+    assert_eq!(xmm5, 32.0f32);
+    assert_eq!(xmm6, 64.0f32);
+    assert_eq!(xmm7, 128.0f32);
+    42
+}
+
+// this struct contains 8 i64's, while only 6 can be passed in registers.
+#[cfg(target_arch = "x86_64")]
+#[derive(PartialEq, Eq, Debug)]
+pub struct LargeStruct(i64, i64, i64, i64, i64, i64, i64, i64);
+
+#[cfg(target_arch = "x86_64")]
+#[inline(never)]
+pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct {
+    foo.0 *= 1;
+    foo.1 *= 2;
+    foo.2 *= 3;
+    foo.3 *= 4;
+    foo.4 *= 5;
+    foo.5 *= 6;
+    foo.6 *= 7;
+    foo.7 *= 8;
+    foo
+}
+
+#[cfg(target_arch = "x86_64")]
+pub fn main() {
+    let result: i64;
+    unsafe {
+        asm!("mov rdi, 1;
+              mov rsi, 2;
+              mov rdx, 3;
+              mov rcx, 4;
+              mov r8,  5;
+              mov r9,  6;
+              mov eax, 0x3F800000;
+              movd xmm0, eax;
+              mov eax, 0x40000000;
+              movd xmm1, eax;
+              mov eax, 0x40800000;
+              movd xmm2, eax;
+              mov eax, 0x41000000;
+              movd xmm3, eax;
+              mov eax, 0x41800000;
+              movd xmm4, eax;
+              mov eax, 0x42000000;
+              movd xmm5, eax;
+              mov eax, 0x42800000;
+              movd xmm6, eax;
+              mov eax, 0x43000000;
+              movd xmm7, eax;
+              call r10
+              "
+            : "={rax}"(result)
+            : "{r10}"(all_the_registers as usize)
+            : "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r11", "cc", "memory"
+            : "intel", "alignstack"
+        )
+    }
+    assert_eq!(result, 42);
+
+    assert_eq!(
+        large_struct_by_val(LargeStruct(1, 2, 3, 4, 5, 6, 7, 8)),
+        LargeStruct(1, 4, 9, 16, 25, 36, 49, 64)
+    );
+}
+
+#[cfg(not(target_arch = "x86_64"))]
+pub fn main() {}
\ No newline at end of file
diff --git a/src/test/run-pass/atomic-access-bool.rs b/src/test/run-pass/atomic-access-bool.rs
new file mode 100644 (file)
index 0000000..286c92c
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(atomic_access)]
+use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
+use std::sync::atomic::Ordering::*;
+
+static mut ATOMIC: AtomicBool = ATOMIC_BOOL_INIT;
+
+fn main() {
+    unsafe {
+        assert_eq!(*ATOMIC.get_mut(), false);
+        ATOMIC.store(true, SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), true);
+        ATOMIC.fetch_or(false, SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), true);
+        ATOMIC.fetch_and(false, SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), false);
+        ATOMIC.fetch_nand(true, SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), true);
+        ATOMIC.fetch_xor(true, SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), false);
+    }
+}
index cdd1b96de1e6081e14f965d594457a9a6c847a2b..2a86489c69aa58018244b699f00304e6314cf10d 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern:expected item
-
 // pretty-expanded FIXME #23616
 
 #![feature(custom_attribute, test)]
index cd02b5a9e73109498a2ba5ff438371facffd170f..c8683f2d1475139b2bb7ea99600f0d7757b2a5d2 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern:expected item
-
 // pretty-expanded FIXME #23616
 
 #![feature(custom_attribute, test)]
diff --git a/src/test/run-pass/attr-no-drop-flag-size.rs b/src/test/run-pass/attr-no-drop-flag-size.rs
deleted file mode 100644 (file)
index 0c464c9..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(unsafe_no_drop_flag)]
-
-use std::mem::size_of;
-
-#[unsafe_no_drop_flag]
-struct Test<T> {
-    a: T
-}
-
-impl<T> Drop for Test<T> {
-    fn drop(&mut self) { }
-}
-
-pub fn main() {
-    assert_eq!(size_of::<isize>(), size_of::<Test<isize>>());
-}
index a21deb44fcc834e7023a866f042686fb1f40f40a..ed42ad6e875273237792d9c3b799007d09ab3699 100644 (file)
@@ -8,9 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(unsafe_no_drop_flag)]
-
-#[unsafe_no_drop_flag]
 pub struct ZeroLengthThingWithDestructor;
 impl Drop for ZeroLengthThingWithDestructor {
     fn drop(&mut self) {}
index 5b55ef633353495021f941a21e57b5b3cb98979d..ff513325d5e6846260780b0ffdf117778f249c01 100644 (file)
@@ -10,6 +10,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![allow(dead_code)]
 
 #[derive]   //~ WARNING empty trait list in `derive`
 struct Foo;
diff --git a/src/test/run-pass/diverging-fn-tail-35849.rs b/src/test/run-pass/diverging-fn-tail-35849.rs
new file mode 100644 (file)
index 0000000..6c05a02
--- /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.
+
+fn assert_sizeof() -> ! {
+    unsafe {
+        ::std::mem::transmute::<f64, [u8; 8]>(panic!())
+    }
+}
+
+fn main() { }
+
diff --git a/src/test/run-pass/drop-flag-sanity-check.rs b/src/test/run-pass/drop-flag-sanity-check.rs
deleted file mode 100644 (file)
index a801476..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z force-dropflag-checks=on
-// ignore-emscripten
-
-// Quick-and-dirty test to ensure -Z force-dropflag-checks=on works as
-// expected. Note that the inlined drop-flag is slated for removal
-// (RFC 320); when that happens, the -Z flag and this test should
-// simply be removed.
-//
-// See also drop-flag-skip-sanity-check.rs.
-
-use std::env;
-use std::process::Command;
-
-fn main() {
-    let args: Vec<String> = env::args().collect();
-    if args.len() > 1 && args[1] == "test" {
-        return test();
-    }
-
-    let mut p = Command::new(&args[0]).arg("test").spawn().unwrap();
-    // The invocation should fail due to the drop-flag sanity check.
-    assert!(!p.wait().unwrap().success());
-}
-
-#[derive(Debug)]
-struct Corrupted {
-    x: u8
-}
-
-impl Drop for Corrupted {
-    fn drop(&mut self) { println!("dropping"); }
-}
-
-fn test() {
-    {
-        let mut c1 = Corrupted { x: 1 };
-        let mut c2 = Corrupted { x: 2 };
-        unsafe {
-            let p1 = &mut c1 as *mut Corrupted as *mut u8;
-            let p2 = &mut c2 as *mut Corrupted as *mut u8;
-            for i in 0..std::mem::size_of::<Corrupted>() {
-                // corrupt everything, *including the drop flag.
-                //
-                // (We corrupt via two different means to safeguard
-                // against the hypothetical assignment of the
-                // dtor_needed/dtor_done values to v and v+k.  that
-                // happen to match with one of the corruption values
-                // below.)
-                *p1.offset(i as isize) += 2;
-                *p2.offset(i as isize) += 3;
-            }
-        }
-        // Here, at the end of the scope of `c1` and `c2`, the
-        // drop-glue should detect the corruption of (at least one of)
-        // the drop-flags.
-    }
-    println!("We should never get here.");
-}
diff --git a/src/test/run-pass/drop-flag-skip-sanity-check.rs b/src/test/run-pass/drop-flag-skip-sanity-check.rs
deleted file mode 100644 (file)
index 07a10c8..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z force-dropflag-checks=off
-// ignore-emscripten no threads support
-
-// Quick-and-dirty test to ensure -Z force-dropflag-checks=off works as
-// expected. Note that the inlined drop-flag is slated for removal
-// (RFC 320); when that happens, the -Z flag and this test should
-// simply be removed.
-//
-// See also drop-flag-sanity-check.rs.
-
-use std::env;
-use std::process::Command;
-
-fn main() {
-    let args: Vec<String> = env::args().collect();
-    if args.len() > 1 && args[1] == "test" {
-        return test();
-    }
-
-    let s = Command::new(&args[0]).arg("test").status().unwrap();
-    // Invocatinn should succeed as drop-flag sanity check is skipped.
-    assert!(s.success());
-}
-
-#[derive(Debug)]
-struct Corrupted {
-    x: u8
-}
-
-impl Drop for Corrupted {
-    fn drop(&mut self) { println!("dropping"); }
-}
-
-fn test() {
-    {
-        let mut c1 = Corrupted { x: 1 };
-        let mut c2 = Corrupted { x: 2 };
-        unsafe {
-            let p1 = &mut c1 as *mut Corrupted as *mut u8;
-            let p2 = &mut c2 as *mut Corrupted as *mut u8;
-            for i in 0..std::mem::size_of::<Corrupted>() {
-                // corrupt everything, *including the drop flag.
-                //
-                // (We corrupt via two different means to safeguard
-                // against the hypothetical assignment of the
-                // dtor_needed/dtor_done values to v and v+k.  that
-                // happen to match with one of the corruption values
-                // below.)
-                *p1.offset(i as isize) += 2;
-                *p2.offset(i as isize) += 3;
-            }
-        }
-        // Here, at the end of the scope of `c1` and `c2`, the
-        // drop-glue should detect the corruption of (at least one of)
-        // the drop-flags.
-    }
-}
index f917531e868f1ba29d93c75ce5b8a5a4bd287060..2b016dfb33ecaf33f69e7003ae40ad70ae009116 100644 (file)
@@ -74,7 +74,6 @@ fn drop(&mut self) {
     }
 }
 
-#[rustc_mir]
 fn dynamic_init(a: &Allocator, c: bool) {
     let _x;
     if c {
@@ -82,7 +81,6 @@ fn dynamic_init(a: &Allocator, c: bool) {
     }
 }
 
-#[rustc_mir]
 fn dynamic_drop(a: &Allocator, c: bool) {
     let x = a.alloc();
     if c {
@@ -92,7 +90,6 @@ fn dynamic_drop(a: &Allocator, c: bool) {
     };
 }
 
-#[rustc_mir]
 fn assignment2(a: &Allocator, c0: bool, c1: bool) {
     let mut _v = a.alloc();
     let mut _w = a.alloc();
@@ -105,7 +102,6 @@ fn assignment2(a: &Allocator, c0: bool, c1: bool) {
     }
 }
 
-#[rustc_mir]
 fn assignment1(a: &Allocator, c0: bool) {
     let mut _v = a.alloc();
     let mut _w = a.alloc();
index 0bf5df5d61021f204df4adc8ed402780ff5c6653..21996c5fabf1a30c2bd310c158dbfa888a844749 100644 (file)
@@ -10,7 +10,7 @@
 //
 // ignore-pretty
 
-#![deny(enum_size_variance)]
+#![warn(variant_size_differences)]
 #![allow(dead_code)]
 
 enum Enum1 { }
@@ -21,8 +21,8 @@ enum Enum3 { D(isize), E, F }
 
 enum Enum4 { H(isize), I(isize), J }
 
-enum Enum5 { //~ ERROR three times larger
-    L(isize, isize, isize, isize), //~ NOTE this variant is the largest
+enum Enum5 {
+    L(isize, isize, isize, isize), //~ WARNING three times larger
     M(isize),
     N
 }
@@ -33,7 +33,7 @@ enum Enum6<T, U> {
     Q(isize)
 }
 
-#[allow(enum_size_variance)]
+#[allow(variant_size_differences)]
 enum Enum7 {
     R(isize, isize, isize, isize),
     S(isize),
index d88a5f12e303dd17ce017b1accfe197f7437080b..27bcab43229c52ade34099809fdd634f1d698917 100644 (file)
@@ -15,9 +15,6 @@
 // sanity in that we generate an if-else chain giving the correct
 // results.
 
-#![feature(rustc_attrs)]
-
-#[rustc_mir]
 fn foo(x: bool, y: bool) -> u32 {
     match (x, y) {
         (false, _) => 0,
index c2916ccd75b8e4a58e8d926714b02b35b608c60f..7d49bd25309f5ad2b0479331265e36e834527413 100644 (file)
@@ -34,7 +34,7 @@ fn main() {
 }
 
 fn parent() {
-    let file = File::open("Makefile").unwrap();
+    let file = File::open(file!()).unwrap();
     let tcp1 = TcpListener::bind("127.0.0.1:0").unwrap();
     let tcp2 = tcp1.try_clone().unwrap();
     let addr = tcp1.local_addr().unwrap();
diff --git a/src/test/run-pass/imports.rs b/src/test/run-pass/imports.rs
new file mode 100644 (file)
index 0000000..9851dfe
--- /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.
+
+// ignore-pretty : (#23623) problems when ending with // comments
+
+#![feature(item_like_imports)]
+#![allow(unused)]
+
+// Like other items, private imports can be imported and used non-lexically in paths.
+mod a {
+    use a as foo;
+    use self::foo::foo as bar;
+
+    mod b {
+        use super::bar;
+    }
+}
+
+mod foo { pub fn f() {} }
+mod bar { pub fn f() {} }
+
+pub fn f() -> bool { true }
+
+// Items and explicit imports shadow globs.
+fn g() {
+    use foo::*;
+    use bar::*;
+    fn f() -> bool { true }
+    let _: bool = f();
+}
+
+fn h() {
+    use foo::*;
+    use bar::*;
+    use f;
+    let _: bool = f();
+}
+
+// Here, there appears to be shadowing but isn't because of namespaces.
+mod b {
+    use foo::*; // This imports `f` in the value namespace.
+    use super::b as f; // This imports `f` only in the type namespace,
+    fn test() { self::f(); } // so the glob isn't shadowed.
+}
+
+// Here, there is shadowing in one namespace, but not the other.
+mod c {
+    mod test {
+        pub fn f() {}
+        pub mod f {}
+    }
+    use self::test::*; // This glob-imports `f` in both namespaces.
+    mod f { pub fn f() {} } // This shadows the glob only in the value namespace.
+
+    fn test() {
+        self::f(); // Check that the glob-imported value isn't shadowed.
+        self::f::f(); // Check that the glob-imported module is shadowed.
+    }
+}
+
+// Unused names can be ambiguous.
+mod d {
+    pub use foo::*; // This imports `f` in the value namespace.
+    pub use bar::*; // This also imports `f` in the value namespace.
+}
+
+mod e {
+    pub use d::*; // n.b. Since `e::f` is not used, this is not considered to be a use of `d::f`.
+}
+
+fn main() {}
index eb482b3230a439ec38f580c7dc0f10903cf0c602..ea42b59f1f2b84045a973bce147501e596d31056 100644 (file)
@@ -55,15 +55,6 @@ pub fn main() {
         // compiler is hidden.
         rusti::move_val_init(&mut y, x);
 
-        // In particular, it may be tracked via a drop-flag embedded
-        // in the value, or via a null pointer, or via
-        // mem::POST_DROP_USIZE, or (most preferably) via a
-        // stack-local drop flag.
-        //
-        // (This test used to build-in knowledge of how it was
-        // tracked, and check that the underlying stack slot had been
-        // set to `mem::POST_DROP_USIZE`.)
-
         // But what we *can* observe is how many times the destructor
         // for `D` is invoked, and what the last value we saw was
         // during such a destructor call. We do so after the end of
index 3dc96ecde1c0769b84d32dadea417104537fd485..a521e5d4b6c34b04488b4f2db023e05655702167 100644 (file)
@@ -8,12 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
-#![feature(unsafe_no_drop_flag)]
-
 static mut drop_count: usize = 0;
 
-#[unsafe_no_drop_flag]
 struct Foo {
     dropped: bool
 }
diff --git a/src/test/run-pass/issue-12033.rs b/src/test/run-pass/issue-12033.rs
new file mode 100644 (file)
index 0000000..5e1d82c
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cell::RefCell;
+
+fn main() {
+    let x = RefCell::new(0);
+    if *x.borrow() == 0 {} else {}
+}
diff --git a/src/test/run-pass/issue-14875.rs b/src/test/run-pass/issue-14875.rs
new file mode 100644 (file)
index 0000000..ad19a9b
--- /dev/null
@@ -0,0 +1,43 @@
+// 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.
+
+// Check that values are not leaked when a dtor panics (#14875)
+
+use std::panic::{self, UnwindSafe};
+
+struct SetInnerOnDrop<'a>(&'a mut bool);
+
+impl<'a> UnwindSafe for SetInnerOnDrop<'a> {}
+
+impl<'a> Drop for SetInnerOnDrop<'a> {
+    fn drop(&mut self) {
+        *self.0 = true;
+    }
+}
+
+struct PanicOnDrop;
+impl Drop for PanicOnDrop {
+    fn drop(&mut self) {
+        panic!("test panic");
+    }
+}
+
+
+fn main() {
+    let mut set_on_drop = false;
+    {
+        let set_inner_on_drop = SetInnerOnDrop(&mut set_on_drop);
+        let _ = panic::catch_unwind(|| {
+            let _set_inner_on_drop = set_inner_on_drop;
+            let _panic_on_drop = PanicOnDrop;
+        });
+    }
+    assert!(set_on_drop);
+}
index e596bee8bfe9fc7afc4936c33c7537873306aabb..e1b94179764bf8fbe6bfa3ad3516e603955ad1c9 100644 (file)
@@ -9,9 +9,8 @@
 // except according to those terms.
 
 
-#![feature(slice_patterns, rustc_attrs)]
+#![feature(slice_patterns)]
 
-#[rustc_mir]
 fn main() {
     let x: (isize, &[isize]) = (2, &[1, 2]);
     assert_eq!(match x {
index 0fd4b4394dc271ab32e2df0e7b40deecbde298d7..7ff9ae996f525b2f753b4956a724ad18e6556cdb 100644 (file)
@@ -8,6 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![allow(non_snake_case)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
 #[derive(Copy, Clone)]
 enum Foo {
     Bar,
index 8deb2e244ae08111d2ec4f432698f70087ae8dde..d1fb75377050d680a50b1aaf359cff98ee8510da 100644 (file)
@@ -22,6 +22,6 @@ fn x(&mut self) {
 
 fn main() {
     let mut foo = Foo { a: 137 };
-    FUNC(&mut foo); //~ ERROR bad
+    FUNC(&mut foo);
     assert_eq!(foo.a, 5);
 }
index 242528dcb1474e89fc13faf87d4c70c2c6d91599..e223d3412e04929b7a280dbfc77687349bd63369 100644 (file)
@@ -22,7 +22,6 @@ struct E {
 
 impl A for E {
   fn b<F,G>(&self, _x: F) -> F { panic!() }
-  //~^ ERROR in method `b`, type parameter 0 has 1 bound, but
 }
 
 pub fn main() {}
diff --git a/src/test/run-pass/issue-26251.rs b/src/test/run-pass/issue-26251.rs
new file mode 100644 (file)
index 0000000..1e77d54
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    let x = 'a';
+
+    let y = match x {
+        'a'...'b' if false => "one",
+        'a' => "two",
+        'a'...'b' => "three",
+        _ => panic!("what?"),
+    };
+
+    assert_eq!(y, "two");
+}
index dde1d3bfe938939333ab5098b0d9a34ece5c6582..e010b162cc4068f75c638e137886748eb5c6a703 100644 (file)
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
 macro_rules! piece(
     ($piece:pat) => ($piece);
 );
index 5587f68bd18544465c2aa5c8fb8dd7929ed233f4..b0fd0e148c8c26f690e55faa7f01ae419a67f88a 100644 (file)
@@ -26,11 +26,11 @@ fn drop(&mut self) {}
 #[cfg(target_pointer_width = "64")]
 pub fn main() {
     assert_eq!(mem::size_of::<Cat>(), 8 as usize);
-    assert_eq!(mem::size_of::<Kitty>(), 16 as usize);
+    assert_eq!(mem::size_of::<Kitty>(), 8 as usize);
 }
 
 #[cfg(target_pointer_width = "32")]
 pub fn main() {
     assert_eq!(mem::size_of::<Cat>(), 4 as usize);
-    assert_eq!(mem::size_of::<Kitty>(), 8 as usize);
+    assert_eq!(mem::size_of::<Kitty>(), 4 as usize);
 }
index a905727afff4fcfd22d6ae1afd75b6880a45bceb..a70c2b3ae1b7ba03dea6fb1220116a9a63f885e7 100644 (file)
@@ -9,19 +9,23 @@
 // except according to those terms.
 
 // ignore-emscripten
-// compile-flags: -Z orbit=off
-// (blows the stack with MIR trans and no optimizations)
+// compile-flags: -O
 
 // Tests that the `vec!` macro does not overflow the stack when it is
 // given data larger than the stack.
 
+// FIXME(eddyb) Improve unoptimized codegen to avoid the temporary,
+// and thus run successfully even when compiled at -C opt-level=0.
+
 const LEN: usize = 1 << 15;
 
 use std::thread::Builder;
 
 fn main() {
     assert!(Builder::new().stack_size(LEN / 2).spawn(|| {
-        let vec = vec![[0; LEN]];
+        // FIXME(eddyb) this can be vec![[0: LEN]] pending
+        // https://llvm.org/bugs/show_bug.cgi?id=28987
+        let vec = vec![unsafe { std::mem::zeroed::<[u8; LEN]>() }];
         assert_eq!(vec.len(), 1);
     }).unwrap().join().is_ok());
 }
index ea49cf3e7bedb66cd0069980e7cd6bb4e009fe41..b7ff63b75ce88df7cc2c4f9490f396951a60dc18 100644 (file)
@@ -8,19 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
-#[rustc_mir]
 fn const_mir() -> f32 { 9007199791611905.0 }
 
-#[rustc_no_mir]
-fn const_old() -> f32 { 9007199791611905.0 }
-
 fn main() {
     let original = "9007199791611905.0"; // (1<<53)+(1<<29)+1
     let expected = "9007200000000000";
 
     assert_eq!(const_mir().to_string(), expected);
-    assert_eq!(const_old().to_string(), expected);
     assert_eq!(original.parse::<f32>().unwrap().to_string(), expected);
 }
index a4b85bc7a091d89f3bb6fc71ba0482c7d2a67898..d30e88b3968c7ab242d22800ff86fee7e82ff377 100644 (file)
@@ -24,17 +24,14 @@ trait Foo {
 
 struct Bar<T: ?Sized>(T);
 
-#[rustc_mir]
 fn unsize_fat_ptr<'a>(x: &'a Bar<Foo + Send + 'a>) -> &'a Bar<Foo + 'a> {
     x
 }
 
-#[rustc_mir]
 fn unsize_nested_fat_ptr(x: Arc<Foo + Send>) -> Arc<Foo> {
     x
 }
 
-#[rustc_mir]
 fn main() {
     let x: Box<Bar<Foo + Send>> = Box::new(Bar([1,2]));
     assert_eq!(unsize_fat_ptr(&*x).0.get(), [1, 2]);
diff --git a/src/test/run-pass/issue-33687.rs b/src/test/run-pass/issue-33687.rs
new file mode 100644 (file)
index 0000000..59badca
--- /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.
+
+#![feature(unboxed_closures)]
+#![feature(fn_traits)]
+
+struct Test;
+
+impl FnOnce<(u32, u32)> for Test {
+    type Output = u32;
+
+    extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 {
+        a + b
+    }
+}
+
+fn main() {
+    assert_eq!(Test(1u32, 2u32), 3u32);
+}
diff --git a/src/test/run-pass/issue-34053.rs b/src/test/run-pass/issue-34053.rs
new file mode 100644 (file)
index 0000000..7f8a494
--- /dev/null
@@ -0,0 +1,23 @@
+// 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(drop_types_in_const)]
+
+struct A(i32);
+
+impl Drop for A {
+    fn drop(&mut self) {}
+}
+
+static FOO: A = A(123);
+
+fn main() {
+    println!("{}", &FOO.0);
+}
diff --git a/src/test/run-pass/issue-35423.rs b/src/test/run-pass/issue-35423.rs
new file mode 100644 (file)
index 0000000..35d0c30
--- /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.
+
+fn main () {
+    let x = 4;
+    match x {
+        ref r if *r < 0 => println!("got negative num {} < 0", r),
+        e @ 1 ... 100 => println!("got number within range [1,100] {}", e),
+        _ => println!("no"),
+    }
+}
diff --git a/src/test/run-pass/issue-35815.rs b/src/test/run-pass/issue-35815.rs
new file mode 100644 (file)
index 0000000..6195429
--- /dev/null
@@ -0,0 +1,23 @@
+// 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;
+
+struct Foo<T: ?Sized> {
+    a: i64,
+    b: bool,
+    c: T,
+}
+
+fn main() {
+    let foo: &Foo<i32> = &Foo { a: 1, b: false, c: 2i32 };
+    let foo_unsized: &Foo<Send> = foo;
+    assert_eq!(mem::size_of_val(foo), mem::size_of_val(foo_unsized));
+}
diff --git a/src/test/run-pass/issue-36023.rs b/src/test/run-pass/issue-36023.rs
new file mode 100644 (file)
index 0000000..53a8a40
--- /dev/null
@@ -0,0 +1,34 @@
+// 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.
+
+// min-llvm-version 3.9
+
+use std::ops::Deref;
+
+fn main() {
+    if env_var("FOOBAR").as_ref().map(Deref::deref).ok() == Some("yes") {
+        panic!()
+    }
+
+    let env_home: Result<String, ()> = Ok("foo-bar-baz".to_string());
+    let env_home = env_home.as_ref().map(Deref::deref).ok();
+
+    if env_home == Some("") { panic!() }
+}
+
+#[inline(never)]
+fn env_var(s: &str) -> Result<String, VarError> {
+    Err(VarError::NotPresent)
+}
+
+pub enum VarError {
+    NotPresent,
+    NotUnicode(String),
+}
diff --git a/src/test/run-pass/issue-36139-normalize-closure-sig.rs b/src/test/run-pass/issue-36139-normalize-closure-sig.rs
new file mode 100644 (file)
index 0000000..adde0ed
--- /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.
+
+// Previously the closure's argument would be inferred to
+// <S as ITrait<'a>>::Item, causing an error in MIR type
+// checking
+
+trait ITrait<'a> {type Item;}
+
+struct S {}
+
+impl<'a> ITrait<'a> for S { type Item = &'a mut usize; }
+
+fn m<T, I, F>(_: F)
+    where I: for<'a> ITrait<'a>,
+          F: for<'a> FnMut(<I as ITrait<'a>>::Item) { }
+
+
+fn main() {
+    m::<usize,S,_>(|x| { *x += 1; });
+}
index 0008825226ba0161fdcd88b4c92e457c42331ec6..badc013cd621f6297af82991af69264dc35b0073 100644 (file)
@@ -11,7 +11,6 @@
 
 #![feature(advanced_slice_patterns)]
 #![feature(slice_patterns)]
-#![feature(rustc_attrs)]
 
 use std::ops::Add;
 
@@ -22,7 +21,6 @@
     [a, b, b, a]
 }
 
-#[rustc_mir]
 fn main() {
     assert_eq!(foo([1, 2, 3]), (1, 3, 6));
 
index 6fc15478f7a55e0d23d9b1a4fca5b83f8afe0e05..76b44832a8a1651f1c1d06360a8495e1cfbb8466 100644 (file)
 
 // pretty-expanded FIXME #23616
 
-#![allow(unreachable_code)]
+#![allow(dead_code)]
 
 fn test() {
     let _v: isize;
     _v = 1;
     return;
-    _v = 2; //~ WARNING: unreachable statement
+    _v = 2;
 }
 
 pub fn main() {
index 010c1455210084b521a898b125e183d8d1f2f1cb..fa609593c24b631807873967526c5c30238b803e 100644 (file)
@@ -11,9 +11,7 @@
 
 #![feature(advanced_slice_patterns)]
 #![feature(slice_patterns)]
-#![feature(rustc_attrs)]
 
-#[rustc_mir]
 fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str {
     match (l1, l2) {
         (&[], &[]) => "both empty",
@@ -22,7 +20,6 @@ fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str {
     }
 }
 
-#[rustc_mir]
 fn match_vecs_cons<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str {
     match (l1, l2) {
         (&[], &[]) => "both empty",
@@ -31,7 +28,6 @@ fn match_vecs_cons<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str {
     }
 }
 
-#[rustc_mir]
 fn match_vecs_snoc<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str {
     match (l1, l2) {
         (&[], &[]) => "both empty",
@@ -40,7 +36,6 @@ fn match_vecs_snoc<'a, T>(l1: &'a [T], l2: &'a [T]) -> &'static str {
     }
 }
 
-#[rustc_mir]
 fn match_nested_vecs_cons<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'static str {
     match (l1, l2) {
         (Some(&[]), Ok(&[])) => "Some(empty), Ok(empty)",
@@ -51,7 +46,6 @@ fn match_nested_vecs_cons<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -
     }
 }
 
-#[rustc_mir]
 fn match_nested_vecs_snoc<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'static str {
     match (l1, l2) {
         (Some(&[]), Ok(&[])) => "Some(empty), Ok(empty)",
index 4526c40af84cf8d1fadb5847c0a26218a664ec4c..6b47721ab4b32779e372d8daa773e16aa5c5b237 100644 (file)
@@ -8,15 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
-#[repr(C, u32)]
+#[repr(C)]
 enum CEnum {
     Hello = 30,
     World = 60
 }
 
-#[rustc_mir]
 fn test1(c: CEnum) -> i32 {
   let c2 = CEnum::Hello;
   match (c, c2) {
@@ -40,7 +37,6 @@ impl Drop for Pakd {
     fn drop(&mut self) {}
 }
 
-#[rustc_mir]
 fn test2() -> Pakd {
     Pakd { a: 42, b: 42, c: 42, d: 42, e: () }
 }
@@ -48,18 +44,15 @@ fn test2() -> Pakd {
 #[derive(PartialEq, Debug)]
 struct TupleLike(u64, u32);
 
-#[rustc_mir]
 fn test3() -> TupleLike {
     TupleLike(42, 42)
 }
 
-#[rustc_mir]
 fn test4(x: fn(u64, u32) -> TupleLike) -> (TupleLike, TupleLike) {
     let y = TupleLike;
     (x(42, 84), y(42, 84))
 }
 
-#[rustc_mir]
 fn test5(x: fn(u32) -> Option<u32>) -> (Option<u32>, Option<u32>) {
     let y = Some;
     (x(42), y(42))
index b227be9c543b21d427b27343f7b12c631a6db86b..bc1013429aa59252aa3ddeb7ff1763b9b5a27b81 100644 (file)
@@ -10,9 +10,8 @@
 
 // Tests that the result of type ascription has adjustments applied
 
-#![feature(rustc_attrs, type_ascription)]
+#![feature(type_ascription)]
 
-#[rustc_mir]
 fn main() {
     let x = [1, 2, 3];
     // The RHS should coerce to &[i32]
index dcfa569a933e8835075b4a9f024ff64ce5756e09..bb90f25fce5f405200a6490a5152621bb7368812 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
 use std::mem;
 use std::ops::{
     AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign, MulAssign, RemAssign,
@@ -33,7 +31,6 @@ fn main() {
     main_mir();
 }
 
-#[rustc_mir]
 fn main_mir() {
     let mut x = Int(1);
 
@@ -92,91 +89,78 @@ fn main_mir() {
 }
 
 impl AddAssign for Int {
-    #[rustc_mir]
     fn add_assign(&mut self, rhs: Int) {
         self.0 += rhs.0;
     }
 }
 
 impl BitAndAssign for Int {
-    #[rustc_mir]
     fn bitand_assign(&mut self, rhs: Int) {
         self.0 &= rhs.0;
     }
 }
 
 impl BitOrAssign for Int {
-    #[rustc_mir]
     fn bitor_assign(&mut self, rhs: Int) {
         self.0 |= rhs.0;
     }
 }
 
 impl BitXorAssign for Int {
-    #[rustc_mir]
     fn bitxor_assign(&mut self, rhs: Int) {
         self.0 ^= rhs.0;
     }
 }
 
 impl DivAssign for Int {
-    #[rustc_mir]
     fn div_assign(&mut self, rhs: Int) {
         self.0 /= rhs.0;
     }
 }
 
 impl MulAssign for Int {
-    #[rustc_mir]
     fn mul_assign(&mut self, rhs: Int) {
         self.0 *= rhs.0;
     }
 }
 
 impl RemAssign for Int {
-    #[rustc_mir]
     fn rem_assign(&mut self, rhs: Int) {
         self.0 %= rhs.0;
     }
 }
 
 impl ShlAssign<u8> for Int {
-    #[rustc_mir]
     fn shl_assign(&mut self, rhs: u8) {
         self.0 <<= rhs;
     }
 }
 
 impl ShlAssign<u16> for Int {
-    #[rustc_mir]
     fn shl_assign(&mut self, rhs: u16) {
         self.0 <<= rhs;
     }
 }
 
 impl ShrAssign<u8> for Int {
-    #[rustc_mir]
     fn shr_assign(&mut self, rhs: u8) {
         self.0 >>= rhs;
     }
 }
 
 impl ShrAssign<u16> for Int {
-    #[rustc_mir]
     fn shr_assign(&mut self, rhs: u16) {
         self.0 >>= rhs;
     }
 }
 
 impl SubAssign for Int {
-    #[rustc_mir]
     fn sub_assign(&mut self, rhs: Int) {
         self.0 -= rhs.0;
     }
 }
 
 impl AddAssign<i32> for Slice {
-    #[rustc_mir]
     fn add_assign(&mut self, rhs: i32) {
         for lhs in &mut self.0 {
             *lhs += rhs;
index 81712e4569f06b288985fdb0a6590929e21eb8e7..f0032fee2835eff90350ccde03ae68622262fa2c 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
 use std::ops::{Deref, DerefMut};
 
 pub struct MyRef(u32);
@@ -24,12 +22,10 @@ fn deref_mut(&mut self) -> &mut u32 { &mut self.0 }
 }
 
 
-#[rustc_mir]
 fn deref(x: &MyRef) -> &u32 {
     x
 }
 
-#[rustc_mir]
 fn deref_mut(x: &mut MyRef) -> &mut u32 {
     x
 }
index 1d635e9f778df62aee4552f18f6c31626f579398..1c5134755d7aa1465eacbcf7939abdb52ee5d655 100644 (file)
@@ -8,9 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs, box_syntax)]
+#![feature(box_syntax)]
 
-#[rustc_mir]
 fn test() -> Box<i32> {
     box 42
 }
index ad24e39d4f93fb05e43ebfacdbd4288c76b50b75..b195ff63412af4dcc960fbf7869ad9e742cbdfb3 100644 (file)
@@ -8,9 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
-#[rustc_mir]
 fn test1(x: i8) -> i32 {
   match x {
     1...10 => 0,
@@ -21,7 +18,6 @@ fn test1(x: i8) -> i32 {
 const U: Option<i8> = Some(10);
 const S: &'static str = "hello";
 
-#[rustc_mir]
 fn test2(x: i8) -> i32 {
   match Some(x) {
     U => 0,
@@ -29,7 +25,6 @@ fn test2(x: i8) -> i32 {
   }
 }
 
-#[rustc_mir]
 fn test3(x: &'static str) -> i32 {
   match x {
     S => 0,
@@ -42,7 +37,6 @@ enum Opt<T> {
     None
 }
 
-#[rustc_mir]
 fn test4(x: u64) -> i32 {
   let opt = Opt::Some{ v: x };
   match opt {
index 08401c275a52cff5dbbba98d714feae9e86a67de..935d0e58985d7c683160a10dbc6c7614ed1e1dc1 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
 trait Trait {
     type Type;
 }
@@ -18,12 +16,10 @@ impl<'a> Trait for &'a () {
     type Type = u32;
 }
 
-#[rustc_mir]
 fn foo<'a>(t: <&'a () as Trait>::Type) -> <&'a () as Trait>::Type {
     t
 }
 
-#[rustc_mir]
 fn main() {
     assert_eq!(foo(4), 4);
 }
index 8a723967aff5f04ce6764f9cb121f127b741b181..311d5451eb6dd5012d56247e316072e19a6c1b82 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
 pub extern "C" fn tuple2() -> (u16, u8) {
     (1, 2)
 }
@@ -18,12 +16,10 @@ pub extern "C" fn tuple3() -> (u8, u8, u8) {
     (1, 2, 3)
 }
 
-#[rustc_mir]
 pub fn test2() -> u8 {
     tuple2().1
 }
 
-#[rustc_mir]
 pub fn test3() -> u8 {
     tuple3().2
 }
index 4d5c59276d7506a056c77915d6007cc65cd0b5c3..2be2854fac959cc582065264633a927c4c0b7a2e 100644 (file)
@@ -10,9 +10,6 @@
 
 // Tests the coercion casts are handled properly
 
-#![feature(rustc_attrs)]
-
-#[rustc_mir]
 fn main() {
     // This should produce only a reification of f,
     // not a fn -> fn cast as well
index 09dd52e30bef9ff7e1bd8c2db70ed5d410c64a6f..79d1cfde7cd581b831aa46417d12df41545e6347 100644 (file)
@@ -8,16 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs, coerce_unsized, unsize)]
+#![feature(coerce_unsized, unsize)]
 
 use std::ops::CoerceUnsized;
 use std::marker::Unsize;
 
-#[rustc_mir]
 fn identity_coercion(x: &(Fn(u32)->u32 + Send)) -> &Fn(u32)->u32 {
     x
 }
-#[rustc_mir]
 fn fn_coercions(f: &fn(u32) -> u32) ->
     (unsafe fn(u32) -> u32,
      &(Fn(u32) -> u32+Send))
@@ -25,7 +23,6 @@ fn fn_coercions(f: &fn(u32) -> u32) ->
     (*f, f)
 }
 
-#[rustc_mir]
 fn simple_array_coercion(x: &[u8; 3]) -> &[u8] { x }
 
 fn square(a: u32) -> u32 { a * a }
@@ -39,23 +36,19 @@ impl<'a, T: ?Sized+Unsize<U>, U: ?Sized>
 impl<'a, T: ?Sized+Unsize<U>, U: ?Sized>
     CoerceUnsized<TrivPtrWrapper<'a, U>> for TrivPtrWrapper<'a, T> {}
 
-#[rustc_mir]
 fn coerce_ptr_wrapper(p: PtrWrapper<[u8; 3]>) -> PtrWrapper<[u8]> {
     p
 }
 
-#[rustc_mir]
 fn coerce_triv_ptr_wrapper(p: TrivPtrWrapper<[u8; 3]>) -> TrivPtrWrapper<[u8]> {
     p
 }
 
-#[rustc_mir]
 fn coerce_fat_ptr_wrapper(p: PtrWrapper<Fn(u32) -> u32+Send>)
                           -> PtrWrapper<Fn(u32) -> u32> {
     p
 }
 
-#[rustc_mir]
 fn coerce_ptr_wrapper_poly<'a, T, Trait: ?Sized>(p: PtrWrapper<'a, T>)
                                                  -> PtrWrapper<'a, Trait>
     where PtrWrapper<'a, T>: CoerceUnsized<PtrWrapper<'a, Trait>>
index 0ce9e88ef3dbea7cc8d03c9f3212e0143d556b8a..696ff8a7e600fe16756eaa6ab6aab5924f3d6806 100644 (file)
@@ -7,7 +7,6 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
-#![feature(rustc_attrs)]
 
 #[derive(PartialEq, Debug)]
 struct Point {
@@ -23,7 +22,6 @@ struct Point {
 const TUPLE2: (&'static str, &'static str) = ("hello","world");
 const PAIR_NEWTYPE: (Newtype<i32>, Newtype<i32>) = (Newtype(42), Newtype(42));
 
-#[rustc_mir]
 fn mir() -> (Point, (i32, i32), (&'static str, &'static str), (Newtype<i32>, Newtype<i32>)) {
     let struct1 = STRUCT;
     let tuple1 = TUPLE1;
@@ -34,7 +32,6 @@ fn mir() -> (Point, (i32, i32), (&'static str, &'static str), (Newtype<i32>, New
 
 const NEWTYPE: Newtype<&'static str> = Newtype("foobar");
 
-#[rustc_mir]
 fn test_promoted_newtype_str_ref() {
     let x = &NEWTYPE;
     assert_eq!(x, &Newtype("foobar"));
diff --git a/src/test/run-pass/mir_cross_crate.rs b/src/test/run-pass/mir_cross_crate.rs
deleted file mode 100644 (file)
index cc239d9..0000000
+++ /dev/null
@@ -1,28 +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.
-
-// compile-flags: -Z orbit
-// Tests that -Z orbit affects functions from other crates.
-
-#![feature(unsafe_no_drop_flag)]
-
-#[unsafe_no_drop_flag]
-struct Foo;
-
-impl Drop for Foo {
-    fn drop(&mut self) {
-        panic!("MIR trans is not enabled for mem::forget");
-    }
-}
-
-fn main() {
-    let x = Foo;
-    std::mem::forget(x);
-}
diff --git a/src/test/run-pass/mir_early_return_scope.rs b/src/test/run-pass/mir_early_return_scope.rs
new file mode 100644 (file)
index 0000000..c27e573
--- /dev/null
@@ -0,0 +1,37 @@
+// 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.
+
+static mut DROP: bool = false;
+
+struct ConnWrap(Conn);
+impl ::std::ops::Deref for ConnWrap {
+    type Target=Conn;
+    fn deref(&self) -> &Conn { &self.0 }
+}
+
+struct Conn;
+impl Drop for  Conn {
+    fn drop(&mut self) { unsafe { DROP = true; } }
+}
+
+fn inner() {
+    let conn = &*match Some(ConnWrap(Conn)) {
+        Some(val) => val,
+        None => return,
+    };
+    return;
+}
+
+fn main() {
+    inner();
+    unsafe {
+        assert_eq!(DROP, true);
+    }
+}
index 9a4267bec925c88a500ddb7eb766ad8b61cc05a5..e5c9e3577d1c302a1cd6458eccf6019e01e1845b 100644 (file)
 
 // test that ordinary fat pointer operations work.
 
-#![feature(rustc_attrs)]
-
 struct Wrapper<T: ?Sized>(u32, T);
 
 struct FatPtrContainer<'a> {
     ptr: &'a [u8]
 }
 
-#[rustc_mir]
 fn fat_ptr_project(a: &Wrapper<[u8]>) -> &[u8] {
     &a.1
 }
 
-#[rustc_mir]
 fn fat_ptr_simple(a: &[u8]) -> &[u8] {
     a
 }
 
-#[rustc_mir]
 fn fat_ptr_via_local(a: &[u8]) -> &[u8] {
     let x = a;
     x
 }
 
-#[rustc_mir]
 fn fat_ptr_from_struct(s: FatPtrContainer) -> &[u8] {
     s.ptr
 }
 
-#[rustc_mir]
 fn fat_ptr_to_struct(a: &[u8]) -> FatPtrContainer {
     FatPtrContainer { ptr: a }
 }
 
-#[rustc_mir]
 fn fat_ptr_store_to<'a>(a: &'a [u8], b: &mut &'a [u8]) {
     *b = a;
 }
 
-#[rustc_mir]
 fn fat_ptr_constant() -> &'static str {
     "HELLO"
 }
index 3f79be0479391a3a0bc435f3cc1a35d474fcc661..64e68c78c3ca6b77a201049d6f131e6f354a7846 100644 (file)
@@ -27,7 +27,6 @@ fn drop(&mut self) {
     }
 }
 
-#[rustc_mir]
 fn fat_ptr_move_then_drop(a: Box<[DropMe]>) {
     let b = a;
 }
diff --git a/src/test/run-pass/mir_heavy_promoted.rs b/src/test/run-pass/mir_heavy_promoted.rs
new file mode 100644 (file)
index 0000000..9e03342
--- /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.
+
+const TEST_DATA: [u8; 32 * 1024 * 1024] = [42; 32 * 1024 * 1024];
+
+// Check that the promoted copy of TEST_DATA doesn't
+// leave an alloca from an unused temp behind, which,
+// without optimizations, can still blow the stack.
+fn main() {
+    println!("{}", TEST_DATA.len());
+}
index fb177ba7b2bb083aeb925d09f2a487f8bffd7ee0..487999e6ed62bbf0978e44f21347fa726d2d474a 100644 (file)
@@ -10,9 +10,6 @@
 
 // #30527 - We were not generating arms with guards in certain cases.
 
-#![feature(rustc_attrs)]
-
-#[rustc_mir]
 fn match_with_guard(x: Option<i8>) -> i8 {
     match x {
         Some(xyz) if xyz > 100 => 0,
index 0799ffebe69e51123350b9a9d4bd495ccd0dd036..ae719ac2800eeefb8a1e59983d494456ada45ce3 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(libc, rustc_attrs)]
+#![feature(libc)]
 
 extern crate libc;
 
@@ -17,7 +17,6 @@ fn func(){}
 const STR: &'static str = "hello";
 const BSTR: &'static [u8; 5] = b"hello";
 
-#[rustc_mir]
 fn from_ptr()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, *const ()) {
     let f = 1_usize as *const libc::FILE;
@@ -35,7 +34,6 @@ fn from_ptr()
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11)
 }
 
-#[rustc_mir]
 fn from_1()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
     let c1 = 1 as isize;
@@ -54,7 +52,6 @@ fn from_1()
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
-#[rustc_mir]
 fn from_1usize()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
     let c1 = 1_usize as isize;
@@ -73,7 +70,6 @@ fn from_1usize()
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
-#[rustc_mir]
 fn from_1isize()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
     let c1 = 1_isize as isize;
@@ -92,7 +88,6 @@ fn from_1isize()
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
-#[rustc_mir]
 fn from_1u8()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
     let c1 = 1_u8 as isize;
@@ -111,7 +106,6 @@ fn from_1u8()
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
-#[rustc_mir]
 fn from_1i8()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
     let c1 = 1_i8 as isize;
@@ -130,7 +124,6 @@ fn from_1i8()
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
-#[rustc_mir]
 fn from_1u16()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
     let c1 = 1_u16 as isize;
@@ -149,7 +142,6 @@ fn from_1u16()
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
-#[rustc_mir]
 fn from_1i16()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
     let c1 = 1_i16 as isize;
@@ -168,7 +160,6 @@ fn from_1i16()
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
-#[rustc_mir]
 fn from_1u32()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
     let c1 = 1_u32 as isize;
@@ -187,7 +178,6 @@ fn from_1u32()
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
-#[rustc_mir]
 fn from_1i32()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
     let c1 = 1_i32 as isize;
@@ -206,7 +196,6 @@ fn from_1i32()
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
-#[rustc_mir]
 fn from_1u64()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
     let c1 = 1_u64 as isize;
@@ -225,7 +214,6 @@ fn from_1u64()
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
-#[rustc_mir]
 fn from_1i64()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, *const libc::FILE) {
     let c1 = 1_i64 as isize;
@@ -244,7 +232,6 @@ fn from_1i64()
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
 }
 
-#[rustc_mir]
 fn from_bool()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64) {
     let c1 = true as isize;
@@ -260,7 +247,6 @@ fn from_bool()
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10)
 }
 
-#[rustc_mir]
 fn from_1f32()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64) {
     let c1 = 1.0_f32 as isize;
@@ -278,7 +264,6 @@ fn from_1f32()
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12)
 }
 
-#[rustc_mir]
 fn from_1f64()
 -> (isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64) {
     let c1 = 1.0f64 as isize;
@@ -296,7 +281,6 @@ fn from_1f64()
     (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12)
 }
 
-#[rustc_mir]
 fn other_casts()
 -> (*const u8, *const isize, *const u8, *const u8) {
     let c1 = func as *const u8;
index 04ac606a8a9a5458e0c4ec1c7ee70b7965271700..0db1e7b4563c18907e89fa840131fc583fb2d111 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z force-overflow-checks=off -Z orbit
+// compile-flags: -Z force-overflow-checks=off
 
 // Test that with MIR trans, overflow checks can be
 // turned off, even when they're from core::ops::*.
index a632f00d9ee5f5d1cbca7ccd5626fac7e99bde80..c9fd88f2fb3cfba15dac2d00005680145de62c5b 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
 // ignore-pretty : (#23623) problems when  ending with // comments
 
 // check raw fat pointer ops in mir
@@ -54,7 +52,6 @@ struct ComparisonResults {
     ne: true
 };
 
-#[rustc_mir]
 fn compare_su8(a: *const S<[u8]>, b: *const S<[u8]>) -> ComparisonResults {
     ComparisonResults {
         lt: a < b,
@@ -66,7 +63,6 @@ fn compare_su8(a: *const S<[u8]>, b: *const S<[u8]>) -> ComparisonResults {
     }
 }
 
-#[rustc_mir]
 fn compare_au8(a: *const [u8], b: *const [u8]) -> ComparisonResults {
     ComparisonResults {
         lt: a < b,
@@ -78,7 +74,6 @@ fn compare_au8(a: *const [u8], b: *const [u8]) -> ComparisonResults {
     }
 }
 
-#[rustc_mir]
 fn compare_foo<'a>(a: *const (Foo+'a), b: *const (Foo+'a)) -> ComparisonResults {
     ComparisonResults {
         lt: a < b,
@@ -90,7 +85,6 @@ fn compare_foo<'a>(a: *const (Foo+'a), b: *const (Foo+'a)) -> ComparisonResults
     }
 }
 
-#[rustc_mir]
 fn simple_eq<'a>(a: *const (Foo+'a), b: *const (Foo+'a)) -> bool {
     let result = a == b;
     result
index 67baf2f9c49c190df6e4c089e6828bf4ba64a161..df90fe2b7918d43740e740c9a2411be2769f66d4 100644 (file)
@@ -7,9 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
-#![feature(rustc_attrs)]
-// aux-build:mir_external_refs.rs
 
+// aux-build:mir_external_refs.rs
 
 extern crate mir_external_refs as ext;
 
@@ -78,128 +77,103 @@ fn parametric<T>(u: T) -> T {
     u
 }
 
-#[rustc_mir]
 fn t1() -> fn()->u8 {
     regular
 }
 
-#[rustc_mir]
 fn t2() -> fn(u8)->E {
     E::U
 }
 
-#[rustc_mir]
 fn t3() -> fn(u8)->S {
     S
 }
 
-#[rustc_mir]
 fn t4() -> fn()->u8 {
     S::hey
 }
 
-#[rustc_mir]
 fn t5() -> fn(&S)-> u8 {
     <S as X>::hoy
 }
 
 
-#[rustc_mir]
 fn t6() -> fn()->u8{
     ext::regular_fn
 }
 
-#[rustc_mir]
 fn t7() -> fn(u8)->ext::E {
     ext::E::U
 }
 
-#[rustc_mir]
 fn t8() -> fn(u8)->ext::S {
     ext::S
 }
 
-#[rustc_mir]
 fn t9() -> fn()->u8 {
     ext::S::hey
 }
 
-#[rustc_mir]
 fn t10() -> fn(&ext::S)->u8 {
     <ext::S as ext::X>::hoy
 }
 
-#[rustc_mir]
 fn t11() -> fn(u8)->u8 {
     parametric
 }
 
-#[rustc_mir]
 fn t12() -> u8 {
     C
 }
 
-#[rustc_mir]
 fn t13() -> [u8; 5] {
     C2
 }
 
-#[rustc_mir]
 fn t13_2() -> [u8; 3] {
     C3
 }
 
-#[rustc_mir]
 fn t14() -> fn()-> u8 {
     <S as X>::hoy2
 }
 
-#[rustc_mir]
 fn t15() -> fn(&S)-> u8 {
     S::hey2
 }
 
-#[rustc_mir]
 fn t16() -> fn(u32, u32)->u64 {
     F::f
 }
 
-#[rustc_mir]
 fn t17() -> fn(u32, u64)->u64 {
     F::f
 }
 
-#[rustc_mir]
 fn t18() -> fn(u64, u64)->u64 {
     F::f
 }
 
-#[rustc_mir]
 fn t19() -> fn(u64, u32)->u64 {
     F::f
 }
 
-#[rustc_mir]
 fn t20() -> fn(u64, u32)->(u64, u32) {
     <u32 as T<_, _>>::staticmeth
 }
 
-#[rustc_mir]
 fn t21() -> Unit {
     Unit
 }
 
-#[rustc_mir]
 fn t22() -> Option<u8> {
     None
 }
 
-#[rustc_mir]
 fn t23() -> (CEnum, CEnum) {
     (CEnum::A, CEnum::B)
 }
 
-#[rustc_mir]
 fn t24() -> fn(u8) -> S {
     C4
 }
index 8a0cb046b7a7d24371fd88ac15b163e496901122..639a585ae0013f60ecfbead13fdaa0d05530c617 100644 (file)
@@ -8,9 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
-#[rustc_mir]
 fn foo((x, y): (i8, i8)) {
 }
 
index 1f75369b94a8617ecd54c1f5a080049217038760..7b2514c27c8cba1b852ac0583848e57b6a265583 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
 use std::marker::PhantomData;
 
 pub trait DataBind {
@@ -26,7 +24,6 @@ pub struct Data {
     pub offsets: <Global<[u32; 2]> as DataBind>::Data,
 }
 
-#[rustc_mir]
 fn create_data() -> Data {
     let mut d = Data { offsets: [1, 2] };
     d.offsets[0] = 3;
index de83c1f5ee0cd137140ce632fdede069d16cd1eb..4865e955091f8eac6754f179fdf3da20296a9cc5 100644 (file)
@@ -8,9 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
-#[rustc_mir]
 fn test1(f: f32) -> bool {
     // test that we properly promote temporaries to allocas when a temporary is assigned to
     // multiple times (assignment is still happening once ∀ possible dataflows).
index e6ffb895825126d82cf3f2d49e30585df250f201..b7f247012ce129da0bb7f694698a792d31ff0bd5 100644 (file)
@@ -7,9 +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.
-#![feature(rustc_attrs)]
 
-#[rustc_mir]
 fn into_inner() -> [u64; 1024] {
     let mut x = 10 + 20;
     [x; 1024]
index 4aa686298e9eee9188befbeeaafcd502a9895ca6..c7133fb0c0e4923b5447bc4732fb3b8b72579dd2 100644 (file)
@@ -7,9 +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.
-#![feature(rustc_attrs)]
 
-#[rustc_mir]
 fn into_inner(x: u64) -> [u64; 1024] {
     [x; 2*4*8*16]
 }
index d8acfec25c4b5dc1b5ae3851ac8255ff30d0a78e..7d420bb86c6077968714deba37f25d3cede35739 100644 (file)
@@ -7,13 +7,11 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
-#![feature(rustc_attrs)]
 
 fn converging_fn() -> u64 {
     43
 }
 
-#[rustc_mir]
 fn mir() -> u64 {
     let x;
     loop {
index 7ff684a5ef392912b1ab64020316a4a9b24885de..d429c681bbe4ac317271c7c479416dba951e9556 100644 (file)
@@ -8,9 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs, fn_traits)]
+#![feature(fn_traits)]
 
-#[rustc_mir]
 fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) {
     // Test passing a number of arguments including a fat pointer.
     // Also returning via an out pointer
@@ -20,7 +19,6 @@ fn callee(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) {
     callee(a, b, c)
 }
 
-#[rustc_mir]
 fn test2(a: isize) -> isize {
     // Test passing a single argument.
     // Not using out pointer.
@@ -36,7 +34,6 @@ impl Foo {
     fn inherent_method(&self, a: isize) -> isize { a }
 }
 
-#[rustc_mir]
 fn test3(x: &Foo, a: isize) -> isize {
     // Test calling inherent method
     x.inherent_method(a)
@@ -47,19 +44,16 @@ fn extension_method(&self, a: isize) -> isize { a }
 }
 impl Bar for Foo {}
 
-#[rustc_mir]
 fn test4(x: &Foo, a: isize) -> isize {
     // Test calling extension method
     x.extension_method(a)
 }
 
-#[rustc_mir]
 fn test5(x: &Bar, a: isize) -> isize {
     // Test calling method on trait object
     x.extension_method(a)
 }
 
-#[rustc_mir]
 fn test6<T: Bar>(x: &T, a: isize) -> isize {
     // Test calling extension method on generic callee
     x.extension_method(a)
@@ -72,7 +66,6 @@ impl One for isize {
     fn one() -> isize { 1 }
 }
 
-#[rustc_mir]
 fn test7() -> isize {
     // Test calling trait static method
     <isize as One>::one()
@@ -83,7 +76,6 @@ impl Two {
     fn two() -> isize { 2 }
 }
 
-#[rustc_mir]
 fn test8() -> isize {
     // Test calling impl static method
     Two::two()
@@ -93,24 +85,20 @@ fn test8() -> isize {
     x + y.0 * y.1
 }
 
-#[rustc_mir]
 fn test9() -> u32 {
     simple_extern(41, (42, 43))
 }
 
-#[rustc_mir]
 fn test_closure<F>(f: &F, x: i32, y: i32) -> i32
     where F: Fn(i32, i32) -> i32
 {
     f(x, y)
 }
 
-#[rustc_mir]
 fn test_fn_object(f: &Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 {
     f(x, y)
 }
 
-#[rustc_mir]
 fn test_fn_impl(f: &&Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 {
     // This call goes through the Fn implementation for &Fn provided in
     // core::ops::impls. It expands to a static Fn::call() that calls the
@@ -118,28 +106,24 @@ fn test_fn_impl(f: &&Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 {
     f(x, y)
 }
 
-#[rustc_mir]
 fn test_fn_direct_call<F>(f: &F, x: i32, y: i32) -> i32
     where F: Fn(i32, i32) -> i32
 {
     f.call((x, y))
 }
 
-#[rustc_mir]
 fn test_fn_const_call<F>(f: &F) -> i32
     where F: Fn(i32, i32) -> i32
 {
     f.call((100, -1))
 }
 
-#[rustc_mir]
 fn test_fn_nil_call<F>(f: &F) -> i32
     where F: Fn() -> i32
 {
     f()
 }
 
-#[rustc_mir]
 fn test_fn_transmute_zst(x: ()) -> [(); 1] {
     fn id<T>(x: T) -> T {x}
 
@@ -148,30 +132,24 @@ fn id<T>(x: T) -> T {x}
     })
 }
 
-#[rustc_mir]
 fn test_fn_ignored_pair() -> ((), ()) {
     ((), ())
 }
 
-#[rustc_mir]
 fn test_fn_ignored_pair_0() {
     test_fn_ignored_pair().0
 }
 
-#[rustc_mir]
 fn id<T>(x: T) -> T { x }
 
-#[rustc_mir]
 fn ignored_pair_named() -> (Foo, Foo) {
     (Foo, Foo)
 }
 
-#[rustc_mir]
 fn test_fn_ignored_pair_named() -> (Foo, Foo) {
     id(ignored_pair_named())
 }
 
-#[rustc_mir]
 fn test_fn_nested_pair(x: &((f32, f32), u32)) -> (f32, f32) {
     let y = *x;
     let z = y.0;
index 7f711b2758dc7f5b6dde3df1fd7b393fee32c681..4e06738da4fd5e5a1d2b63591a393f04a9ef34c7 100644 (file)
@@ -8,14 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
 #[link(name = "rust_test_helpers")]
 extern {
     fn rust_interesting_average(_: i64, ...) -> f64;
 }
 
-#[rustc_mir]
 fn test<T, U>(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 {
     unsafe {
         rust_interesting_average(6, a, a as f64,
index 320f40175926dfc2e4ed233726648ae6c356ddb8..f6fe19c43097aed253c460c77715be4d1f799961 100644 (file)
@@ -29,7 +29,6 @@ impl<A, B> Foo<A, B>
 where A: Iterator, B: Iterator<Item=A::Item>
 {
     // This is the function we care about
-    #[rustc_mir]
     fn next(&mut self) -> Option<A::Item> {
         match self.state {
             State::Both => match self.a.next() {
index 9a06ab78e73b45efd2023a2c450c372ffca8c1e7..8474e841e01ad91d794f285142d6ee38b6eb54e8 100644 (file)
@@ -10,9 +10,6 @@
 
 // A simple spike test for MIR version of trans.
 
-#![feature(rustc_attrs)]
-
-#[rustc_mir]
 fn sum(x: i32, y: i32) -> i32 {
     x + y
 }
index c32d9da724d05eab5bcd9a2be90b533412e0cbe7..b097bf46ad3708210eebf151ad60077439553971 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
 enum Abc {
     A(u8),
     B(i8),
@@ -17,7 +15,6 @@ enum Abc {
     D,
 }
 
-#[rustc_mir]
 fn foo(x: Abc) -> i32 {
     match x {
         Abc::C => 3,
@@ -27,7 +24,6 @@ fn foo(x: Abc) -> i32 {
     }
 }
 
-#[rustc_mir]
 fn foo2(x: Abc) -> bool {
     match x {
         Abc::D => true,
index edde5f3c895873d9386260484924409d736762bc..537734596a5214f42de7ba2b8b94cd5e8b486a2b 100644 (file)
@@ -8,9 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
-#[rustc_mir]
 pub fn foo(x: i8) -> i32 {
   match x {
     1 => 0,
index 8b07449b8fafd93e765e89f95a51dae30c349d7d..78cb9fb39d6a6cf28fc9bcb093abca0beffe2d91 100644 (file)
@@ -8,9 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
-#[rustc_mir]
 fn mir() -> (){
     let x = 1;
     let mut y = 0;
index a3ad343240918b0c522374362e508761925d6bcf..fc9e3d5e3b535d1a74faf62fb283dc3012bc3ce0 100644 (file)
@@ -8,11 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
-
 fn nil() {}
 
-#[rustc_mir]
 fn mir(){
     nil()
 }
diff --git a/src/test/run-pass/no-drop-flag-size.rs b/src/test/run-pass/no-drop-flag-size.rs
new file mode 100644 (file)
index 0000000..a606a8a
--- /dev/null
@@ -0,0 +1,23 @@
+// 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::size_of;
+
+struct Test<T> {
+    a: T
+}
+
+impl<T> Drop for Test<T> {
+    fn drop(&mut self) { }
+}
+
+pub fn main() {
+    assert_eq!(size_of::<isize>(), size_of::<Test<isize>>());
+}
diff --git a/src/test/run-pass/rfc1592-deprecated.rs b/src/test/run-pass/rfc1592-deprecated.rs
deleted file mode 100644 (file)
index 81bf025..0000000
+++ /dev/null
@@ -1,29 +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.
-
-use std::fmt;
-
-trait Foo {
-    fn foo(&self) -> (Self, Self);
-}
-
-impl<T: Copy> Foo for T {
-    fn foo(&self) -> (Self, Self) {
-        (*self, *self)
-    }
-}
-
-fn main() {
-    assert_eq!((11).foo(), (11, 11));
-
-    let junk: Box<fmt::Debug+Sized> = Box::new(42);
-    let f = format!("{:?}", junk);
-    assert_eq!(f, "42");
-}
diff --git a/src/test/run-pass/rfc1623.rs b/src/test/run-pass/rfc1623.rs
new file mode 100644 (file)
index 0000000..1745393
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+// very simple test for a 'static static with default lifetime
+static STATIC_STR: &str = "&'static str";
+const CONST_STR: &str = "&'static str";
+
+// this should be the same as without default:
+static EXPLICIT_STATIC_STR: &'static str = "&'static str";
+const EXPLICIT_CONST_STR: &'static str = "&'static str";
+
+// a function that elides to an unbound lifetime for both in- and output
+fn id_u8_slice(arg: &[u8]) -> &[u8] {
+    arg
+}
+
+// one with a function, argument elided
+static STATIC_SIMPLE_FN: &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]);
+const CONST_SIMPLE_FN: &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]);
+
+// this should be the same as without elision
+static STATIC_NON_ELIDED_fN: &for<'a> fn(&'a [u8]) -> &'a [u8] =
+    &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]);
+const CONST_NON_ELIDED_fN: &for<'a> fn(&'a [u8]) -> &'a [u8] =
+    &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]);
+
+// another function that elides, each to a different unbound lifetime
+fn multi_args(a: &u8, b: &u8, c: &u8) {}
+
+static STATIC_MULTI_FN: &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8));
+const CONST_MULTI_FN: &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8));
+
+struct Foo<'a> {
+    bools: &'a [bool],
+}
+
+static STATIC_FOO: Foo = Foo { bools: &[true, false] };
+const CONST_FOO: Foo = Foo { bools: &[true, false] };
+
+type Bar<'a> = Foo<'a>;
+
+static STATIC_BAR: Bar = Bar { bools: &[true, false] };
+const CONST_BAR: Bar = Bar { bools: &[true, false] };
+
+type Baz<'a> = fn(&'a [u8]) -> Option<u8>;
+
+fn baz(e: &[u8]) -> Option<u8> {
+    e.first().map(|x| *x)
+}
+
+static STATIC_BAZ: &Baz = &(baz as Baz);
+const CONST_BAZ: &Baz = &(baz as Baz);
+
+static BYTES: &[u8] = &[1, 2, 3];
+
+fn main() {
+    // make sure that the lifetime is actually elided (and not defaulted)
+    let x = &[1u8, 2, 3];
+    STATIC_SIMPLE_FN(x);
+    CONST_SIMPLE_FN(x);
+
+    STATIC_BAZ(BYTES); // neees static lifetime
+    CONST_BAZ(BYTES);
+
+    // make sure this works with different lifetimes
+    let a = &1;
+    {
+        let b = &2;
+        let c = &3;
+        CONST_MULTI_FN(a, b, c);
+    }
+}
diff --git a/src/test/run-pass/rfc1623.rs.bk b/src/test/run-pass/rfc1623.rs.bk
new file mode 100644 (file)
index 0000000..0915118
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+// very simple test for a 'static static with default lifetime
+static STATIC_STR : &str = "&'static str";
+const CONST_STR : &str = "&'static str";
+
+// this should be the same as without default:
+static EXPLICIT_STATIC_STR : &'static str = "&'static str";
+const EXPLICIT_CONST_STR : &'static str = "&'static str";
+
+// a function that elides to an unbound lifetime for both in- and output
+fn id_u8_slice(arg: &[u8]) -> &[u8] { arg }
+
+// one with a function, argument elided
+static STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] =
+        &(id_u8_slice as fn(&[u8]) -> &[u8]);
+const CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] =
+        &(id_u8_slice as fn(&[u8]) -> &[u8]);
+
+// this should be the same as without elision
+static STATIC_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] =
+        &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]);
+const CONST_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] =
+        &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]);
+
+// another function that elides, each to a different unbound lifetime
+fn multi_args(a: &u8, b: &u8, c: &u8) { }
+
+static STATIC_MULTI_FN : &fn(&u8, &u8, &u8) =
+        &(multi_args as fn(&u8, &u8, &u8));
+const CONST_MULTI_FN : &fn(&u8, &u8, &u8) =
+        &(multi_args as fn(&u8, &u8, &u8));
+
+struct Foo<'a> {
+    bools: &'a [bool]
+}
+
+static STATIC_FOO : Foo = Foo { bools: &[true, false] };
+const CONST_FOO : Foo = Foo { bools: &[true, false] };
+
+type Bar<'a> = Foo<'a>;
+
+static STATIC_BAR : Bar = Bar { bools: &[true, false] };
+const CONST_BAR : Bar = Bar { bools: &[true, false] };
+
+type Baz<'a> = fn(&'a [u8]) -> Option<u8>;
+
+fn baz(e: &[u8]) -> Option<u8> { e.first().map(|x| *x) }
+
+static STATIC_BAZ : &Baz = &(baz as Baz);
+const CONST_BAZ : &Baz = &(baz as Baz);
+
+static BYTES : &[u8] = &[1, 2, 3];
+
+fn main() {
+    // make sure that the lifetime is actually elided (and not defaulted)
+    let x = &[1u8, 2, 3];
+    STATIC_SIMPLE_FN(x);
+    CONST_SIMPLE_FN(x);
+
+    STATIC_BAZ(BYTES); // neees static lifetime
+    CONST_BAZ(BYTES);
+
+    // make sure this works with different lifetimes
+    let a = &1;
+    {
+        let b = &2;
+        let c = &3;
+        CONST_MULTI_FN(a, b, c);
+    }
+}
index c7759ca743bbb6e3669233f0fc75705b4af85624..8a2bbc83c424e3eb952b4a0e20a125379d92f01f 100644 (file)
@@ -18,7 +18,7 @@ pub fn main() {
     let args: Vec<String> = env::args().collect();
     if args.len() >= 2 && args[1] == "signal" {
         // Raise a segfault.
-        unsafe { *(0 as *mut isize) = 0; }
+        unsafe { *(1 as *mut isize) = 0; }
     } else {
         let status = Command::new(&args[0]).arg("signal").status().unwrap();
         assert!(status.code().is_none());
index a20dd3ef72a54cd831eebf714931095419dd00ad..2efd9333999b24ca0f83834b7be300b849cb7f19 100644 (file)
@@ -8,8 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(repr_simd, platform_intrinsics, concat_idents,
-           type_macros, test)]
+#![feature(repr_simd, platform_intrinsics, concat_idents, test)]
 #![allow(non_camel_case_types)]
 
 extern crate test;
diff --git a/src/test/run-pass/try-operator-custom.rs b/src/test/run-pass/try-operator-custom.rs
new file mode 100644 (file)
index 0000000..577d19a
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(question_mark, question_mark_carrier)]
+
+use std::ops::Carrier;
+
+enum MyResult<T, U> {
+    Awesome(T),
+    Terrible(U)
+}
+
+impl<U, V> Carrier for MyResult<U, V> {
+    type Success = U;
+    type Error = V;
+
+    fn from_success(u: U) -> MyResult<U, V> {
+        MyResult::Awesome(u)
+    }
+
+    fn from_error(e: V) -> MyResult<U, V> {
+        MyResult::Terrible(e)
+    }
+
+    fn translate<T>(self) -> T
+        where T: Carrier<Success=U, Error=V>
+    {
+        match self {
+            MyResult::Awesome(u) => T::from_success(u),
+            MyResult::Terrible(e) => T::from_error(e),
+        }
+    }
+}
+
+fn f(x: i32) -> Result<i32, String> {
+    if x == 0 {
+        Ok(42)
+    } else {
+        let y = g(x)?;
+        Ok(y)
+    }
+}
+
+fn g(x: i32) -> MyResult<i32, String> {
+    let _y = f(x - 1)?;
+    MyResult::Terrible("Hello".to_owned())
+}
+
+fn h() -> MyResult<i32, String> {
+    let a: Result<i32, &'static str> = Err("Hello");
+    let b = a?;
+    MyResult::Awesome(b)
+}
+
+fn i() -> MyResult<i32, String> {
+    let a: MyResult<i32, &'static str> = MyResult::Terrible("Hello");
+    let b = a?;
+    MyResult::Awesome(b)
+}
+
+fn main() {
+    assert!(f(0) == Ok(42));
+    assert!(f(10) == Err("Hello".to_owned()));
+    let _ = h();
+    let _ = i();
+}
index 803b0eae99e887f1ff72a0fdc86c8856354ab1e2..84c0983de80c83abfb580d9dedcd2b4f9122ff16 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(type_macros)]
-
 use std::ops::*;
 
 #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
index 22dfd507f7e2e6e0c2e65021b1a62f805f640e37..7d1045cf3f1a82e0950e2298044b30c4dfada22e 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(type_macros)]
-
 macro_rules! Tuple {
     { $A:ty,$B:ty } => { ($A, $B) }
 }
index 189c5cdb9b747f7aaf7c64c28f72a176455efd69..6448056fb11f4db1448b7ce57008c48c09890b9d 100644 (file)
@@ -9,14 +9,14 @@
 // except according to those terms.
 
 
-#![allow(unreachable_code)]
 #![allow(unused_variables)]
+#![allow(dead_code)]
 
 fn id(x: bool) -> bool { x }
 
 fn call_id() {
     let c = panic!();
-    id(c); //~ WARNING unreachable statement
+    id(c);
 }
 
 fn call_id_3() { id(return) && id(return); }
index 7a6129d311ee386e83a51ca4fb706ac2fa0809b5..ac80a4211ada627fbfc0c0a2eb50dfda3d31f570 100644 (file)
 
 #![feature(advanced_slice_patterns)]
 #![feature(slice_patterns)]
-#![feature(rustc_attrs)]
 
 use std::fmt::Debug;
 
-#[rustc_mir(graphviz="mir.gv")]
 fn foldl<T, U, F>(values: &[T],
                   initial: U,
                   mut function: F)
@@ -32,7 +30,6 @@ fn foldl<T, U, F>(values: &[T],
     }
 }
 
-#[rustc_mir]
 fn foldr<T, U, F>(values: &[T],
                   initial: U,
                   mut function: F)
index 1093bc7c18b867e6f6e817e32527df9e09d6b52d..eecc3e7afdbb45d0549903076547343060a974c9 100644 (file)
@@ -8,9 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(slice_patterns, rustc_attrs)]
+#![feature(slice_patterns)]
 
-#[rustc_mir]
 pub fn main() {
     let x = &[1, 2, 3, 4, 5];
     let x: &[isize] = &[1, 2, 3, 4, 5];
index 075709a63b5f5d2978947ea1062e189fc7440a6a..97006f54cd9551f07feb03256ae448f993202aae 100644 (file)
@@ -11,9 +11,7 @@
 
 #![feature(advanced_slice_patterns)]
 #![feature(slice_patterns)]
-#![feature(rustc_attrs)]
 
-#[rustc_mir]
 fn a() {
     let x = [1];
     match x {
@@ -23,7 +21,6 @@ fn a() {
     }
 }
 
-#[rustc_mir]
 fn b() {
     let x = [1, 2, 3];
     match x {
@@ -60,7 +57,6 @@ fn b() {
 }
 
 
-#[rustc_mir]
 fn b_slice() {
     let x : &[_] = &[1, 2, 3];
     match x {
@@ -100,7 +96,6 @@ fn b_slice() {
     }
 }
 
-#[rustc_mir]
 fn c() {
     let x = [1];
     match x {
@@ -109,7 +104,6 @@ fn c() {
     }
 }
 
-#[rustc_mir]
 fn d() {
     let x = [1, 2, 3];
     let branch = match x {
@@ -121,7 +115,6 @@ fn d() {
     assert_eq!(branch, 1);
 }
 
-#[rustc_mir]
 fn e() {
     let x: &[isize] = &[1, 2, 3];
     let a = match *x {
index 6084a0d07a114911f2e180062d159f3e42f11f6c..d123eb36a7d4d0d2a762b0ddf2dc733e68e6f6b9 100644 (file)
 
 
 #![feature(slice_patterns)]
-#![feature(rustc_attrs)]
 
 struct Foo {
     string: &'static str
 }
 
-#[rustc_mir]
 pub fn main() {
     let x = [
         Foo { string: "foo" },
index a663ae650c087574611c8156d098a3b5674abc22..18b6c372a5ec2a0ae0e93e437ec9eda5857bdad1 100644 (file)
@@ -8,15 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs, unsafe_no_drop_flag)]
-
-// ignore-pretty : (#23623) problems when  ending with // comments
-
 static mut destructions : isize = 3;
 
-#[rustc_no_mir] // FIXME #29855 MIR doesn't handle all drops correctly.
 pub fn foo() {
-    #[unsafe_no_drop_flag]
     struct Foo;
 
     impl Drop for Foo {
index 00f4aa98a3e062bf2694beca39bb2882f682f2d6..d399ef72976f1ae818c3f45a8980069970ada7ab 100644 (file)
@@ -8,10 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
 #![feature(slice_patterns)]
 
-#[rustc_mir]
 fn main() {
     let x = [(), ()];
 
index df40c01686dcc57698729a4b02ed836d152dea5f..12de76654512d3ee2cb3544376e9a13f14297fb9 100644 (file)
@@ -12,7 +12,7 @@
 // ignore-cross-compile
 // build-aux-docs
 
-// @has issue_26606_macro/macro.make_item!.html
+// @has issue_26606_macro/macro.make_item.html
 #[macro_use]
 extern crate issue_26606_macro;
 
index b052ad2da2fa9b496dbdc2f8f2dc25771728462f..9aeeb71707c905f4cbe3094751adbd480ee7c92e 100644 (file)
@@ -8,10 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// @has macros/macro.my_macro!.html //pre 'macro_rules! my_macro {'
+// @has macros/macro.my_macro.html //pre 'macro_rules! my_macro {'
 // @has - //pre '() => { ... };'
 // @has - //pre '($a:tt) => { ... };'
 // @has - //pre '($e:expr) => { ... };'
+// @has macros/macro.my_macro!.html
+// @has - //a 'macro.my_macro.html'
 #[macro_export]
 macro_rules! my_macro {
     () => [];
diff --git a/src/test/ui/codemap_tests/bad-format-args.rs b/src/test/ui/codemap_tests/bad-format-args.rs
new file mode 100644 (file)
index 0000000..de7bc88
--- /dev/null
@@ -0,0 +1,15 @@
+// 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() {
+    format!();
+    format!("" 1);
+    format!("", 1 1);
+}
diff --git a/src/test/ui/codemap_tests/bad-format-args.stderr b/src/test/ui/codemap_tests/bad-format-args.stderr
new file mode 100644 (file)
index 0000000..fab8e2c
--- /dev/null
@@ -0,0 +1,26 @@
+error: requires at least a format string argument
+  --> $DIR/bad-format-args.rs:12:5
+   |
+12 |     format!();
+   |     ^^^^^^^^^^
+   |
+   = note: this error originates in a macro from the standard library
+
+error: expected token: `,`
+  --> $DIR/bad-format-args.rs:13:5
+   |
+13 |     format!("" 1);
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: this error originates in a macro from the standard library
+
+error: expected token: `,`
+  --> $DIR/bad-format-args.rs:14:5
+   |
+14 |     format!("", 1 1);
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in a macro from the standard library
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/codemap_tests/issue-28308.rs b/src/test/ui/codemap_tests/issue-28308.rs
new file mode 100644 (file)
index 0000000..e3a4920
--- /dev/null
@@ -0,0 +1,13 @@
+// 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() {
+    assert!("foo");
+}
diff --git a/src/test/ui/codemap_tests/issue-28308.stderr b/src/test/ui/codemap_tests/issue-28308.stderr
new file mode 100644 (file)
index 0000000..0d51a3f
--- /dev/null
@@ -0,0 +1,10 @@
+error: cannot apply unary operator `!` to type `&'static str`
+  --> $DIR/issue-28308.rs:12:5
+   |
+12 |     assert!("foo");
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in a macro from the standard library
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/codemap_tests/repair_span_std_macros.rs b/src/test/ui/codemap_tests/repair_span_std_macros.rs
new file mode 100644 (file)
index 0000000..3abc91d
--- /dev/null
@@ -0,0 +1,13 @@
+// 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() {
+    let x = vec![];
+}
diff --git a/src/test/ui/codemap_tests/repair_span_std_macros.stderr b/src/test/ui/codemap_tests/repair_span_std_macros.stderr
new file mode 100644 (file)
index 0000000..1c9cbd6
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0282]: unable to infer enough type information about `_`
+  --> $DIR/repair_span_std_macros.rs:12:13
+   |
+12 |     let x = vec![];
+   |             ^^^^^^ cannot infer type for `_`
+   |
+   = note: type annotations or generic parameter binding required
+   = note: this error originates in a macro from the standard library
+
+error: aborting due to previous error
+
index aa42ae341c54542e20508839e372ce1690b5ff29..a748e13ecf102bf9207afbb3f409938f5549f278 100644 (file)
@@ -1,4 +1,4 @@
-error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́`
+error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, sysv64, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́`
   --> $DIR/unicode.rs:11:8
    |
 11 | extern "路濫狼á́́" fn foo() {}
diff --git a/src/test/ui/cross-crate-macro-backtrace/auxiliary/extern_macro_crate.rs b/src/test/ui/cross-crate-macro-backtrace/auxiliary/extern_macro_crate.rs
new file mode 100644 (file)
index 0000000..598e9f0
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "dylib"]
+
+pub fn print(_args: std::fmt::Arguments) {}
+
+#[macro_export]
+macro_rules! myprint {
+    ($($arg:tt)*) => (print(format_args!($($arg)*)));
+}
+
+#[macro_export]
+macro_rules! myprintln {
+    ($fmt:expr) => (myprint!(concat!($fmt, "\n")));
+}
diff --git a/src/test/ui/cross-crate-macro-backtrace/main.rs b/src/test/ui/cross-crate-macro-backtrace/main.rs
new file mode 100644 (file)
index 0000000..f8bb84a
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:extern_macro_crate.rs
+#[macro_use(myprintln, myprint)]
+extern crate extern_macro_crate;
+
+fn main() {
+    myprintln!("{}"); //~ ERROR in this macro
+}
diff --git a/src/test/ui/cross-crate-macro-backtrace/main.stderr b/src/test/ui/cross-crate-macro-backtrace/main.stderr
new file mode 100644 (file)
index 0000000..fceaa70
--- /dev/null
@@ -0,0 +1,10 @@
+error: invalid reference to argument `0` (no arguments given)
+  --> $DIR/main.rs:16:5
+   |
+16 |     myprintln!("{}"); //~ ERROR in this macro
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in a macro from the standard library
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.rs b/src/test/ui/lifetimes/borrowck-let-suggestion.rs
new file mode 100644 (file)
index 0000000..eeafaab
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn f() {
+    let x = [1].iter();
+}
+
+fn main() {
+    f();
+}
diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.stderr b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr
new file mode 100644 (file)
index 0000000..9160034
--- /dev/null
@@ -0,0 +1,14 @@
+error: borrowed value does not live long enough
+  --> $DIR/borrowck-let-suggestion.rs:12:13
+   |
+12 |     let x = [1].iter();
+   |             ^^^       - temporary value only lives until here
+   |             |
+   |             temporary value created here
+13 | }
+   | - temporary value needs to live until here
+   |
+   = note: consider using a `let` binding to increase its lifetime
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/macros/bad_hello.rs b/src/test/ui/macros/bad_hello.rs
new file mode 100644 (file)
index 0000000..a18771d
--- /dev/null
@@ -0,0 +1,13 @@
+// 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() {
+    println!(3 + 4);
+}
diff --git a/src/test/ui/macros/bad_hello.stderr b/src/test/ui/macros/bad_hello.stderr
new file mode 100644 (file)
index 0000000..bffb33f
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected a literal
+  --> $DIR/bad_hello.rs:12:14
+   |
+12 |     println!(3 + 4);
+   |              ^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.rs b/src/test/ui/macros/macro-backtrace-invalid-internals.rs
new file mode 100644 (file)
index 0000000..546e06b
--- /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.
+
+// Macros in statement vs expression position handle backtraces differently.
+
+macro_rules! fake_method_stmt {
+     () => {
+          1.fake()
+     }
+}
+
+macro_rules! fake_field_stmt {
+     () => {
+          1.fake
+     }
+}
+
+macro_rules! fake_anon_field_stmt {
+     () => {
+          (1).0
+     }
+}
+
+macro_rules! fake_method_expr {
+     () => {
+          1.fake()
+     }
+}
+
+macro_rules! fake_field_expr {
+     () => {
+          1.fake
+     }
+}
+
+macro_rules! fake_anon_field_expr {
+     () => {
+          (1).0
+     }
+}
+
+fn main() {
+    fake_method_stmt!();
+    fake_field_stmt!();
+    fake_anon_field_stmt!();
+
+    let _ = fake_method_expr!();
+    let _ = fake_field_expr!();
+    let _ = fake_anon_field_expr!();
+}
diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr
new file mode 100644 (file)
index 0000000..82000a5
--- /dev/null
@@ -0,0 +1,56 @@
+error: no method named `fake` found for type `{integer}` in the current scope
+  --> $DIR/macro-backtrace-invalid-internals.rs:15:13
+   |
+15 |           1.fake()
+   |             ^^^^
+...
+50 |     fake_method_stmt!();
+   |     -------------------- in this macro invocation
+
+error: attempted access of field `fake` on type `{integer}`, but no field with that name was found
+  --> $DIR/macro-backtrace-invalid-internals.rs:21:11
+   |
+21 |           1.fake
+   |           ^^^^^^
+...
+51 |     fake_field_stmt!();
+   |     ------------------- in this macro invocation
+
+error: attempted tuple index `0` on type `{integer}`, but the type was not a tuple or tuple struct
+  --> $DIR/macro-backtrace-invalid-internals.rs:27:11
+   |
+27 |           (1).0
+   |           ^^^^^
+...
+52 |     fake_anon_field_stmt!();
+   |     ------------------------ in this macro invocation
+
+error: no method named `fake` found for type `{integer}` in the current scope
+  --> $DIR/macro-backtrace-invalid-internals.rs:33:13
+   |
+33 |           1.fake()
+   |             ^^^^
+...
+54 |     let _ = fake_method_expr!();
+   |             ------------------- in this macro invocation
+
+error: attempted access of field `fake` on type `{integer}`, but no field with that name was found
+  --> $DIR/macro-backtrace-invalid-internals.rs:39:11
+   |
+39 |           1.fake
+   |           ^^^^^^
+...
+55 |     let _ = fake_field_expr!();
+   |             ------------------ in this macro invocation
+
+error: attempted tuple index `0` on type `{integer}`, but the type was not a tuple or tuple struct
+  --> $DIR/macro-backtrace-invalid-internals.rs:45:11
+   |
+45 |           (1).0
+   |           ^^^^^
+...
+56 |     let _ = fake_anon_field_expr!();
+   |             ----------------------- in this macro invocation
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/macros/macro-backtrace-nested.rs b/src/test/ui/macros/macro-backtrace-nested.rs
new file mode 100644 (file)
index 0000000..d8bf622
--- /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.
+
+// In expression position, but not statement position, when we expand a macro,
+// we replace the span of the expanded expression with that of the call site.
+
+macro_rules! nested_expr {
+    () => (fake)
+}
+
+macro_rules! call_nested_expr {
+    () => (nested_expr!())
+}
+
+macro_rules! call_nested_expr_sum {
+    () => { 1 + nested_expr!(); }
+}
+
+fn main() {
+    1 + call_nested_expr!();
+    call_nested_expr_sum!();
+}
diff --git a/src/test/ui/macros/macro-backtrace-nested.stderr b/src/test/ui/macros/macro-backtrace-nested.stderr
new file mode 100644 (file)
index 0000000..e452e8d
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0425]: unresolved name `fake`
+  --> $DIR/macro-backtrace-nested.rs:15:12
+   |
+15 |     () => (fake)
+   |            ^^^^
+...
+27 |     1 + call_nested_expr!();
+   |         ------------------- in this macro invocation
+
+error[E0425]: unresolved name `fake`
+  --> $DIR/macro-backtrace-nested.rs:15:12
+   |
+15 |     () => (fake)
+   |            ^^^^
+...
+28 |     call_nested_expr_sum!();
+   |     ------------------------ in this macro invocation
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/macros/macro-backtrace-println.rs b/src/test/ui/macros/macro-backtrace-println.rs
new file mode 100644 (file)
index 0000000..baf2769
--- /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.
+
+// The `format_args!` syntax extension issues errors before code expansion
+// has completed, but we still need a backtrace.
+
+// This test includes stripped-down versions of `print!` and `println!`,
+// because we can't otherwise verify the lines of the backtrace.
+
+fn print(_args: std::fmt::Arguments) {}
+
+macro_rules! myprint {
+    ($($arg:tt)*) => (print(format_args!($($arg)*)));
+}
+
+macro_rules! myprintln {
+    ($fmt:expr) => (myprint!(concat!($fmt, "\n")));
+}
+
+fn main() {
+    myprintln!("{}");
+}
diff --git a/src/test/ui/macros/macro-backtrace-println.stderr b/src/test/ui/macros/macro-backtrace-println.stderr
new file mode 100644 (file)
index 0000000..f21253b
--- /dev/null
@@ -0,0 +1,11 @@
+error: invalid reference to argument `0` (no arguments given)
+  --> $DIR/macro-backtrace-println.rs:24:30
+   |
+24 |     ($fmt:expr) => (myprint!(concat!($fmt, "/n")));
+   |                              ^^^^^^^^^^^^^^^^^^^
+...
+28 |     myprintln!("{}");
+   |     ----------------- in this macro invocation
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/mismatched_types/const-fn-in-trait.rs b/src/test/ui/mismatched_types/const-fn-in-trait.rs
new file mode 100644 (file)
index 0000000..5e44030
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// rustc-env:RUST_NEW_ERROR_FORMAT
+
+#![feature(const_fn)]
+
+trait Foo {
+    fn f() -> u32;
+    const fn g();
+}
+
+impl Foo for u32 {
+    const fn f() -> u32 { 22 }
+    fn g() {}
+}
+
+fn main() { }
diff --git a/src/test/ui/mismatched_types/const-fn-in-trait.stderr b/src/test/ui/mismatched_types/const-fn-in-trait.stderr
new file mode 100644 (file)
index 0000000..f7b7635
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0379]: trait fns cannot be declared const
+  --> $DIR/const-fn-in-trait.rs:17:5
+   |
+17 |     const fn g();
+   |     ^^^^^ trait fns cannot be const
+
+error[E0379]: trait fns cannot be declared const
+  --> $DIR/const-fn-in-trait.rs:21:5
+   |
+21 |     const fn f() -> u32 { 22 }
+   |     ^^^^^ trait fns cannot be const
+
+error: aborting due to 2 previous errors
+
index 13f23a5d01ac1aea63c45eddc76abd776f139b2b..5d07ee1648a3ecfffe90986405e78bec9e8abfb5 100644 (file)
@@ -3,14 +3,18 @@ error[E0308]: mismatched types
    |
 26 |                   $arr.len() * size_of($arr[0]));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize
-$DIR/issue-26480.rs:37:5: 37:19 note: in this expansion of write! (defined in $DIR/issue-26480.rs)
+...
+37 |     write!(hello);
+   |     -------------- in this macro invocation
 
 error: non-scalar cast: `{integer}` as `()`
   --> $DIR/issue-26480.rs:32:19
    |
 32 |     ($x:expr) => ($x as ())
    |                   ^^^^^^^^
-$DIR/issue-26480.rs:38:5: 38:14 note: in this expansion of cast! (defined in $DIR/issue-26480.rs)
+...
+38 |     cast!(2);
+   |     --------- in this macro invocation
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs
new file mode 100644 (file)
index 0000000..099c869
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// rustc-env:RUST_NEW_ERROR_FORMAT
+
+trait Foo {
+    fn foo(x: u16);
+    fn bar(&mut self, bar: &mut Bar);
+}
+
+struct Bar;
+
+impl Foo for Bar {
+    fn foo(x: i16) { }
+    fn bar(&mut self, bar: &Bar) { }
+}
+
+fn main() {
+}
+
diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
new file mode 100644 (file)
index 0000000..4a0ccc4
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0053]: method `foo` has an incompatible type for trait
+  --> $DIR/trait-impl-fn-incompatibility.rs:21:15
+   |
+14 |     fn foo(x: u16);
+   |               --- type in trait
+...
+21 |     fn foo(x: i16) { }
+   |               ^^^ expected u16, found i16
+
+error[E0053]: method `bar` has an incompatible type for trait
+  --> $DIR/trait-impl-fn-incompatibility.rs:22:28
+   |
+15 |     fn bar(&mut self, bar: &mut Bar);
+   |                            -------- type in trait
+...
+22 |     fn bar(&mut self, bar: &Bar) { }
+   |                            ^^^^ types differ in mutability
+   |
+   = note: expected type `fn(&mut Bar, &mut Bar)`
+   = note:    found type `fn(&mut Bar, &Bar)`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/span/issue-11925.rs b/src/test/ui/span/issue-11925.rs
new file mode 100644 (file)
index 0000000..7bea864
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(box_syntax, unboxed_closures)]
+
+fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+
+fn main() {
+    let r = {
+        let x: Box<_> = box 42;
+        let f = to_fn_once(move|| &x);
+        f()
+    };
+
+    drop(r);
+}
diff --git a/src/test/ui/span/issue-11925.stderr b/src/test/ui/span/issue-11925.stderr
new file mode 100644 (file)
index 0000000..3fedb28
--- /dev/null
@@ -0,0 +1,14 @@
+error: `x` does not live long enough
+  --> $DIR/issue-11925.rs:18:36
+   |
+18 |         let f = to_fn_once(move|| &x);
+   |                                    ^
+   |                                    |
+   |                                    does not live long enough
+   |                                    borrowed value only lives until here
+...
+23 | }
+   | - borrowed value needs to live until here
+
+error: aborting due to previous error
+
index 24c8b20fdf8d799f30724a0700ec244e3640d66e..755697806a00e579b852752221d23fd51281ca08 100644 (file)
@@ -80,3 +80,13 @@ name = "utf8-ranges"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[metadata]
+"checksum aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67077478f0a03952bed2e6786338d400d40c25e9836e08ad50af96607317fd03"
+"checksum env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aba65b63ffcc17ffacd6cf5aa843da7c5a25e3bd4bbe0b7def8b214e411250e5"
+"checksum libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "95ca44454e7cfe7f8a2095a41a10c79d96a177c0b1672cbf1a30d901a9c16ee5"
+"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
+"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
+"checksum mempool 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f997e65fe3eb7a6f8557a7a477de9ed5c511850c85363d13f7b0145b526ed36a"
+"checksum regex 0.1.62 (registry+https://github.com/rust-lang/crates.io-index)" = "22bdab319e36735729aa280752c9293b29ec0053a6810679d697515f80a986fe"
+"checksum regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "841591b1e05609a643e3b4d0045fce04f701daba7151ddcd3ad47b080693d5a9"
+"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
index 6090cb4f52725784789fb5904c7ffc850e334ef1..5d522736089ea4d2acf1340b99bf5a6cd6c23583 100644 (file)
@@ -152,6 +152,9 @@ pub struct Config {
     // Version of LLDB
     pub lldb_version: Option<String>,
 
+    // Version of LLVM
+    pub llvm_version: Option<String>,
+
     // Path to the android tools
     pub android_cross_path: PathBuf,
 
index af33d76be1b0db0f430b4dcc5a4ee774a2c0d08d..899a366a4bb7412b42ae3a09b1a69197c53ab410 100644 (file)
@@ -44,7 +44,9 @@ pub fn from_file(config: &Config, testfile: &Path) -> Self {
                 (config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) ||
                 (config.target != config.host &&
                  parse_name_directive(ln, "ignore-cross-compile")) ||
-                ignore_gdb(config, ln) || ignore_lldb(config, ln);
+                ignore_gdb(config, ln) ||
+                ignore_lldb(config, ln) ||
+                ignore_llvm(config, ln);
 
             props.should_fail = props.should_fail || parse_name_directive(ln, "should-fail");
         });
@@ -115,6 +117,24 @@ fn ignore_lldb(config: &Config, line: &str) -> bool {
                 false
             }
         }
+
+        fn ignore_llvm(config: &Config, line: &str) -> bool {
+            if let Some(ref actual_version) = config.llvm_version {
+                if line.contains("min-llvm-version") {
+                    let min_version = line.trim()
+                        .split(' ')
+                        .last()
+                        .expect("Malformed llvm version directive");
+                    // Ignore if actual version is smaller the minimum required
+                    // version
+                    &actual_version[..] < min_version
+                } else {
+                    false
+                }
+            } else {
+                false
+            }
+        }
     }
 }
 
index 90641b5c476d7bbd93412d4eeb878fa0f7295e52..4afeb3613319b025bb8291e5d03ce4cf622a8a7c 100644 (file)
@@ -99,6 +99,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
           optopt("", "host", "the host to build for", "HOST"),
           optopt("", "gdb-version", "the version of GDB used", "VERSION STRING"),
           optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING"),
+          optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING"),
           optopt("", "android-cross-path", "Android NDK standalone path", "PATH"),
           optopt("", "adb-path", "path to the android debugger", "PATH"),
           optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
@@ -170,6 +171,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
         host: opt_str2(matches.opt_str("host")),
         gdb_version: extract_gdb_version(matches.opt_str("gdb-version")),
         lldb_version: extract_lldb_version(matches.opt_str("lldb-version")),
+        llvm_version: matches.opt_str("llvm-version"),
         android_cross_path: opt_path(matches, "android-cross-path"),
         adb_path: opt_str2(matches.opt_str("adb-path")),
         adb_test_dir: format!("{}/{}",
index 0d081b267bb7084301f001f4a3f61861b8b7ddf3..228d6ada01dcc4d1dc3b2d98ac83e7ba44edf54a 100644 (file)
@@ -197,6 +197,11 @@ fn run_rpass_test(&self) {
             self.fatal_proc_rec("compilation failed!", &proc_res);
         }
 
+        let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
+        if !expected_errors.is_empty() {
+            self.check_expected_errors(expected_errors, &proc_res);
+        }
+
         let proc_res = self.exec_compiled_test();
 
         if !proc_res.status.success() {
@@ -992,7 +997,8 @@ fn check_forbid_output(&self,
     fn check_expected_errors(&self,
                              expected_errors: Vec<errors::Error>,
                              proc_res: &ProcRes) {
-        if proc_res.status.success() {
+        if proc_res.status.success() &&
+            expected_errors.iter().any(|x| x.kind == Some(ErrorKind::Error)) {
             self.fatal_proc_rec("process did not return an error status", proc_res);
         }
 
@@ -1320,6 +1326,7 @@ fn make_compile_args(&self,
         match self.config.mode {
             CompileFail |
             ParseFail |
+            RunPass |
             Incremental => {
                 // If we are extracting and matching errors in the new
                 // fashion, then you want JSON mode. Old-skool error
@@ -1350,7 +1357,6 @@ fn make_compile_args(&self,
                 args.push(dir_opt);
             }
             RunFail |
-            RunPass |
             RunPassValgrind |
             Pretty |
             DebugInfoGdb |
@@ -1970,7 +1976,10 @@ fn init_incremental_test(&self) {
         // runs.
         let incremental_dir = self.incremental_dir();
         if incremental_dir.exists() {
-            fs::remove_dir_all(&incremental_dir).unwrap();
+            // Canonicalizing the path will convert it to the //?/ format
+            // on Windows, which enables paths longer than 260 character
+            let canonicalized = incremental_dir.canonicalize().unwrap();
+            fs::remove_dir_all(canonicalized).unwrap();
         }
         fs::create_dir_all(&incremental_dir).unwrap();
 
@@ -2035,7 +2044,7 @@ fn run_incremental_test(&self) {
 
     /// Directory where incremental work products are stored.
     fn incremental_dir(&self) -> PathBuf {
-        self.output_base_name().with_extension("incremental")
+        self.output_base_name().with_extension("inc")
     }
 
     fn run_rmake_test(&self) {
index ed5fe081ffb2efed86a5225df5c15c0bdc56e660..d71df6d3f83a860b5d84432c9f05402fdb0eeab1 100644 (file)
@@ -42,3 +42,9 @@ dependencies = [
  "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[metadata]
+"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11"
+"checksum matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e"
+"checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f"
+"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172"
+"checksum url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afe9ec54bc4db14bc8744b7fed060d785ac756791450959b2248443319d5b119"
index 6014439fafcf9661cfe981a515bea5558f8c58a4..09c2d2510e31729cea5c5a9b842e795bc07370ce 100644 (file)
@@ -61,9 +61,9 @@ fn walk_item(item: &BookItem,
                  section,
                  item.title)?;
         if !item.children.is_empty() {
-            writeln!(out, "<ul class='section'>")?;
+            writeln!(out, "<ol class='section'>")?;
             let _ = walk_items(&item.children[..], section, current_page, out);
-            writeln!(out, "</ul>")?;
+            writeln!(out, "</ol>")?;
         }
         writeln!(out, "</li>")?;
 
@@ -71,9 +71,9 @@ fn walk_item(item: &BookItem,
     }
 
     writeln!(out, "<div id='toc' class='mobile-hidden'>")?;
-    writeln!(out, "<ul class='chapter'>")?;
+    writeln!(out, "<ol class='chapter'>")?;
     walk_items(&book.chapters[..], "", &current_page, out)?;
-    writeln!(out, "</ul>")?;
+    writeln!(out, "</ol>")?;
     writeln!(out, "</div>")?;
 
     Ok(())
index e91b8fb0967a82375043ae927362500b428f7cfe..876ae404bbaed54f6094d118017ae9b22cb11232 100644 (file)
@@ -24,6 +24,7 @@ pub fn check(_path: &Path, _bad: &mut bool) {}
 #[cfg(unix)]
 pub fn check(path: &Path, bad: &mut bool) {
     use std::fs;
+    use std::process::{Command, Stdio};
     use std::os::unix::prelude::*;
 
     super::walk(path,
@@ -37,8 +38,22 @@ pub fn check(path: &Path, bad: &mut bool) {
 
         let metadata = t!(fs::symlink_metadata(&file), &file);
         if metadata.mode() & 0o111 != 0 {
-            println!("binary checked into source: {}", file.display());
-            *bad = true;
+            let rel_path = file.strip_prefix(path).unwrap();
+            let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");
+            let ret_code = Command::new("git")
+                                        .arg("ls-files")
+                                        .arg(&git_friendly_path)
+                                        .current_dir(path)
+                                        .stdout(Stdio::null())
+                                        .stderr(Stdio::null())
+                                        .status()
+                                        .unwrap_or_else(|e| {
+                                            panic!("could not run git ls-files: {}", e);
+                                        });
+            if ret_code.success() {
+                println!("binary checked into source: {}", file.display());
+                *bad = true;
+            }
         }
     })
 }