]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #40166 - aidanhs:aphs-index-coerce, r=nikomatsakis
authorCorey Farwell <coreyf@rwell.org>
Thu, 2 Mar 2017 19:53:51 +0000 (14:53 -0500)
committerGitHub <noreply@github.com>
Thu, 2 Mar 2017 19:53:51 +0000 (14:53 -0500)
Allow types passed to [] to coerce, like .index()

Fixes #40085

Basically steals the relevant part of [check_argument_types](https://github.com/rust-lang/rust/blob/1.15.1/src/librustc_typeck/check/mod.rs#L2653-L2672).

478 files changed:
.travis.yml
COMPILER_TESTS.md [deleted file]
CONTRIBUTING.md
README.md
appveyor.yml
src/Cargo.lock
src/bootstrap/bin/rustc.rs
src/bootstrap/bootstrap.py
src/bootstrap/flags.rs
src/bootstrap/lib.rs
src/bootstrap/mk/Makefile.in
src/bootstrap/sanity.rs
src/ci/docker/android/Dockerfile [deleted file]
src/ci/docker/android/accept-licenses.sh [deleted file]
src/ci/docker/android/install-ndk.sh [deleted file]
src/ci/docker/android/install-sdk.sh [deleted file]
src/ci/docker/android/start-emulator.sh [deleted file]
src/ci/docker/arm-android/Dockerfile [new file with mode: 0644]
src/ci/docker/arm-android/accept-licenses.sh [new file with mode: 0755]
src/ci/docker/arm-android/install-ndk.sh [new file with mode: 0644]
src/ci/docker/arm-android/install-sdk.sh [new file with mode: 0644]
src/ci/docker/arm-android/start-emulator.sh [new file with mode: 0755]
src/ci/docker/armhf-gnu/Dockerfile
src/ci/docker/cross/Dockerfile
src/ci/docker/dist-android/Dockerfile [new file with mode: 0644]
src/ci/docker/dist-android/install-ndk.sh [new file with mode: 0644]
src/ci/docker/dist-arm-linux/Dockerfile
src/ci/docker/dist-armv7-aarch64-linux/Dockerfile
src/ci/docker/dist-freebsd/Dockerfile
src/ci/docker/dist-mips-linux/Dockerfile
src/ci/docker/dist-mips64-linux/Dockerfile
src/ci/docker/dist-powerpc-linux/Dockerfile
src/ci/docker/dist-powerpc64-linux/Dockerfile
src/ci/docker/dist-s390x-linux-netbsd/Dockerfile
src/ci/docker/dist-x86-linux/Dockerfile
src/ci/docker/emscripten/Dockerfile
src/ci/docker/i686-gnu-nopt/Dockerfile
src/ci/docker/i686-gnu/Dockerfile
src/ci/docker/linux-tested-targets/Dockerfile
src/ci/docker/linux-tested-targets/build-musl.sh
src/ci/docker/run.sh
src/ci/docker/x86_64-gnu-aux/Dockerfile
src/ci/docker/x86_64-gnu-debug/Dockerfile
src/ci/docker/x86_64-gnu-distcheck/Dockerfile
src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile
src/ci/docker/x86_64-gnu-incremental/Dockerfile
src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile
src/ci/docker/x86_64-gnu-nopt/Dockerfile
src/ci/docker/x86_64-gnu/Dockerfile
src/ci/run.sh
src/ci/shared.sh [new file with mode: 0644]
src/doc/book/src/concurrency.md
src/doc/book/src/const-and-static.md
src/doc/book/src/ffi.md
src/doc/book/src/functions.md
src/doc/book/src/getting-started.md
src/doc/book/src/guessing-game.md
src/doc/book/src/if-let.md
src/doc/book/src/lifetimes.md
src/doc/book/src/loops.md
src/doc/book/src/procedural-macros.md
src/doc/book/src/strings.md
src/doc/book/src/structs.md
src/doc/book/src/the-stack-and-the-heap.md
src/doc/nomicon/src/exception-safety.md
src/doc/nomicon/src/phantom-data.md
src/doc/reference/src/attributes.md
src/doc/reference/src/linkage.md
src/doc/unstable-book/src/SUMMARY.md
src/doc/unstable-book/src/abi-x86-interrupt.md [new file with mode: 0644]
src/libcollections/fmt.rs
src/libcollections/macros.rs
src/libcollections/range.rs
src/libcollections/string.rs
src/libcollections/vec.rs
src/libcollectionstest/btree/map.rs
src/libcollectionstest/lib.rs
src/libcollectionstest/vec.rs
src/libcompiler_builtins/build.rs
src/libcore/fmt/mod.rs
src/libcore/slice.rs
src/libcore/str/mod.rs
src/liblibc
src/libproc_macro/lib.rs
src/libproc_macro_plugin/qquote.rs
src/librustc/cfg/construct.rs
src/librustc/dep_graph/dep_node.rs
src/librustc/dep_graph/dep_tracking_map.rs
src/librustc/diagnostics.rs
src/librustc/hir/def.rs
src/librustc/hir/intravisit.rs
src/librustc/hir/lowering.rs
src/librustc/hir/map/mod.rs
src/librustc/hir/mod.rs
src/librustc/hir/print.rs
src/librustc/infer/error_reporting.rs [deleted file]
src/librustc/infer/error_reporting/mod.rs [new file with mode: 0644]
src/librustc/infer/error_reporting/note.rs [new file with mode: 0644]
src/librustc/infer/mod.rs
src/librustc/lib.rs
src/librustc/lint/builtin.rs
src/librustc/middle/astconv_util.rs [deleted file]
src/librustc/middle/const_val.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/intrinsicck.rs
src/librustc/middle/liveness.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/resolve_lifetime.rs
src/librustc/middle/stability.rs
src/librustc/mir/mod.rs
src/librustc/mir/tcx.rs
src/librustc/mir/transform.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/mod.rs
src/librustc/traits/object_safety.rs
src/librustc/traits/project.rs
src/librustc/traits/select.rs
src/librustc/traits/specialize/mod.rs
src/librustc/traits/specialize/specialization_graph.rs
src/librustc/traits/structural_impls.rs
src/librustc/traits/util.rs
src/librustc/ty/adjustment.rs
src/librustc/ty/contents.rs
src/librustc/ty/context.rs
src/librustc/ty/error.rs
src/librustc/ty/fast_reject.rs
src/librustc/ty/flags.rs
src/librustc/ty/fold.rs
src/librustc/ty/inhabitedness/mod.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/relate.rs
src/librustc/ty/structural_impls.rs
src/librustc/ty/sty.rs
src/librustc/ty/subst.rs
src/librustc/ty/trait_def.rs
src/librustc/ty/util.rs
src/librustc/ty/walk.rs
src/librustc/util/ppaux.rs
src/librustc_back/target/mod.rs
src/librustc_back/target/sparcv9_sun_solaris.rs [new file with mode: 0644]
src/librustc_borrowck/borrowck/check_loans.rs
src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
src/librustc_borrowck/borrowck/gather_loans/move_error.rs
src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs
src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
src/librustc_borrowck/borrowck/mir/gather_moves.rs
src/librustc_borrowck/borrowck/mir/mod.rs
src/librustc_const_eval/_match.rs
src/librustc_const_eval/check_match.rs
src/librustc_const_eval/diagnostics.rs
src/librustc_const_eval/eval.rs
src/librustc_const_eval/lib.rs
src/librustc_const_eval/pattern.rs
src/librustc_const_math/float.rs
src/librustc_const_math/int.rs
src/librustc_const_math/lib.rs
src/librustc_driver/driver.rs
src/librustc_driver/pretty.rs
src/librustc_driver/test.rs
src/librustc_incremental/calculate_svh/svh_visitor.rs
src/librustc_incremental/persist/data.rs
src/librustc_incremental/persist/dirty_clean.rs
src/librustc_incremental/persist/load.rs
src/librustc_incremental/persist/preds/mod.rs
src/librustc_incremental/persist/save.rs
src/librustc_lint/bad_style.rs
src/librustc_lint/builtin.rs
src/librustc_lint/lib.rs
src/librustc_lint/types.rs
src/librustc_llvm/ffi.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/cstore.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/lib.rs
src/librustc_metadata/schema.rs
src/librustc_mir/build/expr/as_lvalue.rs
src/librustc_mir/build/expr/as_rvalue.rs
src/librustc_mir/build/expr/category.rs
src/librustc_mir/build/expr/into.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/hair/cx/expr.rs
src/librustc_mir/hair/cx/mod.rs
src/librustc_mir/hair/mod.rs
src/librustc_mir/lib.rs
src/librustc_mir/mir_map.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/type_check.rs
src/librustc_passes/consts.rs
src/librustc_passes/diagnostics.rs
src/librustc_passes/loops.rs
src/librustc_passes/mir_stats.rs
src/librustc_passes/rvalues.rs
src/librustc_passes/static_recursion.rs
src/librustc_privacy/lib.rs
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/diagnostics.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/librustc_save_analysis/dump_visitor.rs
src/librustc_save_analysis/lib.rs
src/librustc_save_analysis/span_utils.rs
src/librustc_trans/abi.rs
src/librustc_trans/base.rs
src/librustc_trans/builder.rs
src/librustc_trans/callee.rs
src/librustc_trans/collector.rs
src/librustc_trans/common.rs
src/librustc_trans/consts.rs
src/librustc_trans/context.rs
src/librustc_trans/debuginfo/metadata.rs
src/librustc_trans/debuginfo/mod.rs
src/librustc_trans/debuginfo/type_names.rs
src/librustc_trans/debuginfo/utils.rs
src/librustc_trans/declare.rs
src/librustc_trans/disr.rs
src/librustc_trans/glue.rs
src/librustc_trans/intrinsic.rs
src/librustc_trans/meth.rs
src/librustc_trans/mir/block.rs
src/librustc_trans/mir/constant.rs
src/librustc_trans/mir/mod.rs
src/librustc_trans/mir/rvalue.rs
src/librustc_trans/trans_item.rs
src/librustc_trans/type_of.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/callee.rs
src/librustc_typeck/check/closure.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/compare_method.rs
src/librustc_typeck/check/demand.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/mod.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/builtin.rs
src/librustc_typeck/coherence/inherent.rs [new file with mode: 0644]
src/librustc_typeck/coherence/mod.rs
src/librustc_typeck/coherence/orphan.rs
src/librustc_typeck/coherence/overlap.rs
src/librustc_typeck/coherence/unsafety.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/diagnostics.rs
src/librustc_typeck/impl_wf_check.rs
src/librustc_typeck/lib.rs
src/librustc_typeck/variance/constraints.rs
src/librustc_typeck/variance/solve.rs
src/librustc_typeck/variance/terms.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/core.rs
src/librustdoc/html/format.rs
src/librustdoc/html/highlight.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/main.js
src/librustdoc/html/static/rustdoc.css
src/librustdoc/test.rs
src/librustdoc/visit_ast.rs
src/librustdoc/visit_lib.rs
src/libstd/build.rs
src/libstd/collections/hash/map.rs
src/libstd/ffi/c_str.rs
src/libstd/panic.rs
src/libstd/panicking.rs
src/libstd/process.rs
src/libstd/sync/barrier.rs
src/libstd/sync/condvar.rs
src/libstd/sync/mutex.rs
src/libstd/sys/redox/backtrace.rs
src/libstd/sys/redox/mod.rs
src/libstd/sys/redox/net/tcp.rs
src/libstd/sys/redox/net/udp.rs
src/libstd/sys/unix/backtrace/mod.rs
src/libstd/sys/unix/backtrace/printing/dladdr.rs
src/libstd/sys/unix/backtrace/printing/gnu.rs [deleted file]
src/libstd/sys/unix/backtrace/printing/mod.rs
src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs
src/libstd/sys/unix/backtrace/tracing/gcc_s.rs
src/libstd/sys/unix/fs.rs
src/libstd/sys/unix/os.rs
src/libstd/sys/unix/process/magenta.rs
src/libstd/sys/unix/process/process_fuchsia.rs
src/libstd/sys/windows/backtrace.rs [deleted file]
src/libstd/sys/windows/backtrace/backtrace_gnu.rs [new file with mode: 0644]
src/libstd/sys/windows/backtrace/mod.rs [new file with mode: 0644]
src/libstd/sys/windows/backtrace/printing/mod.rs [new file with mode: 0644]
src/libstd/sys/windows/backtrace/printing/msvc.rs [new file with mode: 0644]
src/libstd/sys/windows/backtrace_gnu.rs [deleted file]
src/libstd/sys/windows/printing/gnu.rs [deleted file]
src/libstd/sys/windows/printing/msvc.rs [deleted file]
src/libstd/sys_common/backtrace.rs
src/libstd/sys_common/gnu/libbacktrace.rs
src/libstd/sys_common/poison.rs
src/libstd/thread/mod.rs
src/libsyntax/abi.rs
src/libsyntax/attr.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/quote.rs
src/libsyntax/ext/tt/macro_parser.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax/ext/tt/quoted.rs [new file with mode: 0644]
src/libsyntax/ext/tt/transcribe.rs
src/libsyntax/feature_gate.rs
src/libsyntax/fold.rs
src/libsyntax/lib.rs
src/libsyntax/parse/lexer/mod.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/libsyntax/tokenstream.rs
src/libsyntax/visit.rs
src/libsyntax_ext/deriving/generic/mod.rs
src/libsyntax_ext/lib.rs
src/libsyntax_ext/proc_macro_impl.rs
src/libsyntax_ext/proc_macro_registrar.rs
src/libtest/lib.rs
src/libtest/stats.rs
src/libunwind/libunwind.rs
src/test/COMPILER_TESTS.md [new file with mode: 0644]
src/test/codegen/abi-x86-interrupt.rs [new file with mode: 0644]
src/test/codegen/function-arguments.rs
src/test/compile-fail-fulldeps/gated-quote.rs
src/test/compile-fail-fulldeps/proc-macro/auxiliary/bang_proc_macro.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs
src/test/compile-fail/E0079.rs [deleted file]
src/test/compile-fail/E0081.rs
src/test/compile-fail/E0117.rs
src/test/compile-fail/E0306.rs [deleted file]
src/test/compile-fail/asm-bad-clobber.rs
src/test/compile-fail/asm-in-bad-modifier.rs
src/test/compile-fail/asm-misplaced-option.rs
src/test/compile-fail/asm-out-assign-imm.rs
src/test/compile-fail/asm-out-no-modifier.rs
src/test/compile-fail/asm-out-read-uninit.rs
src/test/compile-fail/associated-const-array-len.rs
src/test/compile-fail/associated-const-type-parameter-arrays-2.rs
src/test/compile-fail/associated-const-type-parameter-arrays.rs
src/test/compile-fail/closure-no-fn.rs [new file with mode: 0644]
src/test/compile-fail/coherence-cross-crate-conflict.rs
src/test/compile-fail/coherence-default-trait-impl.rs
src/test/compile-fail/coherence-impls-sized.rs
src/test/compile-fail/const-array-oob.rs
src/test/compile-fail/const-block-non-item-statement-2.rs [new file with mode: 0644]
src/test/compile-fail/const-block-non-item-statement.rs
src/test/compile-fail/const-call.rs
src/test/compile-fail/const-eval-overflow-4b.rs
src/test/compile-fail/const-eval-span.rs
src/test/compile-fail/const-integer-bool-ops.rs
src/test/compile-fail/const-tup-index-span.rs
src/test/compile-fail/cycle-projection-based-on-where-clause.rs
src/test/compile-fail/cycle-trait-default-type-trait.rs
src/test/compile-fail/cycle-trait-supertrait-indirect.rs
src/test/compile-fail/default_ty_param_conflict.rs
src/test/compile-fail/default_ty_param_conflict_cross_crate.rs
src/test/compile-fail/deprecated_no_stack_check.rs [new file with mode: 0644]
src/test/compile-fail/discrim-ill-typed.rs
src/test/compile-fail/enum-discrim-too-small.rs
src/test/compile-fail/feature-gate-abi.rs
src/test/compile-fail/feature-gate-cfg-target-has-atomic.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-closure_to_fn_coercion.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-static_recursion.rs [deleted file]
src/test/compile-fail/feature-gate-unboxed-closures.rs [new file with mode: 0644]
src/test/compile-fail/generic-non-trailing-defaults.rs
src/test/compile-fail/generic-type-params-forward-mention.rs
src/test/compile-fail/impl-trait/auto-trait-leak.rs
src/test/compile-fail/impl-trait/equality.rs
src/test/compile-fail/invalid-path-in-const.rs
src/test/compile-fail/issue-12511.rs
src/test/compile-fail/issue-15524.rs
src/test/compile-fail/issue-18183.rs
src/test/compile-fail/issue-20772.rs
src/test/compile-fail/issue-21177.rs
src/test/compile-fail/issue-22933-2.rs
src/test/compile-fail/issue-23217.rs
src/test/compile-fail/issue-25145.rs [deleted file]
src/test/compile-fail/issue-28586.rs
src/test/compile-fail/issue-3008-2.rs
src/test/compile-fail/issue-31910.rs
src/test/compile-fail/issue-3521.rs
src/test/compile-fail/issue-35450.rs
src/test/compile-fail/issue-35869.rs
src/test/compile-fail/issue-37131.rs
src/test/compile-fail/issue-37576.rs [new file with mode: 0644]
src/test/compile-fail/issue-39404.rs [new file with mode: 0644]
src/test/compile-fail/issue-39559.rs
src/test/compile-fail/issue-39709.rs [deleted file]
src/test/compile-fail/issue-8761.rs
src/test/compile-fail/macro-error.rs
src/test/compile-fail/macro-tt-matchers.rs
src/test/compile-fail/malformed_macro_lhs.rs
src/test/compile-fail/match-privately-empty.rs [new file with mode: 0644]
src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
src/test/compile-fail/non-constant-expr-for-vec-repeat.rs
src/test/compile-fail/resolve-label.rs
src/test/compile-fail/resolve-self-in-impl.rs
src/test/compile-fail/static-recursion-gate.rs [deleted file]
src/test/compile-fail/transmute-from-fn-item-types-error.rs
src/test/compile-fail/transmute-from-fn-item-types-lint.rs [deleted file]
src/test/compile-fail/uninhabited-matches-feature-gated.rs
src/test/incremental/hashes/enum_defs.rs
src/test/incremental/issue-39828/auxiliary/generic.rs [new file with mode: 0644]
src/test/incremental/issue-39828/issue-39828.rs [new file with mode: 0644]
src/test/mir-opt/simplify_if.rs
src/test/parse-fail/issue-33569.rs
src/test/parse-fail/range_inclusive_gate.rs
src/test/run-make/fpic/Makefile [new file with mode: 0644]
src/test/run-make/fpic/hello.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot
src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot
src/test/run-make/issue-24445/Makefile
src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs
src/test/run-pass-fulldeps/mbe_matching_test_macro.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/bang-macro.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/proc-macro/auxiliary/issue-39889.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/proc-macro/bang-macro.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/proc-macro/issue-39889.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/quote-tokens.rs
src/test/run-pass/associated-types-sugar-path.rs
src/test/run-pass/auxiliary/clibrary.rs [new file with mode: 0644]
src/test/run-pass/auxiliary/issue_39823.rs [new file with mode: 0644]
src/test/run-pass/backtrace-debuginfo.rs
src/test/run-pass/backtrace.rs
src/test/run-pass/closure-to-fn-coercion.rs [new file with mode: 0644]
src/test/run-pass/enum-layout-optimization.rs [new file with mode: 0644]
src/test/run-pass/impl-trait/auto-trait-leak.rs
src/test/run-pass/impl-trait/equality.rs
src/test/run-pass/issue-2063-resource.rs
src/test/run-pass/issue-2063.rs
src/test/run-pass/issue-25145.rs [new file with mode: 0644]
src/test/run-pass/issue-38972.rs [new file with mode: 0644]
src/test/run-pass/issue-39548.rs [new file with mode: 0644]
src/test/run-pass/issue-39709.rs [new file with mode: 0644]
src/test/run-pass/issue-39823.rs [new file with mode: 0644]
src/test/run-pass/iter-sum-overflow-overflow-checks.rs [new file with mode: 0644]
src/test/run-pass/lib-defaults.rs [new file with mode: 0644]
src/test/run-pass/loop-break-value.rs
src/test/run-pass/panic-safe.rs
src/test/run-pass/static-recursive.rs
src/test/run-pass/transmute-from-fn-item-types.rs [deleted file]
src/test/rustdoc/assoc-consts.rs
src/test/rustdoc/issue-27759.rs
src/test/rustdoc/issue-28478.rs
src/test/rustdoc/issue-32374.rs
src/test/rustdoc/issue-33302.rs
src/test/ui/codemap_tests/unicode.stderr
src/test/ui/mismatched_types/E0053.stderr
src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
src/test/ui/resolve/issue-23305.stderr
src/test/ui/resolve/levenshtein.stderr
src/test/ui/span/E0204.stderr
src/tools/build-manifest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/rustbook/Cargo.toml
src/tools/tidy/src/features.rs

index c4b97def3126b3b2615c6f9dfc311bc0dc862a2a..442d02aca7867f27fe58e95a4e08f17777c9e8a2 100644 (file)
@@ -12,10 +12,11 @@ matrix:
   fast_finish: true
   include:
     # Linux builders, all docker images
-    - env: IMAGE=android DEPLOY=1
+    - env: IMAGE=arm-android
     - env: IMAGE=armhf-gnu
     - env: IMAGE=cross DEPLOY=1
     - env: IMAGE=linux-tested-targets DEPLOY=1
+    - env: IMAGE=dist-android DEPLOY=1
     - env: IMAGE=dist-arm-linux DEPLOY=1
     - env: IMAGE=dist-armv7-aarch64-linux DEPLOY=1
     - env: IMAGE=dist-freebsd DEPLOY=1
@@ -45,8 +46,8 @@ matrix:
       os: osx
       osx_image: xcode8.2
       install: &osx_install_sccache >
-        curl -L https://api.pub.build.mozilla.org/tooltool/sha512/d0025b286468cc5ada83b23d3fafbc936b9f190eaa7d4a981715b18e8e3bf720a7bcee7bfe758cfdeb8268857f6098fd52dcdd8818232692a30ce91039936596 |
-          tar xJf - -C /usr/local/bin --strip-components=1
+        travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-apple-darwin &&
+          chmod +x /usr/local/bin/sccache
     - env: >
         RUST_CHECK_TARGET=check
         RUST_CONFIGURE_ARGS=--build=i686-apple-darwin
@@ -63,8 +64,10 @@ matrix:
       os: osx
       osx_image: xcode8.2
       install: >
-        curl -L https://api.pub.build.mozilla.org/tooltool/sha512/d0025b286468cc5ada83b23d3fafbc936b9f190eaa7d4a981715b18e8e3bf720a7bcee7bfe758cfdeb8268857f6098fd52dcdd8818232692a30ce91039936596 |
-          tar xJf - -C /usr/local/bin --strip-components=1 && brew uninstall --ignore-dependencies openssl && brew install openssl --universal --without-test
+        travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-apple-darwin &&
+          chmod +x /usr/local/bin/sccache &&
+          brew uninstall --ignore-dependencies openssl &&
+          brew install openssl --universal --without-test
     - env: >
         RUST_CHECK_TARGET=dist
         RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended"
diff --git a/COMPILER_TESTS.md b/COMPILER_TESTS.md
deleted file mode 100644 (file)
index 58df1aa..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-# Compiler Test Documentation
-
-In the Rust project, we use a special set of commands embedded in
-comments to test the Rust compiler. There are two groups of commands:
-
-1. Header commands
-2. Error info commands
-
-Both types of commands are inside comments, but header commands should
-be in a comment before any code.
-
-## Summary of Error Info Commands
-
-Error commands specify something about certain lines of the
-program. They tell the test what kind of error and what message you
-are expecting.
-
-* `~`: Associates the following error level and message with the
-  current line
-* `~|`: Associates the following error level and message with the same
-  line as the previous comment
-* `~^`: Associates the following error level and message with the
-  previous line. Each caret (`^`) that you add adds a line to this, so
-  `~^^^^^^^` is seven lines up.
-
-The error levels that you can have are:
-
-1. `ERROR`
-2. `WARNING`
-3. `NOTE`
-4. `HELP` and `SUGGESTION`*
-
-\* **Note**: `SUGGESTION` must follow immediately after `HELP`.
-
-## Summary of Header Commands
-
-Header commands specify something about the entire test file as a
-whole, instead of just a few lines inside the test.
-
-* `ignore-X` where `X` is an architecture, OS or stage will ignore the test accordingly
-* `ignore-pretty` will not compile the pretty-printed test (this is done to test the pretty-printer, but might not always work)
-* `ignore-test` always ignores the test
-* `ignore-lldb` and `ignore-gdb` will skip the debuginfo tests
-* `min-{gdb,lldb}-version`
-* `should-fail` indicates that the test should fail; used for "meta testing",
-  where we test the compiletest program itself to check that it will generate
-  errors in appropriate scenarios. This header is ignored for pretty-printer tests.
-* `gate-test-X` where `X` is a feature marks the test as "gate test" for feature X.
-  Such tests are supposed to ensure that the compiler errors when usage of a gated
-  feature is attempted without the proper `#![feature(X)]` tag.
-  Each unstable lang feature is required to have a gate test.
-
-## Revisions
-
-Certain classes of tests support "revisions" (as of the time of this
-writing, this includes run-pass, compile-fail, run-fail, and
-incremental, though incremental tests are somewhat
-different). Revisions allow a single test file to be used for multiple
-tests. This is done by adding a special header at the top of the file:
-
-```
-// revisions: foo bar baz
-```
-
-This will result in the test being compiled (and tested) three times,
-once with `--cfg foo`, once with `--cfg bar`, and once with `--cfg
-baz`. You can therefore use `#[cfg(foo)]` etc within the test to tweak
-each of these results.
-
-You can also customize headers and expected error messages to a particular
-revision. To do this, add `[foo]` (or `bar`, `baz`, etc) after the `//`
-comment, like so:
-
-```
-// A flag to pass in only for cfg `foo`:
-//[foo]compile-flags: -Z verbose
-
-#[cfg(foo)]
-fn test_foo() {
-    let x: usize = 32_u32; //[foo]~ ERROR mismatched types
-}
-```
-
-Note that not all headers have meaning when customized to a revision.
-For example, the `ignore-test` header (and all "ignore" headers)
-currently only apply to the test as a whole, not to particular
-revisions. The only headers that are intended to really work when
-customized to a revision are error patterns and compiler flags.
index e9d8c84f4071505ccb75071d3dcfdf9f5962b543..1e983cfd726d6990c25f6ce28f30a3efa8405082 100644 (file)
@@ -97,33 +97,38 @@ system internals, try asking in [`#rust-internals`][pound-rust-internals].
 
 Before you can start building the compiler you need to configure the build for
 your system. In most cases, that will just mean using the defaults provided
-for Rust. Configuring involves invoking the `configure` script in the project
-root.
+for Rust.
 
-```
-./configure
-```
+To change configuration, you must copy the file `src/bootstrap/config.toml.example`
+to `config.toml` in the directory from which you will be running the build, and
+change the settings provided.
+
+There are large number of options provided in this config file that will alter the
+configuration used in the build process. Some options to note:
 
-There are large number of options accepted by this script to alter the
-configuration used later in the build process. Some options to note:
+#### `[llvm]`:
+- `ccache = true` - Use ccache when building llvm
 
-- `--enable-debug` - Build a debug version of the compiler (disables optimizations,
-    which speeds up compilation of stage1 rustc)
-- `--enable-optimize` - Enable optimizations (can be used with `--enable-debug`
-    to make a debug build with optimizations)
-- `--disable-valgrind-rpass` - Don't run tests with valgrind
-- `--enable-clang` - Prefer clang to gcc for building dependencies (e.g., LLVM)
-- `--enable-ccache` - Invoke clang/gcc with ccache to re-use object files between builds
-- `--enable-compiler-docs` - Build compiler documentation
+#### `[build]`:
+- `compiler-docs = true` - Build compiler documentation
 
-To see a full list of options, run `./configure --help`.
+#### `[rust]`:
+- `debuginfo = true` - Build a compiler with debuginfo
+- `optimize = false` - Disable optimizations to speed up compilation of stage1 rust
+
+For more options, the `config.toml` file contains commented out defaults, with
+descriptions of what each option will do.
+
+Note: Previously the `./configure` script was used to configure this
+project. It can still be used, but it's recommended to use a `config.toml`
+file. If you still have a `config.mk` file in your directory - from
+`./configure` - you may need to delete it for `config.toml` to work.
 
 ### Building
 
-Although the `./configure` script will generate a `Makefile`, this is actually
-just a thin veneer over the actual build system driver, `x.py`. This file, at
-the root of the repository, is used to build, test, and document various parts
-of the compiler. You can execute it as:
+The build system uses the `x.py` script to control the build process. This script
+is used to build, test, and document various parts of the compiler. You can
+execute it as:
 
 ```sh
 python x.py build
@@ -185,6 +190,9 @@ To learn about all possible rules you can execute, run:
 python x.py build --help --verbose
 ```
 
+Note: Previously `./configure` and `make` were used to build this project.
+They are still available, but `x.py` is the recommended build system.
+
 ### Useful commands
 
 Some common invocations of `x.py` are:
@@ -235,8 +243,8 @@ feature. We use the 'fork and pull' model described there.
 
 Please make pull requests against the `master` branch.
 
-Compiling all of `make check` can take a while. When testing your pull request,
-consider using one of the more specialized `make` targets to cut down on the
+Compiling all of `./x.py test` can take a while. When testing your pull request,
+consider using one of the more specialized `./x.py` targets to cut down on the
 amount of time you have to wait. You need to have built the compiler at least
 once before running these will work, but that’s only one full build rather than
 one each time.
@@ -307,7 +315,7 @@ To find documentation-related issues, sort by the [A-docs label][adocs].
 
 [adocs]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AA-docs
 
-In many cases, you don't need a full `make doc`. You can use `rustdoc` directly
+In many cases, you don't need a full `./x.py 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 the HTML is right.
index c1218e9c600ce772e82b053083393e84ad44f47c..93415adc423f4b26a28dddc1856fc2b519f8f0f7 100644 (file)
--- a/README.md
+++ b/README.md
@@ -35,15 +35,15 @@ Read ["Installing Rust"] from [The Book].
 3. Build and install:
 
     ```sh
-    $ ./configure
-    $ make && sudo make install
+    $ ./x.py build && sudo ./x.py dist --install
     ```
 
-    > ***Note:*** Install locations can be adjusted by passing a `--prefix`
-    > argument to `configure`. Various other options are also supported – pass
-    > `--help` for more information on them.
+    > ***Note:*** Install locations can be adjusted by copying the config file
+    > from `./src/bootstrap/config.toml.example` to `./config.toml`, and
+    > adjusting the `prefix` option under `[install]`. Various other options are
+    > also supported, and are documented in the config file.
 
-    When complete, `sudo make install` will place several programs into
+    When complete, `sudo ./x.py dist --install` will place several programs into
     `/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
     API-documentation tool. This install does not include [Cargo],
     Rust's package manager, which you may also want to build.
@@ -59,7 +59,6 @@ for interop with software produced by Visual Studio use the MSVC build of Rust;
 for interop with GNU software built using the MinGW/MSYS2 toolchain use the GNU
 build.
 
-
 #### MinGW
 
 [MSYS2][msys2] can be used to easily build Rust on Windows:
@@ -94,11 +93,10 @@ build.
                mingw-w64-x86_64-gcc
    ```
 
-4. Navigate to Rust's source code (or clone it), then configure and build it:
+4. Navigate to Rust's source code (or clone it), then build it:
 
    ```sh
-   $ ./configure
-   $ make && make install
+   $ ./x.py build && ./x.py dist --install
    ```
 
 #### MSVC
@@ -114,13 +112,6 @@ shell with:
 > python x.py build
 ```
 
-If you're running inside of an msys shell, however, you can run:
-
-```sh
-$ ./configure --build=x86_64-pc-windows-msvc
-$ make && make install
-```
-
 Currently building Rust only works with some known versions of Visual Studio. If
 you have a more recent version installed the build system doesn't understand
 then you may need to force rustbuild to use an older version. This can be done
@@ -131,13 +122,43 @@ CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.
 python x.py build
 ```
 
+#### Specifying an ABI
+
+Each specific ABI can also be used from either environment (for example, using
+the GNU ABI in powershell) by using an explicit build triple. The available
+Windows build triples are:
+- GNU ABI (using GCC)
+    - `i686-pc-windows-gnu`
+    - `x86_64-pc-windows-gnu`
+- The MSVC ABI
+    - `i686-pc-windows-msvc`
+    - `x86_64-pc-windows-msvc`
+
+The build triple can be specified by either specifying `--build=ABI` when
+invoking `x.py` commands, or by copying the `config.toml` file (as described
+in Building From Source), and modifying the `build` option under the `[build]`
+section.
+
+### Configure and Make
+
+While it's not the recommended build system, this project also provides a
+configure script and makefile (the latter of which just invokes `x.py`).
+
+```sh
+$ ./configure
+$ make && sudo make install
+```
+
+When using the configure script, the generated config.mk` file may override the
+`config.toml` file. To go back to the `config.toml` file, delete the generated
+`config.mk` file.
+
 ## Building Documentation
 
 If you’d like to build the documentation, it’s almost the same:
 
 ```sh
-$ ./configure
-$ make docs
+$ ./x.py doc
 ```
 
 The generated documentation will appear in a top-level `doc` directory,
index 44791b033a641a789a1efc98f24abd78b40551ef..9a0a4d81f9b1efd66ccb4574253a7b536c60a67e 100644 (file)
@@ -103,7 +103,7 @@ install:
   # /usr/bin/python2.7.exe is not. To ensure we use the right interpreter we
   # move `C:\Python27` ahead in PATH and then also make sure the `python2.7.exe`
   # file exists in there (which it doesn't by default).
-  - if defined MINGW_URL appveyor DownloadFile %MINGW_URL%/%MINGW_ARCHIVE%
+  - if defined MINGW_URL appveyor-retry appveyor DownloadFile %MINGW_URL%/%MINGW_ARCHIVE%
   - if defined MINGW_URL 7z x -y %MINGW_ARCHIVE% > nul
   - if defined MINGW_URL set PATH=%CD%\%MINGW_DIR%\bin;C:\msys64\usr\bin;%PATH%
 
@@ -115,14 +115,12 @@ install:
   - set PATH=C:\Python27;%PATH%
 
   # Download and install sccache
-  - appveyor DownloadFile https://api.pub.build.mozilla.org/tooltool/sha512/%SCCACHE_DIGEST%
-  - mv %SCCACHE_DIGEST% sccache.tar.bz2
-  - 7z x -y sccache.tar.bz2 > nul
-  - 7z x -y sccache.tar > nul
-  - set PATH=%PATH%;%CD%\sccache2
+  - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-pc-windows-msvc
+  - mv 2017-02-25-sccache-x86_64-pc-windows-msvc sccache
+  - set PATH=%PATH%;%CD%
 
   # Install InnoSetup to get `iscc` used to produce installers
-  - choco install -y InnoSetup
+  - appveyor-retry choco install -y InnoSetup
   - set PATH="C:\Program Files (x86)\Inno Setup 5";%PATH%
 
   # Help debug some handle issues on AppVeyor
@@ -133,18 +131,14 @@ install:
   - handle.exe -accepteula -help
 
 test_script:
-  - git submodule update --init
+  - appveyor-retry sh -c 'git submodule deinit -f . && git submodule update --init'
   - set SRC=.
   - set NO_CCACHE=1
   - sh src/ci/run.sh
 
 cache:
-  - "build/i686-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger"
-  - "build/x86_64-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger"
   - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger"
   - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger"
-  - "i686-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger"
-  - "x86_64-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger"
   - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger"
   - "x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger"
 
index 16a641cc96d15ae1facc2eb9ca10165f33fe235f..1fb5d34d13f5d063a59869668340762b400406b6 100644 (file)
@@ -270,7 +270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "mdbook"
-version = "0.0.16"
+version = "0.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -401,7 +401,7 @@ name = "rustbook"
 version = "0.1.0"
 dependencies = [
  "clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "mdbook 0.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mdbook 0.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -976,7 +976,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b"
 "checksum libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "684f330624d8c3784fb9558ca46c4ce488073a8d22450415c5eb4f4cfb0d11b5"
 "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
-"checksum mdbook 0.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "14e8a6aca534ac51bad1c1886b10f6d6948a14fa70b1b20a1e41c9e5c0fe3019"
+"checksum mdbook 0.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dbba458ca886cb082d026afd704eeeeb0531f7e4ffd6c619f72dc309c1c18fe4"
 "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
 "checksum num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a16a42856a256b39c6d3484f097f6713e14feacd9bfb02290917904fae46c81c"
 "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3"
index 62e476bd737d3f62c02d59de2cc168021392b640..a996240f61650fa4e1af52feb76da79d2d9e2c65 100644 (file)
@@ -68,6 +68,7 @@ fn main() {
     };
     let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
     let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
+    let mut on_fail = env::var_os("RUSTC_ON_FAIL").map(|of| Command::new(of));
 
     let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
     let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
@@ -217,9 +218,20 @@ fn main() {
     }
 
     // Actually run the compiler!
-    std::process::exit(match exec_cmd(&mut cmd) {
-        Ok(s) => s.code().unwrap_or(0xfe),
-        Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e),
+    std::process::exit(if let Some(ref mut on_fail) = on_fail {
+        match cmd.status() {
+            Ok(s) if s.success() => 0,
+            _ => {
+                println!("\nDid not run successfully:\n{:?}\n-------------", cmd);
+                exec_cmd(on_fail).expect("could not run the backup command");
+                1
+            }
+        }
+    } else {
+        std::process::exit(match exec_cmd(&mut cmd) {
+            Ok(s) => s.code().unwrap_or(0xfe),
+            Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e),
+        })
     })
 }
 
index 7ca7ef4bd720c2f8ab8a119af8bbe3c6d52b2390..c1ee0c29ac981376a42e09e0554dd90266c3dc40 100644 (file)
@@ -59,6 +59,16 @@ def delete_if_present(path, verbose):
 
 
 def download(path, url, probably_big, verbose):
+    for x in range(0, 4):
+        try:
+            _download(path, url, probably_big, verbose, True)
+            return
+        except RuntimeError:
+            print("\nspurious failure, trying again")
+    _download(path, url, probably_big, verbose, False)
+
+
+def _download(path, url, probably_big, verbose, exception):
     if probably_big or verbose:
         print("downloading {}".format(url))
     # see http://serverfault.com/questions/301128/how-to-download
@@ -66,13 +76,16 @@ def download(path, url, probably_big, verbose):
         run(["PowerShell.exe", "/nologo", "-Command",
              "(New-Object System.Net.WebClient)"
              ".DownloadFile('{}', '{}')".format(url, path)],
-            verbose=verbose)
+            verbose=verbose,
+            exception=exception)
     else:
         if probably_big or verbose:
             option = "-#"
         else:
             option = "-s"
-        run(["curl", option, "--retry", "3", "-Sf", "-o", path, url], verbose=verbose)
+        run(["curl", option, "--retry", "3", "-Sf", "-o", path, url],
+            verbose=verbose,
+            exception=exception)
 
 
 def verify(path, sha_path, verbose):
@@ -112,7 +125,7 @@ def unpack(tarball, dst, verbose=False, match=None):
             shutil.move(tp, fp)
     shutil.rmtree(os.path.join(dst, fname))
 
-def run(args, verbose=False):
+def run(args, verbose=False, exception=False):
     if verbose:
         print("running: " + ' '.join(args))
     sys.stdout.flush()
@@ -122,7 +135,7 @@ def run(args, verbose=False):
     code = ret.wait()
     if code != 0:
         err = "failed to run: " + ' '.join(args)
-        if verbose:
+        if verbose or exception:
             raise RuntimeError(err)
         sys.exit(err)
 
@@ -342,8 +355,12 @@ class RustBuild(object):
         env = os.environ.copy()
         env["CARGO_TARGET_DIR"] = build_dir
         env["RUSTC"] = self.rustc()
-        env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib")
-        env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib")
+        env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
+                                 (os.pathsep + env["LD_LIBRARY_PATH"]) \
+                                 if "LD_LIBRARY_PATH" in env else ""
+        env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
+                                   (os.pathsep + env["DYLD_LIBRARY_PATH"]) \
+                                   if "DYLD_LIBRARY_PATH" in env else ""
         env["PATH"] = os.path.join(self.bin_root(), "bin") + \
                       os.pathsep + env["PATH"]
         if not os.path.isfile(self.cargo()):
@@ -472,6 +489,8 @@ class RustBuild(object):
             ostype += 'abi64'
         elif cputype in {'powerpc', 'ppc', 'ppc64'}:
             cputype = 'powerpc'
+        elif cputype == 'sparcv9':
+            pass
         elif cputype in {'amd64', 'x86_64', 'x86-64', 'x64'}:
             cputype = 'x86_64'
         else:
index c5bbfd89b2787cc530ef7a96e2177585a09913ac..b55f3d710ca7bfcee4643dd40d4e6836dc495503 100644 (file)
@@ -28,6 +28,7 @@
 /// Deserialized version of all flags for this compile.
 pub struct Flags {
     pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
+    pub on_fail: Option<String>,
     pub stage: Option<u32>,
     pub keep_stage: Option<u32>,
     pub build: String,
@@ -81,6 +82,7 @@ pub fn parse(args: &[String]) -> Flags {
         opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
         opts.optmulti("", "host", "host targets to build", "HOST");
         opts.optmulti("", "target", "target targets to build", "TARGET");
+        opts.optopt("", "on-fail", "command to run on failure", "CMD");
         opts.optopt("", "stage", "stage to build", "N");
         opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
         opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
@@ -283,6 +285,7 @@ pub fn parse(args: &[String]) -> Flags {
         Flags {
             verbose: m.opt_count("v"),
             stage: stage,
+            on_fail: m.opt_str("on-fail"),
             keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()),
             build: m.opt_str("build").unwrap_or_else(|| {
                 env::var("BUILD").unwrap()
index 7bd611eb53e3c136d329ec5bb5c56855fb77acb3..2b34142b3b0f37681fff0214262f6a106419078d 100644 (file)
@@ -499,6 +499,10 @@ fn cargo(&self,
             cargo.env("RUSTC_INCREMENTAL", incr_dir);
         }
 
+        if let Some(ref on_fail) = self.flags.on_fail {
+            cargo.env("RUSTC_ON_FAIL", on_fail);
+        }
+
         let verbose = cmp::max(self.config.verbose, self.flags.verbose);
         cargo.env("RUSTC_VERBOSE", format!("{}", verbose));
 
@@ -828,17 +832,6 @@ fn cflags(&self, target: &str) -> Vec<String> {
         if target.contains("apple-darwin") {
             base.push("-stdlib=libc++".into());
         }
-        // This is a hack, because newer binutils broke things on some vms/distros
-        // (i.e., linking against unknown relocs disabled by the following flag)
-        // See: https://github.com/rust-lang/rust/issues/34978
-        match target {
-            "i586-unknown-linux-gnu" |
-            "i686-unknown-linux-musl" |
-            "x86_64-unknown-linux-musl" => {
-                base.push("-Wa,-mrelax-relocations=no".into());
-            },
-            _ => {},
-        }
         return base
     }
 
index 536095503e0daed170d0d0e6dcf4fbdc50bcca56..457ac825832ce1d6ed6f4bb5b9bc719be6dcf524 100644 (file)
@@ -71,6 +71,8 @@ install:
        $(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS)
 tidy:
        $(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS)
+prepare:
+       $(Q)$(BOOTSTRAP) build nonexistent/path/to/trigger/cargo/metadata
 
 check-stage2-T-arm-linux-androideabi-H-x86_64-unknown-linux-gnu:
        $(Q)$(BOOTSTRAP) test --target arm-linux-androideabi
index 8e79c2d27d1957e5d4dbbd1177a8f0ca2ed2502f..bc439d6f7826d4f6bec937ac3f45886e50595316 100644 (file)
@@ -198,10 +198,6 @@ pub fn check(build: &mut Build) {
 ");
             }
         }
-
-        if target.contains("arm-linux-android") {
-            need_cmd("adb".as_ref());
-        }
     }
 
     for host in build.flags.host.iter() {
diff --git a/src/ci/docker/android/Dockerfile b/src/ci/docker/android/Dockerfile
deleted file mode 100644 (file)
index ae1bfd9..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-FROM ubuntu:16.04
-
-RUN dpkg --add-architecture i386 && \
-    apt-get update && \
-    apt-get install -y --no-install-recommends \
-  g++ \
-  make \
-  file \
-  curl \
-  ca-certificates \
-  python2.7 \
-  git \
-  cmake \
-  unzip \
-  expect \
-  openjdk-9-jre \
-  sudo \
-  libstdc++6:i386 \
-  xz-utils \
-  libssl-dev \
-  pkg-config
-
-WORKDIR /android/
-ENV PATH=$PATH:/android/ndk-arm-9/bin:/android/sdk/tools:/android/sdk/platform-tools
-
-COPY install-ndk.sh install-sdk.sh accept-licenses.sh /android/
-RUN sh /android/install-ndk.sh
-RUN sh /android/install-sdk.sh
-
-RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
-    dpkg -i dumb-init_*.deb && \
-    rm dumb-init_*.deb
-
-COPY start-emulator.sh /android/
-
-ENTRYPOINT ["/usr/bin/dumb-init", "--", "/android/start-emulator.sh"]
-
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
-
-ENV TARGETS=arm-linux-androideabi
-ENV TARGETS=$TARGETS,i686-linux-android
-ENV TARGETS=$TARGETS,aarch64-linux-android
-ENV TARGETS=$TARGETS,armv7-linux-androideabi
-
-ENV RUST_CONFIGURE_ARGS \
-      --target=$TARGETS \
-      --arm-linux-androideabi-ndk=/android/ndk-arm-9 \
-      --armv7-linux-androideabi-ndk=/android/ndk-arm-9 \
-      --i686-linux-android-ndk=/android/ndk-x86-9 \
-      --aarch64-linux-android-ndk=/android/ndk-aarch64
-
-# Just a smoke test in dist to see if this works for now, we should expand this
-# to all the targets above eventually.
-ENV SCRIPT \
-  python2.7 ../x.py test --target arm-linux-androideabi && \
-  python2.7 ../x.py dist --target $TARGETS
diff --git a/src/ci/docker/android/accept-licenses.sh b/src/ci/docker/android/accept-licenses.sh
deleted file mode 100755 (executable)
index 8d8f60a..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/expect -f
-# ignore-license
-
-set timeout 1800
-set cmd [lindex $argv 0]
-set licenses [lindex $argv 1]
-
-spawn {*}$cmd
-expect {
-  "Do you accept the license '*'*" {
-        exp_send "y\r"
-        exp_continue
-  }
-  eof
-}
diff --git a/src/ci/docker/android/install-ndk.sh b/src/ci/docker/android/install-ndk.sh
deleted file mode 100644 (file)
index 418ce69..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/bin/sh
-# Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-# file at the top-level directory of this distribution and at
-# http://rust-lang.org/COPYRIGHT.
-#
-# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-# option. This file may not be copied, modified, or distributed
-# except according to those terms.
-
-set -ex
-
-cpgdb() {
-  cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb /android/$1/bin/$2-gdb
-  cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb-orig /android/$1/bin/gdb-orig
-  cp -r android-ndk-r11c/prebuilt/linux-x86_64/share /android/$1/share
-}
-
-# Prep the Android NDK
-#
-# See https://github.com/servo/servo/wiki/Building-for-Android
-curl -O https://dl.google.com/android/repository/android-ndk-r11c-linux-x86_64.zip
-unzip -q android-ndk-r11c-linux-x86_64.zip
-bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
-        --platform=android-9 \
-        --toolchain=arm-linux-androideabi-4.9 \
-        --install-dir=/android/ndk-arm-9 \
-        --ndk-dir=/android/android-ndk-r11c \
-        --arch=arm
-cpgdb ndk-arm-9 arm-linux-androideabi
-bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
-        --platform=android-21 \
-        --toolchain=aarch64-linux-android-4.9 \
-        --install-dir=/android/ndk-aarch64 \
-        --ndk-dir=/android/android-ndk-r11c \
-        --arch=arm64
-bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
-        --platform=android-9 \
-        --toolchain=x86-4.9 \
-        --install-dir=/android/ndk-x86-9 \
-        --ndk-dir=/android/android-ndk-r11c \
-        --arch=x86
-
-rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c
diff --git a/src/ci/docker/android/install-sdk.sh b/src/ci/docker/android/install-sdk.sh
deleted file mode 100644 (file)
index 2db1d46..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/sh
-# Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-# file at the top-level directory of this distribution and at
-# http://rust-lang.org/COPYRIGHT.
-#
-# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-# option. This file may not be copied, modified, or distributed
-# except according to those terms.
-
-set -ex
-
-# Prep the SDK and emulator
-#
-# Note that the update process requires that we accept a bunch of licenses, and
-# we can't just pipe `yes` into it for some reason, so we take the same strategy
-# located in https://github.com/appunite/docker by just wrapping it in a script
-# which apparently magically accepts the licenses.
-
-mkdir sdk
-curl https://dl.google.com/android/android-sdk_r24.4-linux.tgz | \
-    tar xzf - -C sdk --strip-components=1
-
-filter="platform-tools,android-18"
-filter="$filter,sys-img-armeabi-v7a-android-18"
-
-./accept-licenses.sh "android - update sdk -a --no-ui --filter $filter"
-
-echo "no" | android create avd \
-                --name arm-18 \
-                --target android-18 \
-                --abi armeabi-v7a
diff --git a/src/ci/docker/android/start-emulator.sh b/src/ci/docker/android/start-emulator.sh
deleted file mode 100755 (executable)
index 24c477d..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-# Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-# file at the top-level directory of this distribution and at
-# http://rust-lang.org/COPYRIGHT.
-#
-# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-# option. This file may not be copied, modified, or distributed
-# except according to those terms.
-
-set -ex
-ANDROID_EMULATOR_FORCE_32BIT=true \
-  nohup nohup emulator @arm-18 -no-window -partition-size 2047 \
-  0<&- &>/dev/null &
-exec "$@"
diff --git a/src/ci/docker/arm-android/Dockerfile b/src/ci/docker/arm-android/Dockerfile
new file mode 100644 (file)
index 0000000..4c89ce1
--- /dev/null
@@ -0,0 +1,46 @@
+FROM ubuntu:16.04
+
+RUN dpkg --add-architecture i386 && \
+    apt-get update && \
+    apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  unzip \
+  expect \
+  openjdk-9-jre \
+  sudo \
+  libstdc++6:i386 \
+  xz-utils \
+  libssl-dev \
+  pkg-config
+
+WORKDIR /android/
+ENV PATH=$PATH:/android/ndk-arm-9/bin:/android/sdk/tools:/android/sdk/platform-tools
+
+COPY install-ndk.sh install-sdk.sh accept-licenses.sh /android/
+RUN sh /android/install-ndk.sh
+RUN sh /android/install-sdk.sh
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+
+COPY start-emulator.sh /android/
+
+ENTRYPOINT ["/usr/bin/dumb-init", "--", "/android/start-emulator.sh"]
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-24-sccache-x86_64-unknown-linux-gnu && \
+      chmod +x /usr/local/bin/sccache
+
+ENV RUST_CONFIGURE_ARGS \
+      --target=arm-linux-androideabi \
+      --arm-linux-androideabi-ndk=/android/ndk-arm-9
+
+ENV SCRIPT python2.7 ../x.py test --target arm-linux-androideabi
diff --git a/src/ci/docker/arm-android/accept-licenses.sh b/src/ci/docker/arm-android/accept-licenses.sh
new file mode 100755 (executable)
index 0000000..8d8f60a
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/expect -f
+# ignore-license
+
+set timeout 1800
+set cmd [lindex $argv 0]
+set licenses [lindex $argv 1]
+
+spawn {*}$cmd
+expect {
+  "Do you accept the license '*'*" {
+        exp_send "y\r"
+        exp_continue
+  }
+  eof
+}
diff --git a/src/ci/docker/arm-android/install-ndk.sh b/src/ci/docker/arm-android/install-ndk.sh
new file mode 100644 (file)
index 0000000..389ec06
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+
+cpgdb() {
+  cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb /android/$1/bin/$2-gdb
+  cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb-orig /android/$1/bin/gdb-orig
+  cp -r android-ndk-r11c/prebuilt/linux-x86_64/share /android/$1/share
+}
+
+# Prep the Android NDK
+#
+# See https://github.com/servo/servo/wiki/Building-for-Android
+curl -O https://dl.google.com/android/repository/android-ndk-r11c-linux-x86_64.zip
+unzip -q android-ndk-r11c-linux-x86_64.zip
+bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
+        --platform=android-9 \
+        --toolchain=arm-linux-androideabi-4.9 \
+        --install-dir=/android/ndk-arm-9 \
+        --ndk-dir=/android/android-ndk-r11c \
+        --arch=arm
+cpgdb ndk-arm-9 arm-linux-androideabi
+
+rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c
diff --git a/src/ci/docker/arm-android/install-sdk.sh b/src/ci/docker/arm-android/install-sdk.sh
new file mode 100644 (file)
index 0000000..2db1d46
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+
+# Prep the SDK and emulator
+#
+# Note that the update process requires that we accept a bunch of licenses, and
+# we can't just pipe `yes` into it for some reason, so we take the same strategy
+# located in https://github.com/appunite/docker by just wrapping it in a script
+# which apparently magically accepts the licenses.
+
+mkdir sdk
+curl https://dl.google.com/android/android-sdk_r24.4-linux.tgz | \
+    tar xzf - -C sdk --strip-components=1
+
+filter="platform-tools,android-18"
+filter="$filter,sys-img-armeabi-v7a-android-18"
+
+./accept-licenses.sh "android - update sdk -a --no-ui --filter $filter"
+
+echo "no" | android create avd \
+                --name arm-18 \
+                --target android-18 \
+                --abi armeabi-v7a
diff --git a/src/ci/docker/arm-android/start-emulator.sh b/src/ci/docker/arm-android/start-emulator.sh
new file mode 100755 (executable)
index 0000000..24c477d
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+# Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+ANDROID_EMULATOR_FORCE_32BIT=true \
+  nohup nohup emulator @arm-18 -no-window -partition-size 2047 \
+  0<&- &>/dev/null &
+exec "$@"
index e64f65438cbd5a7d4f2f96cc6eb532a758c7309e..39b7e9df4b842922e4b86bdd27225d14f7044139 100644 (file)
@@ -73,9 +73,9 @@ RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static
 # TODO: What is this?!
 RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index 52c5b83f2632284986b0ecf06d331fee56866de2..1d5be59186bdb2a69646e496c0785787aaaf0c17 100644 (file)
@@ -21,9 +21,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile
new file mode 100644 (file)
index 0000000..6d433cc
--- /dev/null
@@ -0,0 +1,50 @@
+FROM ubuntu:16.04
+
+RUN dpkg --add-architecture i386 && \
+    apt-get update && \
+    apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  unzip \
+  expect \
+  openjdk-9-jre \
+  sudo \
+  libstdc++6:i386 \
+  xz-utils \
+  libssl-dev \
+  pkg-config
+
+WORKDIR /android/
+ENV PATH=$PATH:/android/ndk-arm-9/bin:/android/sdk/tools:/android/sdk/platform-tools
+
+COPY install-ndk.sh /android/
+RUN sh /android/install-ndk.sh
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+ENV TARGETS=arm-linux-androideabi
+ENV TARGETS=$TARGETS,i686-linux-android
+ENV TARGETS=$TARGETS,aarch64-linux-android
+ENV TARGETS=$TARGETS,armv7-linux-androideabi
+
+ENV RUST_CONFIGURE_ARGS \
+      --target=$TARGETS \
+      --arm-linux-androideabi-ndk=/android/ndk-arm-9 \
+      --armv7-linux-androideabi-ndk=/android/ndk-arm-9 \
+      --i686-linux-android-ndk=/android/ndk-x86-9 \
+      --aarch64-linux-android-ndk=/android/ndk-aarch64
+
+ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
diff --git a/src/ci/docker/dist-android/install-ndk.sh b/src/ci/docker/dist-android/install-ndk.sh
new file mode 100644 (file)
index 0000000..19c1b94
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+
+# Prep the Android NDK
+#
+# See https://github.com/servo/servo/wiki/Building-for-Android
+curl -O https://dl.google.com/android/repository/android-ndk-r11c-linux-x86_64.zip
+unzip -q android-ndk-r11c-linux-x86_64.zip
+bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
+        --platform=android-9 \
+        --toolchain=arm-linux-androideabi-4.9 \
+        --install-dir=/android/ndk-arm-9 \
+        --ndk-dir=/android/android-ndk-r11c \
+        --arch=arm
+bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
+        --platform=android-21 \
+        --toolchain=aarch64-linux-android-4.9 \
+        --install-dir=/android/ndk-aarch64 \
+        --ndk-dir=/android/android-ndk-r11c \
+        --arch=arm64
+bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
+        --platform=android-9 \
+        --toolchain=x86-4.9 \
+        --install-dir=/android/ndk-x86-9 \
+        --ndk-dir=/android/android-ndk-r11c \
+        --arch=x86
+
+rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c
index e5619564b05d222516a1fb3c336a2623dc1ae925..e2ab6f636af9167e6245964f44ad9e1e83737a31 100644 (file)
@@ -27,9 +27,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index 5b94d5a972704ff9d30619ffdd6f27280b304bfc..5528b05104b8ec8cdf9db307a875b2bfd2721928 100644 (file)
@@ -27,9 +27,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index c39e298e3ceb09f909a840300e7fd2ee10800d2a..43e0734b74aedf321f52bdb8ea38df001dd5f66b 100644 (file)
@@ -25,9 +25,9 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini
     rm dumb-init_*.deb
 ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 ENV \
     AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \
index 5d8b3cfeae2a3116c3e1a5b1b04d250c3bc3b856..a99e9292df58a478470c4364b34433fd9117638c 100644 (file)
@@ -17,9 +17,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index 8feba12e72203db87de50a8e45defb9df0d07640..865d7ea5ea25fed4e13944c35ea0e08df9aa6c5b 100644 (file)
@@ -17,9 +17,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index e5ffbfc090d5ad9a32296fcd5b4b5c91eb9a9928..4ca39eae53f92b2b434287d5eddb9af76cc89a07 100644 (file)
@@ -27,9 +27,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index 7d13bc3d438bab213be729c2b0c170dc12cec096..2aeff7a0b90a5ed275b32d2ef5da38c0120e8530 100644 (file)
@@ -27,9 +27,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index 7f4c6d4647c7d5c83455a3b45c092d069a91d28b..79ffac73425f9f92001db39e9062327f7333a12e 100644 (file)
@@ -27,9 +27,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index f9324991aa06d12abb0db31603c218c1e8b49d28..3f6f71c41b520f887f091758b1e5a2fdd980ad28 100644 (file)
@@ -74,10 +74,9 @@ RUN curl -Lo /rustroot/dumb-init \
       chmod +x /rustroot/dumb-init
 ENTRYPOINT ["/rustroot/dumb-init", "--"]
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      xz --decompress | \
-      tar xf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 ENV HOSTS=i686-unknown-linux-gnu
 ENV HOSTS=$HOSTS,x86_64-unknown-linux-gnu
index 84e12eb6c3e11bd82e5004063b4dd9f3d968a45a..0757547bd2d33ef665878996c963ffcd70ac3f47 100644 (file)
@@ -14,9 +14,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils \
   lib32stdc++6
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index 1ffb24981c59aaa55d501dd3703057f1d12d3a3b..61f8e3dd06a45fe9b2ca3ab859c15e9f31593c01 100644 (file)
@@ -13,9 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index 84b98712b3385c6670e782ec5dd3f47ee6b966ac..1dcdc5591f56fdeada669d7b102439e4ab64b86f 100644 (file)
@@ -13,9 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index feb73bebbdbec0592eaed535b7e2c23ecb437378..a7060cd55fe64aeedaf79241c9c87ba291835c16 100644 (file)
@@ -25,15 +25,23 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini
     rm dumb-init_*.deb
 ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 ENV RUST_CONFIGURE_ARGS \
       --target=x86_64-unknown-linux-musl,i686-unknown-linux-musl,i586-unknown-linux-gnu \
       --musl-root-x86_64=/musl-x86_64 \
       --musl-root-i686=/musl-i686
 
+# Newer binutils broke things on some vms/distros (i.e., linking against
+# unknown relocs disabled by the following flag), so we need to go out of our
+# way to produce "super compatible" binaries.
+#
+# See: https://github.com/rust-lang/rust/issues/34978
+ENV CFLAGS_i686_unknown_linux_musl=-Wa,-mrelax-relocations=no \
+    CFLAGS_x86_64_unknown_linux_musl=-Wa,-mrelax-relocations=no
+
 ENV SCRIPT \
       python2.7 ../x.py test \
           --target x86_64-unknown-linux-musl \
index 260dc11509f4787b38758c13976b89945bc44ee4..ce62c392241d8306ee5c4f543453d2def07a1f07 100644 (file)
 
 set -ex
 
-export CFLAGS="-fPIC"
+# We need to mitigate rust-lang/rust#34978 when compiling musl itself as well
+export CFLAGS="-fPIC -Wa,-mrelax-relocations=no"
+export CXXFLAGS="-Wa,-mrelax-relocations=no"
+
 MUSL=musl-1.1.14
 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
 cd $MUSL
index 892c5baa5c64b03944f454e3759424c86ff3f083..1e61f2169106cdf63a2678db2a36c587df43ff35 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 # 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.
@@ -19,7 +19,9 @@ ci_dir="`dirname $docker_dir`"
 src_dir="`dirname $ci_dir`"
 root_dir="`dirname $src_dir`"
 
-docker \
+source "$ci_dir/shared.sh"
+
+retry docker \
   build \
   --rm \
   -t rust-ci \
index 607163ea547a302d1b487871ed908b4014d16b28..ac46a35a0bcfb5d938ec7fad58af397fde178e88 100644 (file)
@@ -14,9 +14,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index f54e4e562f889f694ea4ee917c911a9638d76819..1f577b4e8ae4e27d88b29f593afd48ffd032a687 100644 (file)
@@ -13,9 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index afa99ca2b8640e438bc4179b6a03e852930afc97..66cf2a5939f8b8a6bf95fc38d3b217854a62ebd4 100644 (file)
@@ -15,9 +15,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libssl-dev \
   pkg-config
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index 206103b92e94df6b037094d34397681c42c3df82..3919daeabaeef410cac9940a3b32d20cb0f1c1e4 100644 (file)
@@ -13,9 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index 3e084f4a3c30289384b4affe22c0e84e8385713f..b01b430cc68c4843d6c6af29b2a7a4a4f46c3d70 100644 (file)
@@ -13,9 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index aabfc0cd1bd8f2067f7b4ea13d18b56bc738a430..89c5a6c89d3a0c8e3d93e9f355dc7896b9031fb6 100644 (file)
@@ -16,9 +16,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   zlib1g-dev \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index d28dc3de1b494bdbfca54481019549f78cd82163..be731e2b0d8a89978d55fafeecf789afe2e8bbbf 100644 (file)
@@ -13,9 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index 427498fabb2d72943b2ea14e36c2f3fcbe1e43f9..02a8fb964ffd29c85d828d028d4fb29f48c8dc29 100644 (file)
@@ -13,9 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils
 
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
-      tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
     dpkg -i dumb-init_*.deb && \
index c4b255659936661c954d7a303191b6422b7d2efc..53d16f6239e66300823c282ccbf4ea0578907979 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 # 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.
@@ -20,6 +20,9 @@ if [ "$NO_CHANGE_USER" = "" ]; then
   fi
 fi
 
+ci_dir=`cd $(dirname $0) && pwd`
+source "$ci_dir/shared.sh"
+
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache"
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-quiet-tests"
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-manage-submodules"
@@ -54,9 +57,8 @@ else
   fi
 fi
 
-set -ex
-
 $SRC/configure $RUST_CONFIGURE_ARGS
+retry make prepare
 
 if [ "$TRAVIS_OS_NAME" = "osx" ]; then
     ncpus=$(sysctl -n hw.ncpu)
@@ -64,6 +66,8 @@ else
     ncpus=$(grep processor /proc/cpuinfo | wc -l)
 fi
 
+set -x
+
 if [ ! -z "$SCRIPT" ]; then
   sh -x -c "$SCRIPT"
 else
diff --git a/src/ci/shared.sh b/src/ci/shared.sh
new file mode 100644 (file)
index 0000000..ecd9b7e
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/bash
+# 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.
+
+# See http://unix.stackexchange.com/questions/82598
+function retry {
+  local n=1
+  local max=5
+  local delay=15
+  while true; do
+    echo "Attempting:" "$@"
+    "$@" && break || {
+      if [[ $n -lt $max ]]; then
+        ((n++))
+        echo "Command failed. Attempt $n/$max:"
+      else
+        echo "The command has failed after $n attempts."
+        exit 1
+      fi
+    }
+  done
+}
index a64178c26f237f914da56b421067f75c063a5ec0..afed379fe471ad8e16cd006ec3b5c0bd7b699c41 100644 (file)
@@ -36,7 +36,7 @@ down the channel and to the other thread. Therefore, we'd ensure that `Send` was
 implemented for that type.
 
 In the opposite way, if we were wrapping a library with [FFI][ffi] that isn't
-threadsafe, we wouldn't want to implement `Send`, and so the compiler will help
+thread-safe, we wouldn't want to implement `Send`, and so the compiler will help
 us enforce that it can't leave the current thread.
 
 [ffi]: ffi.html
index 25b4bd94799e0704a1f81f19cb305a4a9ec1c8e1..66a48566bd7c4256a39210c2a73f5d042f4539e2 100644 (file)
@@ -32,7 +32,7 @@ static N: i32 = 5;
 Unlike [`let`][let] bindings, you must annotate the type of a `static`.
 
 Statics live for the entire lifetime of a program, and therefore any
-reference stored in a constant has a [`'static` lifetime][lifetimes]:
+reference stored in a static has a [`'static` lifetime][lifetimes]:
 
 ```rust
 static NAME: &'static str = "Steve";
index cccefd8dfe73f5d1732586d45426578d3fc58dc3..e9e2dab73eff3f74d553c651e28f8acdd8aac21a 100644 (file)
@@ -408,7 +408,7 @@ libraries:
 * Static - `#[link(name = "my_build_dependency", kind = "static")]`
 * Frameworks - `#[link(name = "CoreFoundation", kind = "framework")]`
 
-Note that frameworks are only available on OSX targets.
+Note that frameworks are only available on macOS targets.
 
 The different `kind` values are meant to differentiate how the native library
 participates in linkage. From a linkage perspective, the Rust compiler creates
@@ -437,7 +437,7 @@ A few examples of how this model can be used are:
   is included in a final target (like a binary), the native library will be
   linked in.
 
-On OSX, frameworks behave with the same semantics as a dynamic library.
+On macOS, frameworks behave with the same semantics as a dynamic library.
 
 # Unsafe blocks
 
index eff77a54d8395c309f265a491750071e57afaff0..96c8e9f5d683423aca4aafef93b7c9aec840ff19 100644 (file)
@@ -230,6 +230,19 @@ If you want more information, you can get a backtrace by setting the
 ```text
 $ RUST_BACKTRACE=1 ./diverges
 thread 'main' panicked at 'This function never returns!', hello.rs:2
+Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
+stack backtrace:
+  hello::diverges
+        at ./hello.rs:2
+  hello::main
+        at ./hello.rs:6
+```
+
+If you want the complete backtrace and filenames:
+
+```text
+$ RUST_BACKTRACE=full ./diverges
+thread 'main' panicked at 'This function never returns!', hello.rs:2
 stack backtrace:
    1:     0x7f402773a829 - sys::backtrace::write::h0942de78b6c02817K8r
    2:     0x7f402773d7fc - panicking::on_panic::h3f23f9d0b5f4c91bu9w
@@ -262,7 +275,7 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace.
 `RUST_BACKTRACE` also works with Cargo’s `run` command:
 
 ```text
-$ RUST_BACKTRACE=1 cargo run
+$ RUST_BACKTRACE=full cargo run
      Running `target/debug/diverges`
 thread 'main' panicked at 'This function never returns!', hello.rs:2
 stack backtrace:
index 6208b1f4c123409f76683b6dd61c0742fc058117..06ea24fef3c1d66beb0b2f0ebd59847c9a0636a4 100644 (file)
@@ -167,7 +167,7 @@ fn main() {
 }
 ```
 
-Save the file, and go back to your terminal window. On Linux or OSX, enter the
+Save the file, and go back to your terminal window. On Linux or macOS, enter the
 following commands:
 
 ```bash
@@ -253,7 +253,7 @@ $ rustc main.rs
 
 If you come from a C or C++ background, you'll notice that this is similar to
 `gcc` or `clang`. After compiling successfully, Rust should output a binary
-executable, which you can see on Linux or OSX by entering the `ls` command in
+executable, which you can see on Linux or macOS by entering the `ls` command in
 your shell as follows:
 
 ```bash
index 7368d2184e5c2d73af831dce3ff7f774b3b95eee..4d81438b11deadfe9cfb3c7a8c587df46fd09747 100644 (file)
@@ -255,7 +255,7 @@ and other whitespace. This helps you split up long lines. We _could_ have
 done:
 
 ```rust,ignore
-    io::stdin().read_line(&mut guess).expect("failed to read line");
+    io::stdin().read_line(&mut guess).expect("Failed to read line");
 ```
 
 But that gets hard to read. So we’ve split it up, two lines for two method
@@ -473,7 +473,7 @@ fn main() {
     let mut guess = String::new();
 
     io::stdin().read_line(&mut guess)
-        .expect("failed to read line");
+        .expect("Failed to read line");
 
     println!("You guessed: {}", guess);
 }
@@ -563,7 +563,7 @@ fn main() {
     let mut guess = String::new();
 
     io::stdin().read_line(&mut guess)
-        .expect("failed to read line");
+        .expect("Failed to read line");
 
     println!("You guessed: {}", guess);
 
@@ -678,7 +678,7 @@ fn main() {
     let mut guess = String::new();
 
     io::stdin().read_line(&mut guess)
-        .expect("failed to read line");
+        .expect("Failed to read line");
 
     let guess: u32 = guess.trim().parse()
         .expect("Please type a number!");
@@ -780,7 +780,7 @@ fn main() {
         let mut guess = String::new();
 
         io::stdin().read_line(&mut guess)
-            .expect("failed to read line");
+            .expect("Failed to read line");
 
         let guess: u32 = guess.trim().parse()
             .expect("Please type a number!");
@@ -847,7 +847,7 @@ fn main() {
         let mut guess = String::new();
 
         io::stdin().read_line(&mut guess)
-            .expect("failed to read line");
+            .expect("Failed to read line");
 
         let guess: u32 = guess.trim().parse()
             .expect("Please type a number!");
@@ -892,7 +892,7 @@ fn main() {
         let mut guess = String::new();
 
         io::stdin().read_line(&mut guess)
-            .expect("failed to read line");
+            .expect("Failed to read line");
 
         let guess: u32 = match guess.trim().parse() {
             Ok(num) => num,
@@ -981,7 +981,7 @@ fn main() {
         let mut guess = String::new();
 
         io::stdin().read_line(&mut guess)
-            .expect("failed to read line");
+            .expect("Failed to read line");
 
         let guess: u32 = match guess.trim().parse() {
             Ok(num) => num,
index 17bf13690009f35361b7c254f624017505ecc923..9eeac3d687ebfaa85398977c0c32421a9383e481 100644 (file)
@@ -1,6 +1,6 @@
 # if let
 
-`if let` permits [patterns][pattern] matching within the condition of an [if][if] statement.
+`if let` permits [patterns][patterns] matching within the condition of an [if][if] statement.
 This allows us to reduce the overhead of certain kinds of [pattern][patterns] matches
 and express them in a more convenient way.  
 
index 8bca13c28f0bd2b2def24b6dc7b1ed8bbdc28abd..042d9af9717d052a705f8f183bb4e998add2b0d4 100644 (file)
@@ -349,8 +349,8 @@ to it.
 
 ## Lifetime Elision
 
-Rust supports powerful local type inference in the bodies of functions but not in their item signatures. 
-It's forbidden to allow reasoning about types based on the item signature alone
+Rust supports powerful local type inference in the bodies of functions, but it
+deliberately does not perform any reasoning about types for item signatures
 However, for ergonomic reasons, a very restricted secondary inference algorithm called 
 “lifetime elision” does apply when judging lifetimes. Lifetime elision is concerned solely with inferring 
 lifetime parameters using three easily memorizable and unambiguous rules. This means lifetime elision 
index ec4acfa311230b862c1e31c8c6bd52a7660b030e..b7658d57a9e16c36d854a7aaf159d6044399a8ba 100644 (file)
@@ -100,7 +100,8 @@ developers.
 
 ### Enumerate
 
-When you need to keep track of how many times you already looped, you can use the `.enumerate()` function.
+When you need to keep track of how many times you have already looped, you can
+use the `.enumerate()` function.
 
 #### On ranges:
 
index 079324d56d1e662ea82e280f2415155f902452b4..e02b5a6cdd79b8c27ad66bf7c675bd71c47880e5 100644 (file)
@@ -128,7 +128,7 @@ pub fn hello_world(input: TokenStream) -> TokenStream {
 So there is a lot going on here. We have introduced two new crates: [`syn`] and
 [`quote`]. As you may have noticed, `input: TokenSteam` is immediately converted
 to a `String`. This `String` is a string representation of the Rust code for which
-we are deriving `HelloWorld` for. At the moment, the only thing you can do with a
+we are deriving `HelloWorld`. At the moment, the only thing you can do with a
 `TokenStream` is convert it to a string. A richer API will exist in the future.
 
 So what we really need is to be able to _parse_ Rust code into something
@@ -170,7 +170,7 @@ a representation of our type (which can be either a `struct` or an `enum`).
 Check out the [docs](https://docs.rs/syn/0.10.5/syn/struct.MacroInput.html),
 there is some useful information there. We are able to get the name of the
 type using `ast.ident`. The `quote!` macro lets us write up the Rust code
-that we wish to return and convert it into `Tokens`. `quote!` let's us use some
+that we wish to return and convert it into `Tokens`. `quote!` lets us use some
 really cool templating mechanics; we simply write `#name` and `quote!` will
 replace it with the variable named `name`. You can even do some repetition
 similar to regular macros work. You should check out the
@@ -211,3 +211,76 @@ Hello, World! My name is Waffles
 ```
 
 We've done it!
+
+## Custom Attributes
+
+In some cases it might make sense to allow users some kind of configuration.
+For example, the user might want to overwrite the name that is printed in the `hello_world()` method.
+
+This can be achieved with custom attributes:
+
+```rust,ignore
+#[derive(HelloWorld)]
+#[HelloWorldName = "the best Pancakes"]
+struct Pancakes;
+
+fn main() {
+    Pancakes::hello_world();
+}
+```
+
+If we try to compile this though, the compiler will respond with an error:
+
+```bash
+error: The attribute `HelloWorldName` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
+```
+
+The compiler needs to know that we're handling this attribute and to not respond with an error.
+This is done in the `hello-world-derive` crate by adding `attributes` to the `proc_macro_derive` attribute:
+
+```rust,ignore
+#[proc_macro_derive(HelloWorld, attributes(HelloWorldName))]
+pub fn hello_world(input: TokenStream) -> TokenStream 
+```
+
+Multiple attributes can be specified that way.
+
+## Raising Errors
+
+Let's assume that we do not want to accept enums as input to our custom derive method.
+
+This condition can be easily checked with the help of `syn`. 
+But how do we tell the user, that we do not accept enums?
+The idiomatic way to report errors in procedural macros is to panic:
+
+```rust,ignore
+fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens {
+    let name = &ast.ident;
+    // Check if derive(HelloWorld) was specified for a struct
+    if let syn::Body::Struct(_) = ast.body {
+        // Yes, this is a struct
+        quote! {
+            impl HelloWorld for #name {
+                fn hello_world() {
+                    println!("Hello, World! My name is {}", stringify!(#name));
+                }
+            }
+        }
+    } else {
+        //Nope. This is an Enum. We cannot handle these!
+       panic!("#[derive(HelloWorld)] is only defined for structs, not for enums!");
+    }
+}
+```
+
+If a user now tries to derive `HelloWorld` from an enum they will be greeted with following, hopefully helpful, error:
+
+```bash
+error: custom derive attribute panicked
+  --> src/main.rs
+   |
+   | #[derive(HelloWorld)]
+   |          ^^^^^^^^^^
+   |
+   = help: message: #[derive(HelloWorld)] is only defined for structs, not for enums!
+```
index ac41be11854b89603c4ffc519a49a470f5f638d7..ffc9d2b6976843fc312741d969e0fb5a33dc89e7 100644 (file)
@@ -145,7 +145,7 @@ This emphasizes that we have to walk from the beginning of the list of `chars`.
 
 ## Slicing
 
-You can get a slice of a string with slicing syntax:
+You can get a slice of a string with the slicing syntax:
 
 ```rust
 let dog = "hachiko";
index 6b2a145c85e512ffdf9d14733bf01509c9eda522..3efa4f0e0a8d85898551218a9e9212d305e0d58b 100644 (file)
@@ -88,7 +88,7 @@ fn main() {
 }
 ```
 
-Your structure can still contain `&mut` pointers, which will let
+Your structure can still contain `&mut` references, which will let
 you do some kinds of mutation:
 
 ```rust
@@ -255,13 +255,14 @@ rather than positions.
 
 You can define a `struct` with no members at all:
 
-```rust
+```rust,compile_fail,E0423
 struct Electron {} // Use empty braces...
 struct Proton;     // ...or just a semicolon.
 
-// Whether you declared the struct with braces or not, do the same when creating one.
+// Use the same notation when creating an instance.
 let x = Electron {};
 let y = Proton;
+let z = Electron; // Error
 ```
 
 Such a `struct` is called ‘unit-like’ because it resembles the empty
index b9b3b801eae58abaa264bf9709778af5a1e9005e..6866505df1310e8de0d3d6c2e441e988fd8aaf82 100644 (file)
@@ -86,7 +86,7 @@ to a large number, representing how much RAM your computer has. For example, if
 you have a gigabyte of RAM, your addresses go from `0` to `1,073,741,823`. That
 number comes from 2<sup>30</sup>, the number of bytes in a gigabyte. [^gigabyte]
 
-[^gigabyte]: ‘Gigabyte’ can mean two things: 10^9, or 2^30. The SI standard resolved this by stating that ‘gigabyte’ is 10^9, and ‘gibibyte’ is 2^30. However, very few people use this terminology, and rely on context to differentiate. We follow in that tradition here.
+[^gigabyte]: ‘Gigabyte’ can mean two things: 10<sup>9</sup>, or 2<sup>30</sup>. The IEC standard resolved this by stating that ‘gigabyte’ is 10<sup>9</sup>, and ‘gibibyte’ is 2<sup>30</sup>. However, very few people use this terminology, and rely on context to differentiate. We follow in that tradition here.
 
 This memory is kind of like a giant array: addresses start at zero and go
 up to the final number. So here’s a diagram of our first stack frame:
index 80e72cd5e36c94404ab2b2be8da6c3e7a20ebf02..a3cbc6abd69cc98023f139e408d15aab03007dc8 100644 (file)
@@ -93,7 +93,7 @@ uselessly. We would rather have the following:
 ```text
 bubble_up(heap, index):
     let elem = heap[index]
-    while index != 0 && element < heap[parent(index)]:
+    while index != 0 && elem < heap[parent(index)]:
         heap[index] = heap[parent(index)]
         index = parent(index)
     heap[index] = elem
@@ -137,7 +137,7 @@ If Rust had `try` and `finally` like in Java, we could do the following:
 bubble_up(heap, index):
     let elem = heap[index]
     try:
       while index != 0 && element < heap[parent(index)]:
       while index != 0 && elem < heap[parent(index)]:
             heap[index] = heap[parent(index)]
             index = parent(index)
     finally:
index 72fa2e2a77764e73319b5a0fbc024b9ad78abdb1..32539c2d01f6dcd9e9488cfae80f02f0be929db6 100644 (file)
@@ -82,5 +82,23 @@ standard library made a utility for itself called `Unique<T>` which:
 
 * wraps a `*const T` for variance
 * includes a `PhantomData<T>`
-* auto-derives Send/Sync as if T was contained
-* marks the pointer as NonZero for the null-pointer optimization
+* auto-derives `Send`/`Sync` as if T was contained
+* marks the pointer as `NonZero` for the null-pointer optimization
+
+## Table of `PhantomData` patterns
+
+Here’s a table of all the wonderful ways `PhantomData` could be used:
+
+| Phantom type                | `'a`      | `T`                       |
+|-----------------------------|-----------|---------------------------|
+| `PhantomData<T>`            | -         | variant (with drop check) |
+| `PhantomData<&'a T>`        | variant   | variant                   |
+| `PhantomData<&'a mut T>`    | variant   | invariant                 |
+| `PhantomData<*const T>`     | -         | variant                   |
+| `PhantomData<*mut T>`       | -         | invariant                 |
+| `PhantomData<fn(T)>`        | -         | contravariant (*)         |
+| `PhantomData<fn() -> T>`    | -         | variant                   |
+| `PhantomData<fn(T) -> T>`   | -         | invariant                 |
+| `PhantomData<Cell<&'a ()>>` | invariant | -                         |
+
+(*) If contravariance gets scrapped, this would be invariant.
index 8f3fdbf3679c1ada9fed4140d05ffc6f44a540aa..31814ef8c5794650ceb16d7b42542acd42214e55 100644 (file)
@@ -219,7 +219,7 @@ command line using `--cfg` (e.g. `rustc main.rs --cfg foo --cfg 'bar="baz"'`).
 Rust code then checks for their presence using the `#[cfg(...)]` attribute:
 
 ```
-// The function is only included in the build when compiling for OSX
+// The function is only included in the build when compiling for macOS
 #[cfg(target_os = "macos")]
 fn macos_only() {
   // ...
index 4755e4be8b685e91d6da895f59bd6094392d6bca..28297a8ec1f36368d02d3dc0ce816c34510f3513 100644 (file)
@@ -46,7 +46,7 @@ be ignored in favor of only building the artifacts specified by command line.
 * `--crate-type=cdylib`, `#[crate_type = "cdylib"]` - A dynamic system
   library will be produced.  This is used when compiling Rust code as
   a dynamic library to be loaded from another language.  This output type will
-  create `*.so` files on Linux, `*.dylib` files on OSX, and `*.dll` files on
+  create `*.so` files on Linux, `*.dylib` files on macOS, and `*.dll` files on
   Windows.
 
 * `--crate-type=rlib`, `#[crate_type = "rlib"]` - A "Rust library" file will be
index ee8ae9a9839e9f409b38d15cce65baa1df64d908..5fb323d6ce90950bf2150ee05ac16255e097cae7 100644 (file)
@@ -1,94 +1,95 @@
 [The Unstable Book](the-unstable-book.md)
 
-- [asm](asm.md)
-- [alloc_system](alloc-system.md)
+- [abi_msp430_interrupt](abi-msp430-interrupt.md)
+- [abi_ptx](abi-ptx.md)
+- [abi_sysv64](abi-sysv64.md)
+- [abi_unadjusted](abi-unadjusted.md)
+- [abi_vectorcall](abi-vectorcall.md)
+- [abi_x86_interrupt](abi-x86-interrupt.md)
+- [advanced_slice_patterns](advanced-slice-patterns.md)
 - [alloc_jemalloc](alloc-jemalloc.md)
-- [test](test.md)
+- [alloc_system](alloc-system.md)
+- [allocator](allocator.md)
+- [allow_internal_unstable](allow-internal-unstable.md)
+- [asm](asm.md)
+- [associated_consts](associated-consts.md)
+- [associated_type_defaults](associated-type-defaults.md)
+- [attr_literals](attr-literals.md)
+- [box_patterns](box-patterns.md)
+- [box_syntax](box-syntax.md)
+- [cfg_target_feature](cfg-target-feature.md)
+- [cfg_target_has_atomic](cfg-target-has-atomic.md)
+- [cfg_target_thread_local](cfg-target-thread-local.md)
+- [cfg_target_vendor](cfg-target-vendor.md)
+- [compiler_builtins](compiler-builtins.md)
 - [concat_idents](concat-idents.md)
-- [link_args](link-args.md)
-- [log_syntax](log-syntax.md)
-- [non_ascii_idents](non-ascii-idents.md)
-- [plugin_registrar](plugin-registrar.md)
-- [thread_local](thread-local.md)
-- [trace_macros](trace-macros.md)
+- [conservative_impl_trait](conservative-impl-trait.md)
+- [const_fn](const-fn.md)
+- [const_indexing](const-indexing.md)
+- [custom_attribute](custom-attribute.md)
+- [custom_derive](custom-derive.md)
+- [default_type_parameter_fallback](default-type-parameter-fallback.md)
+- [drop_types_in_const](drop-types-in-const.md)
+- [dropck_eyepatch](dropck-eyepatch.md)
+- [dropck_parametricity](dropck-parametricity.md)
+- [exclusive_range_pattern](exclusive-range-pattern.md)
+- [field_init_shorthand](field-init-shorthand.md)
+- [fundamental](fundamental.md)
+- [generic_param_attrs](generic-param-attrs.md)
+- [i128_type](i128-type.md)
+- [inclusive_range_syntax](inclusive-range-syntax.md)
 - [intrinsics](intrinsics.md)
 - [lang_items](lang-items.md)
+- [link_args](link-args.md)
+- [link_cfg](link-cfg.md)
 - [link_llvm_intrinsics](link-llvm-intrinsics.md)
 - [linkage](linkage.md)
-- [quote](quote.md)
-- [simd](simd.md)
-- [rustc_diagnostic_macros](rustc-diagnostic-macros.md)
-- [advanced_slice_patterns](advanced-slice-patterns.md)
-- [box_syntax](box-syntax.md)
-- [placement_in_syntax](placement-in-syntax.md)
-- [unboxed_closures](unboxed-closures.md)
-- [allocator](allocator.md)
-- [fundamental](fundamental.md)
+- [log_syntax](log-syntax.md)
+- [loop_break_value](loop-break-value.md)
+- [macro_reexport](macro-reexport.md)
 - [main](main.md)
+- [naked_functions](naked-functions.md)
 - [needs_allocator](needs-allocator.md)
-- [on_unimplemented](on-unimplemented.md)
-- [plugin](plugin.md)
-- [simd_ffi](simd-ffi.md)
-- [start](start.md)
-- [structural_match](structural-match.md)
-- [panic_runtime](panic-runtime.md)
 - [needs_panic_runtime](needs-panic-runtime.md)
-- [optin_builtin_traits](optin-builtin-traits.md)
-- [macro_reexport](macro-reexport.md)
-- [staged_api](staged-api.md)
+- [never_type](never-type.md)
 - [no_core](no-core.md)
-- [box_patterns](box-patterns.md)
-- [dropck_parametricity](dropck-parametricity.md)
-- [dropck_eyepatch](dropck-eyepatch.md)
-- [custom_attribute](custom-attribute.md)
-- [custom_derive](custom-derive.md)
+- [no_debug](no-debug.md)
+- [non_ascii_idents](non-ascii-idents.md)
+- [omit_gdb_pretty_printer_section](omit-gdb-pretty-printer-section.md)
+- [on_unimplemented](on-unimplemented.md)
+- [optin_builtin_traits](optin-builtin-traits.md)
+- [panic_runtime](panic-runtime.md)
+- [placement_in_syntax](placement-in-syntax.md)
+- [platform_intrinsics](platform-intrinsics.md)
+- [plugin](plugin.md)
+- [plugin_registrar](plugin-registrar.md)
+- [prelude_import](prelude-import.md)
+- [proc_macro](proc-macro.md)
+- [pub_restricted](pub-restricted.md)
+- [quote](quote.md)
+- [relaxed_adts](relaxed-adts.md)
+- [repr_simd](repr-simd.md)
 - [rustc_attrs](rustc-attrs.md)
-- [allow_internal_unstable](allow-internal-unstable.md)
+- [rustc_diagnostic_macros](rustc-diagnostic-macros.md)
+- [sanitizer_runtime](sanitizer-runtime.md)
+- [simd](simd.md)
+- [simd_ffi](simd-ffi.md)
 - [slice_patterns](slice-patterns.md)
-- [associated_consts](associated-consts.md)
-- [const_fn](const-fn.md)
-- [const_indexing](const-indexing.md)
-- [prelude_import](prelude-import.md)
+- [specialization](specialization.md)
+- [staged_api](staged-api.md)
+- [start](start.md)
+- [static_nobundle](static-nobundle.md)
 - [static_recursion](static-recursion.md)
-- [default_type_parameter_fallback](default-type-parameter-fallback.md)
-- [associated_type_defaults](associated-type-defaults.md)
-- [repr_simd](repr-simd.md)
-- [cfg_target_feature](cfg-target-feature.md)
-- [platform_intrinsics](platform-intrinsics.md)
-- [unwind_attributes](unwind-attributes.md)
-- [naked_functions](naked-functions.md)
-- [no_debug](no-debug.md)
-- [omit_gdb_pretty_printer_section](omit-gdb-pretty-printer-section.md)
-- [cfg_target_vendor](cfg-target-vendor.md)
 - [stmt_expr_attributes](stmt-expr-attributes.md)
+- [struct_field_attributes](struct-field-attributes.md)
+- [structural_match](structural-match.md)
+- [target_feature](target-feature.md)
+- [test](test.md)
+- [thread_local](thread-local.md)
+- [trace_macros](trace-macros.md)
 - [type_ascription](type-ascription.md)
-- [cfg_target_thread_local](cfg-target-thread-local.md)
-- [abi_vectorcall](abi-vectorcall.md)
-- [inclusive_range_syntax](inclusive-range-syntax.md)
-- [exclusive_range_pattern](exclusive-range-pattern.md)
-- [specialization](specialization.md)
-- [pub_restricted](pub-restricted.md)
-- [drop_types_in_const](drop-types-in-const.md)
-- [cfg_target_has_atomic](cfg-target-has-atomic.md)
-- [conservative_impl_trait](conservative-impl-trait.md)
-- [relaxed_adts](relaxed-adts.md)
-- [never_type](never-type.md)
-- [attr_literals](attr-literals.md)
-- [abi_sysv64](abi-sysv64.md)
+- [unboxed_closures](unboxed-closures.md)
 - [untagged_unions](untagged-unions.md)
-- [compiler_builtins](compiler-builtins.md)
-- [generic_param_attrs](generic-param-attrs.md)
-- [field_init_shorthand](field-init-shorthand.md)
-- [windows_subsystem](windows-subsystem.md)
-- [link_cfg](link-cfg.md)
+- [unwind_attributes](unwind-attributes.md)
 - [use_extern_macros](use-extern-macros.md)
-- [loop_break_value](loop-break-value.md)
-- [target_feature](target-feature.md)
-- [abi_ptx](abi-ptx.md)
-- [i128_type](i128-type.md)
-- [abi_unadjusted](abi-unadjusted.md)
-- [proc_macro](proc-macro.md)
-- [struct_field_attributes](struct-field-attributes.md)
-- [static_nobundle](static-nobundle.md)
-- [abi_msp430_interrupt](abi-msp430-interrupt.md)
-- [sanitizer_runtime](sanitizer-runtime.md)
+- [windows_subsystem](windows-subsystem.md)
diff --git a/src/doc/unstable-book/src/abi-x86-interrupt.md b/src/doc/unstable-book/src/abi-x86-interrupt.md
new file mode 100644 (file)
index 0000000..c89d2ee
--- /dev/null
@@ -0,0 +1,7 @@
+# `abi_x86_interrupt`
+
+The tracking issue for this feature is: [#40180]
+
+[#40180]: https://github.com/rust-lang/rust/issues/40180
+
+------------------------
index bd74848a01d8362f150b23701c6af47359f10f8f..dfd292176d2f9c9bd67445291b3c68d7dad9a23e 100644 (file)
@@ -62,7 +62,7 @@
 //!
 //! A format string is required to use all of its arguments, otherwise it is a
 //! compile-time error. You may refer to the same argument more than once in the
-//! format string, although it must always be referred to with the same type.
+//! format string.
 //!
 //! ## Named parameters
 //!
 //!
 //! ## Argument types
 //!
-//! Each argument's type is dictated by the format string. It is a requirement
-//! that every argument is only ever referred to by one type. For example, this
-//! is an invalid format string:
-//!
-//! ```text
-//! {0:x} {0:o}
-//! ```
-//!
-//! This is invalid because the first argument is both referred to as a
-//! hexadecimal as well as an
-//! octal.
-//!
-//! There are various parameters which do require a particular type, however.
+//! Each argument's type is dictated by the format string.
+//! There are various parameters which require a particular type, however.
 //! An example is the `{:.*}` syntax, which sets the number of decimal places
 //! in floating-point types:
 //!
 //!
 //! If this syntax is used, then the number of characters to print precedes the
 //! actual object being formatted, and the number of characters must have the
-//! type `usize`. Although a `usize` can be printed with `{}`, it is invalid to
-//! reference an argument as such. For example this is another invalid format
-//! string:
-//!
-//! ```text
-//! {:.*} {0}
-//! ```
+//! type `usize`.
 //!
 //! ## Formatting traits
 //!
 pub fn format(args: Arguments) -> string::String {
     let capacity = args.estimated_capacity();
     let mut output = string::String::with_capacity(capacity);
-    let _ = output.write_fmt(args);
+    output.write_fmt(args)
+          .expect("a formatting trait implementation returned an error");
     output
 }
index 3115be00a4d720094fe846219a7d8d91470d924f..396a917dfde261f87ba8823e17c533f2d0f8f660 100644 (file)
@@ -72,6 +72,12 @@ macro_rules! vec {
 ///
 /// [fmt]: ../std/fmt/index.html
 ///
+/// # Panics
+///
+/// `format!` panics if a formatting trait implementation returns an error.
+/// This indicates an incorrect implementation
+/// since `fmt::Write for String` never returns an error itself.
+///
 /// # Examples
 ///
 /// ```
index 1df4ace377707d286fafc9a243a65c9557d30d12..e4b94a1d70ee4189fe3ce610721aa52cf0bd096c 100644 (file)
@@ -14,7 +14,7 @@
 
 //! Range syntax.
 
-use core::ops::{RangeFull, Range, RangeTo, RangeFrom};
+use core::ops::{RangeFull, Range, RangeTo, RangeFrom, RangeInclusive, RangeToInclusive};
 use Bound::{self, Excluded, Included, Unbounded};
 
 /// **RangeArgument** is implemented by Rust's built-in range types, produced
@@ -105,6 +105,32 @@ fn end(&self) -> Bound<&T> {
     }
 }
 
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl<T> RangeArgument<T> for RangeInclusive<T> {
+    fn start(&self) -> Bound<&T> {
+        match *self {
+            RangeInclusive::Empty{ ref at }            => Included(at),
+            RangeInclusive::NonEmpty { ref start, .. } => Included(start),
+        }
+    }
+    fn end(&self) -> Bound<&T> {
+        match *self {
+            RangeInclusive::Empty{ ref at }            => Excluded(at),
+            RangeInclusive::NonEmpty { ref end, .. }   => Included(end),
+        }
+    }
+}
+
+#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+impl<T> RangeArgument<T> for RangeToInclusive<T> {
+    fn start(&self) -> Bound<&T> {
+        Unbounded
+    }
+    fn end(&self) -> Bound<&T> {
+        Included(&self.end)
+    }
+}
+
 impl<T> RangeArgument<T> for (Bound<T>, Bound<T>) {
     fn start(&self) -> Bound<&T> {
         match *self {
index e92eb4ff7bdd4b565b4a81543e09b366d9230dae..f2e4be49684a91af99a761ee4305bc7f9d4a2fd5 100644 (file)
@@ -999,6 +999,9 @@ pub fn as_bytes(&self) -> &[u8] {
     /// If `new_len` is greater than the string's current length, this has no
     /// effect.
     ///
+    /// Note that this method has no effect on the allocated capacity
+    /// of the string
+    ///
     /// # Panics
     ///
     /// Panics if `new_len` does not lie on a [`char`] boundary.
@@ -1480,6 +1483,15 @@ fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> String {
     }
 }
 
+#[stable(feature = "string_from_iter_by_ref", since = "1.17.0")]
+impl<'a> FromIterator<&'a char> for String {
+    fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> String {
+        let mut buf = String::new();
+        buf.extend(iter);
+        buf
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> FromIterator<&'a str> for String {
     fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> String {
@@ -1629,6 +1641,43 @@ fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
     }
 }
 
+/// Implements the `+` operator for concatenating two strings.
+///
+/// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if
+/// necessary). This is done to avoid allocating a new `String` and copying the entire contents on
+/// every operation, which would lead to `O(n^2)` running time when building an `n`-byte string by
+/// repeated concatenation.
+///
+/// The string on the right-hand side is only borrowed; its contents are copied into the returned
+/// `String`.
+///
+/// # Examples
+///
+/// Concatenating two `String`s takes the first by value and borrows the second:
+///
+/// ```
+/// let a = String::from("hello");
+/// let b = String::from(" world");
+/// let c = a + &b;
+/// // `a` is moved and can no longer be used here.
+/// ```
+///
+/// If you want to keep using the first `String`, you can clone it and append to the clone instead:
+///
+/// ```
+/// let a = String::from("hello");
+/// let b = String::from(" world");
+/// let c = a.clone() + &b;
+/// // `a` is still valid here.
+/// ```
+///
+/// Concatenating `&str` slices can be done by converting the first to a `String`:
+///
+/// ```
+/// let a = "hello";
+/// let b = " world";
+/// let c = a.to_string() + b;
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> Add<&'a str> for String {
     type Output = String;
@@ -1640,6 +1689,11 @@ fn add(mut self, other: &str) -> String {
     }
 }
 
+/// Implements the `+=` operator for appending to a `String`.
+///
+/// This has the same behavior as the [`push_str()`] method.
+///
+/// [`push_str()`]: struct.String.html#method.push_str
 #[stable(feature = "stringaddassign", since = "1.12.0")]
 impl<'a> AddAssign<&'a str> for String {
     #[inline]
@@ -1846,13 +1900,20 @@ pub trait ToString {
     fn to_string(&self) -> String;
 }
 
+/// # Panics
+///
+/// In this implementation, the `to_string` method panics
+/// if the `Display` implementation returns an error.
+/// This indicates an incorrect `Display` implementation
+/// since `fmt::Write for String` never returns an error itself.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: fmt::Display + ?Sized> ToString for T {
     #[inline]
     default fn to_string(&self) -> String {
         use core::fmt::Write;
         let mut buf = String::new();
-        let _ = buf.write_fmt(format_args!("{}", self));
+        buf.write_fmt(format_args!("{}", self))
+           .expect("a Display implementation return an error unexpectedly");
         buf.shrink_to_fit();
         buf
     }
index 9e3f117f9b20e15e2b0dc85f7137bed975b4dd18..3134e3c2ce12f802f56016d207317265208d0fb7 100644 (file)
@@ -548,6 +548,9 @@ pub fn into_boxed_slice(mut self) -> Box<[T]> {
     /// The [`drain`] method can emulate `truncate`, but causes the excess
     /// elements to be returned instead of dropped.
     ///
+    /// Note that this method has no effect on the allocated capacity
+    /// of the vector.
+    ///
     /// # Examples
     ///
     /// Truncating a five element vector to two elements:
@@ -1092,6 +1095,9 @@ pub fn drain<R>(&mut self, range: R) -> Drain<T>
 
     /// Clears the vector, removing all values.
     ///
+    /// Note that this method has no effect on the allocated capacity
+    /// of the vector.
+    ///
     /// # Examples
     ///
     /// ```
@@ -1776,6 +1782,7 @@ macro_rules! array_impls {
     30 31 32
 }
 
+/// Implements comparison of vectors, lexicographically.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: PartialOrd> PartialOrd for Vec<T> {
     #[inline]
@@ -1787,6 +1794,7 @@ fn partial_cmp(&self, other: &Vec<T>) -> Option<Ordering> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Eq> Eq for Vec<T> {}
 
+/// Implements ordering of vectors, lexicographically.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Ord> Ord for Vec<T> {
     #[inline]
index f33923f99631911fc4752262235314528361a9b9..2c899d96940ece9e222adc3ff21600f7f164c708 100644 (file)
@@ -178,6 +178,43 @@ fn test_range_small() {
     assert_eq!(j, size - 2);
 }
 
+#[test]
+fn test_range_inclusive() {
+    let size = 500;
+
+    let map: BTreeMap<_, _> = (0...size).map(|i| (i, i)).collect();
+
+    fn check<'a, L, R>(lhs: L, rhs: R)
+        where L: IntoIterator<Item=(&'a i32, &'a i32)>,
+              R: IntoIterator<Item=(&'a i32, &'a i32)>,
+    {
+        let lhs: Vec<_> = lhs.into_iter().collect();
+        let rhs: Vec<_> = rhs.into_iter().collect();
+        assert_eq!(lhs, rhs);
+    }
+
+    check(map.range(size + 1...size + 1), vec![]);
+    check(map.range(size...size), vec![(&size, &size)]);
+    check(map.range(size...size + 1), vec![(&size, &size)]);
+    check(map.range(0...0), vec![(&0, &0)]);
+    check(map.range(0...size - 1), map.range(..size));
+    check(map.range(-1...-1), vec![]);
+    check(map.range(-1...size), map.range(..));
+    check(map.range(...size), map.range(..));
+    check(map.range(...200), map.range(..201));
+    check(map.range(5...8), vec![(&5, &5), (&6, &6), (&7, &7), (&8, &8)]);
+    check(map.range(-1...0), vec![(&0, &0)]);
+    check(map.range(-1...2), vec![(&0, &0), (&1, &1), (&2, &2)]);
+}
+
+#[test]
+fn test_range_inclusive_max_value() {
+    let max = ::std::usize::MAX;
+    let map: BTreeMap<_, _> = vec![(max, 0)].into_iter().collect();
+
+    assert_eq!(map.range(max...max).collect::<Vec<_>>(), &[(&max, &0)]);
+}
+
 #[test]
 fn test_range_equal_empty_cases() {
     let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
index 57e3c2df059e122775f7d98f0c082980a7a4c7bb..849d2401691691eb013d0e57736fd29db0d5a496 100644 (file)
@@ -14,6 +14,7 @@
 #![feature(binary_heap_peek_mut_pop)]
 #![feature(box_syntax)]
 #![feature(btree_range)]
+#![feature(inclusive_range_syntax)]
 #![feature(collection_placement)]
 #![feature(collections)]
 #![feature(collections_bound)]
index edeedf1d40baf3d37b38d6c36928945c7828558a..06d70800d392560e8c99e44fd65edc878c95a114 100644 (file)
@@ -507,6 +507,56 @@ fn test_drain_range() {
     assert_eq!(v, &[(), ()]);
 }
 
+#[test]
+fn test_drain_inclusive_range() {
+    let mut v = vec!['a', 'b', 'c', 'd', 'e'];
+    for _ in v.drain(1...3) {
+    }
+    assert_eq!(v, &['a', 'e']);
+
+    let mut v: Vec<_> = (0...5).map(|x| x.to_string()).collect();
+    for _ in v.drain(1...5) {
+    }
+    assert_eq!(v, &["0".to_string()]);
+
+    let mut v: Vec<String> = (0...5).map(|x| x.to_string()).collect();
+    for _ in v.drain(0...5) {
+    }
+    assert_eq!(v, Vec::<String>::new());
+
+    let mut v: Vec<_> = (0...5).map(|x| x.to_string()).collect();
+    for _ in v.drain(0...3) {
+    }
+    assert_eq!(v, &["4".to_string(), "5".to_string()]);
+
+    let mut v: Vec<_> = (0...1).map(|x| x.to_string()).collect();
+    for _ in v.drain(...0) {
+    }
+    assert_eq!(v, &["1".to_string()]);
+}
+
+#[test]
+fn test_drain_max_vec_size() {
+    let mut v = Vec::<()>::with_capacity(usize::max_value());
+    unsafe { v.set_len(usize::max_value()); }
+    for _ in v.drain(usize::max_value() - 1..) {
+    }
+    assert_eq!(v.len(), usize::max_value() - 1);
+
+    let mut v = Vec::<()>::with_capacity(usize::max_value());
+    unsafe { v.set_len(usize::max_value()); }
+    for _ in v.drain(usize::max_value() - 1...usize::max_value() - 1) {
+    }
+    assert_eq!(v.len(), usize::max_value() - 1);
+}
+
+#[test]
+#[should_panic]
+fn test_drain_inclusive_out_of_bounds() {
+    let mut v = vec![1, 2, 3, 4, 5];
+    v.drain(5...5);
+}
+
 #[test]
 fn test_into_boxed_slice() {
     let xs = vec![1, 2, 3];
index 5360bbdeacd6ad280b93535ed6a6fc5de949dd15..16ecf88256670233c9f1f543ebe05f46f11abd61 100644 (file)
@@ -92,7 +92,15 @@ fn main() {
         // compiler-rt's build system already
         cfg.flag("-fno-builtin");
         cfg.flag("-fvisibility=hidden");
-        cfg.flag("-fomit-frame-pointer");
+        // Accepted practice on Solaris is to never omit frame pointer so that
+        // system observability tools work as expected.  In addition, at least
+        // on Solaris, -fomit-frame-pointer on sparcv9 appears to generate
+        // references to data outside of the current stack frame.  A search of
+        // the gcc bug database provides a variety of issues surrounding
+        // -fomit-frame-pointer on non-x86 platforms.
+        if !target.contains("solaris") && !target.contains("sparc") {
+            cfg.flag("-fomit-frame-pointer");
+        }
         cfg.flag("-ffreestanding");
         cfg.define("VISIBILITY_HIDDEN", None);
     }
index e6c9e1ed38e4fb49f5dba56764538ad5bc6732aa..dc5a662cdb0445fea0fca104923710cb80fbaec8 100644 (file)
@@ -65,12 +65,15 @@ pub mod rt {
 /// A collection of methods that are required to format a message into a stream.
 ///
 /// This trait is the type which this modules requires when formatting
-/// information. This is similar to the standard library's `io::Write` trait,
+/// information. This is similar to the standard library's [`io::Write`] trait,
 /// but it is only intended for use in libcore.
 ///
 /// This trait should generally not be implemented by consumers of the standard
-/// library. The `write!` macro accepts an instance of `io::Write`, and the
-/// `io::Write` trait is favored over implementing this trait.
+/// library. The [`write!`] macro accepts an instance of [`io::Write`], and the
+/// [`io::Write`] trait is favored over implementing this trait.
+///
+/// [`write!`]: ../../std/macro.write.html
+/// [`io::Write`]: ../../std/io/trait.Write.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Write {
     /// Writes a slice of bytes into this writer, returning whether the write
@@ -82,29 +85,79 @@ pub trait Write {
     ///
     /// # Errors
     ///
-    /// This function will return an instance of `Error` on error.
+    /// This function will return an instance of [`Error`] on error.
+    ///
+    /// [`Error`]: struct.Error.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::fmt::{Error, Write};
+    ///
+    /// fn writer<W: Write>(f: &mut W, s: &str) -> Result<(), Error> {
+    ///     f.write_str(s)
+    /// }
+    ///
+    /// let mut buf = String::new();
+    /// writer(&mut buf, "hola").unwrap();
+    /// assert_eq!(&buf, "hola");
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     fn write_str(&mut self, s: &str) -> Result;
 
-    /// Writes a `char` into this writer, returning whether the write succeeded.
+    /// Writes a [`char`] into this writer, returning whether the write succeeded.
     ///
-    /// A single `char` may be encoded as more than one byte.
+    /// A single [`char`] may be encoded as more than one byte.
     /// This method can only succeed if the entire byte sequence was successfully
     /// written, and this method will not return until all data has been
     /// written or an error occurs.
     ///
     /// # Errors
     ///
-    /// This function will return an instance of `Error` on error.
+    /// This function will return an instance of [`Error`] on error.
+    ///
+    /// [`char`]: ../../std/primitive.char.html
+    /// [`Error`]: struct.Error.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::fmt::{Error, Write};
+    ///
+    /// fn writer<W: Write>(f: &mut W, c: char) -> Result<(), Error> {
+    ///     f.write_char(c)
+    /// }
+    ///
+    /// let mut buf = String::new();
+    /// writer(&mut buf, 'a').unwrap();
+    /// writer(&mut buf, 'b').unwrap();
+    /// assert_eq!(&buf, "ab");
+    /// ```
     #[stable(feature = "fmt_write_char", since = "1.1.0")]
     fn write_char(&mut self, c: char) -> Result {
         self.write_str(c.encode_utf8(&mut [0; 4]))
     }
 
-    /// Glue for usage of the `write!` macro with implementors of this trait.
+    /// Glue for usage of the [`write!`] macro with implementors of this trait.
     ///
     /// This method should generally not be invoked manually, but rather through
-    /// the `write!` macro itself.
+    /// the [`write!`] macro itself.
+    ///
+    /// [`write!`]: ../../std/macro.write.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::fmt::{Error, Write};
+    ///
+    /// fn writer<W: Write>(f: &mut W, s: &str) -> Result<(), Error> {
+    ///     f.write_fmt(format_args!("{}", s))
+    /// }
+    ///
+    /// let mut buf = String::new();
+    /// writer(&mut buf, "world").unwrap();
+    /// assert_eq!(&buf, "world");
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     fn write_fmt(&mut self, args: Arguments) -> Result {
         // This Adapter is needed to allow `self` (of type `&mut
index 3e0b84255735382e34795423d04f952a741b2d4c..0331c5d4ba4013280c27dabe8e141126117b5685 100644 (file)
@@ -2202,6 +2202,7 @@ fn ne(&self, other: &[B]) -> bool {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Eq> Eq for [T] {}
 
+/// Implements comparison of vectors lexicographically.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Ord> Ord for [T] {
     fn cmp(&self, other: &[T]) -> Ordering {
@@ -2209,6 +2210,7 @@ fn cmp(&self, other: &[T]) -> Ordering {
     }
 }
 
+/// Implements comparison of vectors lexicographically.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: PartialOrd> PartialOrd for [T] {
     fn partial_cmp(&self, other: &[T]) -> Option<Ordering> {
index 49a6b1b5fceb77a417309ee15bf9c4489790f07b..925cd84154a2e6683479e3c02789acbe093a6352 100644 (file)
@@ -1366,6 +1366,13 @@ mod traits {
     use ops;
     use str::eq_slice;
 
+    /// Implements ordering of strings.
+    ///
+    /// Strings are ordered  lexicographically by their byte values.  This orders Unicode code
+    /// points based on their positions in the code charts.  This is not necessarily the same as
+    /// "alphabetical" order, which varies by language and locale.  Sorting strings according to
+    /// culturally-accepted standards requires locale-specific data that is outside the scope of
+    /// the `str` type.
     #[stable(feature = "rust1", since = "1.0.0")]
     impl Ord for str {
         #[inline]
@@ -1387,6 +1394,13 @@ fn ne(&self, other: &str) -> bool { !(*self).eq(other) }
     #[stable(feature = "rust1", since = "1.0.0")]
     impl Eq for str {}
 
+    /// Implements comparison operations on strings.
+    ///
+    /// Strings are compared lexicographically by their byte values.  This compares Unicode code
+    /// points based on their positions in the code charts.  This is not necessarily the same as
+    /// "alphabetical" order, which varies by language and locale.  Comparing strings according to
+    /// culturally-accepted standards requires locale-specific data that is outside the scope of
+    /// the `str` type.
     #[stable(feature = "rust1", since = "1.0.0")]
     impl PartialOrd for str {
         #[inline]
index 7a3754f2bb5e65eb39adacb189c3626173032177..64d954c6a76e896fbf7ed5c17e77c40e388abe84 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 7a3754f2bb5e65eb39adacb189c3626173032177
+Subproject commit 64d954c6a76e896fbf7ed5c17e77c40e388abe84
index f962c888f42cc4da71e568a567a40f3cd563d5dc..0516e111be3b38002bd924e6a7ada7c107082e4b 100644 (file)
@@ -125,6 +125,10 @@ fn register_custom_derive(&mut self,
         fn register_attr_proc_macro(&mut self,
                                     name: &str,
                                     expand: fn(TokenStream, TokenStream) -> TokenStream);
+
+        fn register_bang_proc_macro(&mut self,
+                                    name: &str,
+                                    expand: fn(TokenStream) -> TokenStream);
     }
 
     // Emulate scoped_thread_local!() here essentially
@@ -173,8 +177,7 @@ fn from_str(src: &str) -> Result<TokenStream, LexError> {
         __internal::with_parse_sess(|sess| {
             let src = src.to_string();
             let name = "<proc-macro source code>".to_string();
-            let tts = try!(parse::parse_tts_from_source_str(name, src, sess)
-                .map_err(parse_to_lex_err));
+            let tts = parse::parse_tts_from_source_str(name, src, sess);
 
             Ok(__internal::token_stream_wrap(tts.into_iter().collect()))
         })
index 300b4df89294354edcafa092abe5601a700245f6..dc7c96a4e27672d88fb2f501d5d2b7b0e69b322d 100644 (file)
@@ -119,7 +119,6 @@ fn quote(&self) -> TokenStream {
                 ::syntax::tokenstream::TokenTree::Delimited(::syntax::ext::quote::rt::DUMMY_SP,
                                                             (quote delimited))
             },
-            _ => panic!("unexpected `TokenTree::Sequence` in `qquote`"),
         }
     }
 }
index 595059332895de875da28ed8b7c86ed9482e7d7a..122543aee40eca45178cf1b84ab1cf77d0bb269c 100644 (file)
@@ -220,15 +220,24 @@ fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex {
                 // Note that `break` and `continue` statements
                 // may cause additional edges.
 
-                // Is the condition considered part of the loop?
                 let loopback = self.add_dummy_node(&[pred]);              // 1
-                let cond_exit = self.expr(&cond, loopback);             // 2
-                let expr_exit = self.add_ast_node(expr.id, &[cond_exit]); // 3
+
+                // Create expr_exit without pred (cond_exit)
+                let expr_exit = self.add_ast_node(expr.id, &[]);         // 3
+
+                // The LoopScope needs to be on the loop_scopes stack while evaluating the
+                // condition and the body of the loop (both can break out of the loop)
                 self.loop_scopes.push(LoopScope {
                     loop_id: expr.id,
                     continue_index: loopback,
                     break_index: expr_exit
                 });
+
+                let cond_exit = self.expr(&cond, loopback);             // 2
+
+                // Add pred (cond_exit) to expr_exit
+                self.add_contained_edge(cond_exit, expr_exit);
+
                 let body_exit = self.block(&body, cond_exit);          // 4
                 self.add_contained_edge(body_exit, loopback);            // 5
                 self.loop_scopes.pop();
@@ -294,17 +303,17 @@ fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex {
                 self.add_unreachable_node()
             }
 
-            hir::ExprBreak(label, ref opt_expr) => {
+            hir::ExprBreak(destination, ref opt_expr) => {
                 let v = self.opt_expr(opt_expr, pred);
-                let loop_scope = self.find_scope(expr, label);
+                let loop_scope = self.find_scope(expr, destination);
                 let b = self.add_ast_node(expr.id, &[v]);
                 self.add_exiting_edge(expr, b,
                                       loop_scope, loop_scope.break_index);
                 self.add_unreachable_node()
             }
 
-            hir::ExprAgain(label) => {
-                let loop_scope = self.find_scope(expr, label);
+            hir::ExprAgain(destination) => {
+                let loop_scope = self.find_scope(expr, destination);
                 let a = self.add_ast_node(expr.id, &[pred]);
                 self.add_exiting_edge(expr, a,
                                       loop_scope, loop_scope.continue_index);
@@ -579,17 +588,18 @@ fn add_returning_edge(&mut self,
 
     fn find_scope(&self,
                   expr: &hir::Expr,
-                  label: Option<hir::Label>) -> LoopScope {
-        match label {
-            None => *self.loop_scopes.last().unwrap(),
-            Some(label) => {
+                  destination: hir::Destination) -> LoopScope {
+
+        match destination.loop_id.into() {
+            Ok(loop_id) => {
                 for l in &self.loop_scopes {
-                    if l.loop_id == label.loop_id {
+                    if l.loop_id == loop_id {
                         return *l;
                     }
                 }
-                span_bug!(expr.span, "no loop scope for id {}", label.loop_id);
+                span_bug!(expr.span, "no loop scope for id {}", loop_id);
             }
+            Err(err) => span_bug!(expr.span, "loop scope error: {}",  err)
         }
     }
 }
index 96d1a925425e8d322a283e9bc4ffc6a716b1eb52..e0233d6f8b98cd1bf818a8766f58da2781a6919c 100644 (file)
@@ -70,6 +70,7 @@ pub enum DepNode<D: Clone + Debug> {
     Resolve,
     EntryPoint,
     CheckEntryFn,
+    CoherenceCheckTrait(D),
     CoherenceCheckImpl(D),
     CoherenceOverlapCheck(D),
     CoherenceOverlapCheckSpecial(D),
@@ -109,11 +110,13 @@ pub enum DepNode<D: Clone + Debug> {
     // predicates for an item wind up in `ItemSignature`).
     AssociatedItems(D),
     ItemSignature(D),
+    TypeParamPredicates((D, D)),
     SizedConstraint(D),
     AssociatedItemDefIds(D),
     InherentImpls(D),
     TypeckTables(D),
     UsedTraitImports(D),
+    MonomorphicConstEval(D),
 
     // The set of impls for a given trait. Ultimately, it would be
     // nice to get more fine-grained here (e.g., to include a
@@ -239,6 +242,7 @@ pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
             MetaData(ref d) => op(d).map(MetaData),
             CollectItem(ref d) => op(d).map(CollectItem),
             CollectItemSig(ref d) => op(d).map(CollectItemSig),
+            CoherenceCheckTrait(ref d) => op(d).map(CoherenceCheckTrait),
             CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
             CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
             CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),
@@ -258,11 +262,15 @@ pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
             TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
             AssociatedItems(ref d) => op(d).map(AssociatedItems),
             ItemSignature(ref d) => op(d).map(ItemSignature),
+            TypeParamPredicates((ref item, ref param)) => {
+                Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
+            }
             SizedConstraint(ref d) => op(d).map(SizedConstraint),
             AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
             InherentImpls(ref d) => op(d).map(InherentImpls),
             TypeckTables(ref d) => op(d).map(TypeckTables),
             UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
+            MonomorphicConstEval(ref d) => op(d).map(MonomorphicConstEval),
             TraitImpls(ref d) => op(d).map(TraitImpls),
             TraitItems(ref d) => op(d).map(TraitItems),
             ReprHints(ref d) => op(d).map(ReprHints),
index 2ffc3951cc94db96466248f17345fd0fba378366..9f45e66f0d937116c255fc65484d64086a67c82b 100644 (file)
@@ -11,6 +11,7 @@
 use hir::def_id::DefId;
 use rustc_data_structures::fx::FxHashMap;
 use std::cell::RefCell;
+use std::collections::hash_map::Entry;
 use std::ops::Index;
 use std::hash::Hash;
 use std::marker::PhantomData;
@@ -67,6 +68,11 @@ pub fn insert(&mut self, k: M::Key, v: M::Value) {
         assert!(old_value.is_none());
     }
 
+    pub fn entry(&mut self, k: M::Key) -> Entry<M::Key, M::Value> {
+        self.write(&k);
+        self.map.entry(k)
+    }
+
     pub fn contains_key(&self, k: &M::Key) -> bool {
         self.read(k);
         self.map.contains_key(k)
index cf51dad5142eea278649b6da04897c03292744ce..85b4ddcdd719099a90bd1cd25abc93827b32b7a2 100644 (file)
@@ -390,44 +390,6 @@ impl Quux for Foo { }
 [iss15872]: https://github.com/rust-lang/rust/issues/15872
 "##,
 
-E0109: r##"
-You tried to give a type parameter to a type which doesn't need it. Erroneous
-code example:
-
-```compile_fail,E0109
-type X = u32<i32>; // error: type parameters are not allowed on this type
-```
-
-Please check that you used the correct type and recheck its definition. Perhaps
-it doesn't need the type parameter.
-
-Example:
-
-```
-type X = u32; // this compiles
-```
-
-Note that type parameters for enum-variant constructors go after the variant,
-not after the enum (Option::None::<u32>, not Option::<u32>::None).
-"##,
-
-E0110: r##"
-You tried to give a lifetime parameter to a type which doesn't need it.
-Erroneous code example:
-
-```compile_fail,E0110
-type X = u32<'static>; // error: lifetime parameters are not allowed on
-                       //        this type
-```
-
-Please check that the correct type was used and recheck its definition; perhaps
-it doesn't need the lifetime parameter. Example:
-
-```
-type X = u32; // ok!
-```
-"##,
-
 E0133: r##"
 Unsafe code was used outside of an unsafe function or block.
 
@@ -627,41 +589,6 @@ fn foo<T: MyTransmutableType>(x: Vec<T>) {
 See also https://doc.rust-lang.org/book/no-stdlib.html
 "##,
 
-E0229: r##"
-An associated type binding was done outside of the type parameter declaration
-and `where` clause. Erroneous code example:
-
-```compile_fail,E0229
-pub trait Foo {
-    type A;
-    fn boo(&self) -> <Self as Foo>::A;
-}
-
-struct Bar;
-
-impl Foo for isize {
-    type A = usize;
-    fn boo(&self) -> usize { 42 }
-}
-
-fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
-// error: associated type bindings are not allowed here
-```
-
-To solve this error, please move the type bindings in the type parameter
-declaration:
-
-```ignore
-fn baz<I: Foo<A=Bar>>(x: &<I as Foo>::A) {} // ok!
-```
-
-Or in the `where` clause:
-
-```ignore
-fn baz<I>(x: &<I as Foo>::A) where I: Foo<A=Bar> {}
-```
-"##,
-
 E0261: r##"
 When using a lifetime like `'a` in a type, it must be declared before being
 used.
@@ -1390,6 +1317,23 @@ fn main() {
 block.
 "##,
 
+E0391: r##"
+This error indicates that some types or traits depend on each other
+and therefore cannot be constructed.
+
+The following example contains a circular dependency between two traits:
+
+```compile_fail,E0391
+trait FirstTrait : SecondTrait {
+
+}
+
+trait SecondTrait : FirstTrait {
+
+}
+```
+"##,
+
 E0398: r##"
 In Rust 1.3, the default object lifetime bounds are expected to change, as
 described in RFC #1156 [1]. You are getting a warning because the compiler
@@ -1781,6 +1725,68 @@ fn main() {
 specified exit code, use `std::process::exit`.
 "##,
 
+E0591: r##"
+Per [RFC 401][rfc401], if you have a function declaration `foo`:
+
+```rust,ignore
+// For the purposes of this explanation, all of these
+// different kinds of `fn` declarations are equivalent:
+fn foo(x: i32) { ... }
+extern "C" fn foo(x: i32);
+impl i32 { fn foo(x: self) { ... } }
+```
+
+the type of `foo` is **not** `fn(i32)`, as one might expect.
+Rather, it is a unique, zero-sized marker type written here as `typeof(foo)`.
+However, `typeof(foo)` can be _coerced_ to a function pointer `fn(i32)`,
+so you rarely notice this:
+
+```rust,ignore
+let x: fn(i32) = foo; // OK, coerces
+```
+
+The reason that this matter is that the type `fn(i32)` is not specific to
+any particular function: it's a function _pointer_. So calling `x()` results
+in a virtual call, whereas `foo()` is statically dispatched, because the type
+of `foo` tells us precisely what function is being called.
+
+As noted above, coercions mean that most code doesn't have to be
+concerned with this distinction. However, you can tell the difference
+when using **transmute** to convert a fn item into a fn pointer.
+
+This is sometimes done as part of an FFI:
+
+```rust,ignore
+extern "C" fn foo(userdata: Box<i32>) {
+   ...
+}
+
+let f: extern "C" fn(*mut i32) = transmute(foo);
+callback(f);
+
+```
+
+Here, transmute is being used to convert the types of the fn arguments.
+This pattern is incorrect because, because the type of `foo` is a function
+**item** (`typeof(foo)`), which is zero-sized, and the target type (`fn()`)
+is a function pointer, which is not zero-sized.
+This pattern should be rewritten. There are a few possible ways to do this:
+- change the original fn declaration to match the expected signature,
+  and do the cast in the fn body (the prefered option)
+- cast the fn item fo a fn pointer before calling transmute, as shown here:
+  - `let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_))`
+  - `let f: extern "C" fn(*mut i32) = transmute(foo as usize) /* works too */`
+
+The same applies to transmutes to `*mut fn()`, which were observedin practice.
+Note though that use of this type is generally incorrect.
+The intention is typically to describe a function pointer, but just `fn()`
+alone suffices for that. `*mut fn()` is a pointer to a fn pointer.
+(Since these values are typically just passed to C code, however, this rarely
+makes a difference in practice.)
+
+[rfc401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
+"##,
+
 }
 
 
index 53b7be74f85037dcaea5d9e7c362f0413d41447b..aedb8fef2885cf461cca140334147a030940e891 100644 (file)
@@ -11,6 +11,7 @@
 use hir::def_id::DefId;
 use util::nodemap::NodeMap;
 use syntax::ast;
+use syntax::ext::base::MacroKind;
 use hir;
 
 #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
@@ -53,7 +54,7 @@ pub enum Def {
     Label(ast::NodeId),
 
     // Macro namespace
-    Macro(DefId),
+    Macro(DefId, MacroKind),
 
     // Both namespaces
     Err,
@@ -141,7 +142,7 @@ pub fn def_id(&self) -> DefId {
             Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) |
             Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
             Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
-            Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id) => {
+            Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) => {
                 id
             }
 
index 1df67615069935a364ca55a7e09d6050e352cca7..fd6796ccc0bf2b0cd6b7957281a960c99322ff4c 100644 (file)
@@ -1006,18 +1006,22 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
         ExprPath(ref qpath) => {
             visitor.visit_qpath(qpath, expression.id, expression.span);
         }
-        ExprBreak(None, ref opt_expr) => {
+        ExprBreak(label, ref opt_expr) => {
+            label.ident.map(|ident| {
+                if let Ok(loop_id) = label.loop_id.into() {
+                    visitor.visit_def_mention(Def::Label(loop_id));
+                }
+                visitor.visit_name(ident.span, ident.node.name);
+            });
             walk_list!(visitor, visit_expr, opt_expr);
         }
-        ExprBreak(Some(label), ref opt_expr) => {
-            visitor.visit_def_mention(Def::Label(label.loop_id));
-            visitor.visit_name(label.span, label.name);
-            walk_list!(visitor, visit_expr, opt_expr);
-        }
-        ExprAgain(None) => {}
-        ExprAgain(Some(label)) => {
-            visitor.visit_def_mention(Def::Label(label.loop_id));
-            visitor.visit_name(label.span, label.name);
+        ExprAgain(label) => {
+            label.ident.map(|ident| {
+                if let Ok(loop_id) = label.loop_id.into() {
+                    visitor.visit_def_mention(Def::Label(loop_id));
+                }
+                visitor.visit_name(ident.span, ident.node.name);
+            });
         }
         ExprRet(ref optional_expression) => {
             walk_list!(visitor, visit_expr, optional_expression);
index c87ce6505fcd505e81bff483904cec8e691ff254..468421a68b54cb5f88168056a7d67ddf07f77761 100644 (file)
@@ -50,6 +50,7 @@
 
 use std::collections::BTreeMap;
 use std::iter;
+use std::mem;
 
 use syntax::attr;
 use syntax::ast::*;
@@ -79,6 +80,12 @@ pub struct LoweringContext<'a> {
     impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
     bodies: FxHashMap<hir::BodyId, hir::Body>,
 
+    trait_impls: BTreeMap<DefId, Vec<NodeId>>,
+    trait_default_impl: BTreeMap<DefId, NodeId>,
+
+    loop_scopes: Vec<NodeId>,
+    is_in_loop_condition: bool,
+
     type_def_lifetime_params: DefIdMap<usize>,
 }
 
@@ -112,6 +119,10 @@ pub fn lower_crate(sess: &Session,
         trait_items: BTreeMap::new(),
         impl_items: BTreeMap::new(),
         bodies: FxHashMap(),
+        trait_impls: BTreeMap::new(),
+        trait_default_impl: BTreeMap::new(),
+        loop_scopes: Vec::new(),
+        is_in_loop_condition: false,
         type_def_lifetime_params: DefIdMap(),
     }.lower_crate(krate)
 }
@@ -195,6 +206,8 @@ fn visit_impl_item(&mut self, item: &'lcx ImplItem) {
             trait_items: self.trait_items,
             impl_items: self.impl_items,
             bodies: self.bodies,
+            trait_impls: self.trait_impls,
+            trait_default_impl: self.trait_default_impl,
         }
     }
 
@@ -244,6 +257,55 @@ fn allow_internal_unstable(&self, reason: &'static str, mut span: Span) -> Span
         span
     }
 
+    fn with_loop_scope<T, F>(&mut self, loop_id: NodeId, f: F) -> T
+        where F: FnOnce(&mut LoweringContext) -> T
+    {
+        // We're no longer in the base loop's condition; we're in another loop.
+        let was_in_loop_condition = self.is_in_loop_condition;
+        self.is_in_loop_condition = false;
+
+        let len = self.loop_scopes.len();
+        self.loop_scopes.push(loop_id);
+
+        let result = f(self);
+        assert_eq!(len + 1, self.loop_scopes.len(),
+            "Loop scopes should be added and removed in stack order");
+
+        self.loop_scopes.pop().unwrap();
+
+        self.is_in_loop_condition = was_in_loop_condition;
+
+        result
+    }
+
+    fn with_loop_condition_scope<T, F>(&mut self, f: F) -> T
+        where F: FnOnce(&mut LoweringContext) -> T
+    {
+        let was_in_loop_condition = self.is_in_loop_condition;
+        self.is_in_loop_condition = true;
+
+        let result = f(self);
+
+        self.is_in_loop_condition = was_in_loop_condition;
+
+        result
+    }
+
+    fn with_new_loop_scopes<T, F>(&mut self, f: F) -> T
+        where F: FnOnce(&mut LoweringContext) -> T
+    {
+        let was_in_loop_condition = self.is_in_loop_condition;
+        self.is_in_loop_condition = false;
+
+        let loop_scopes = mem::replace(&mut self.loop_scopes, Vec::new());
+        let result = f(self);
+        mem::replace(&mut self.loop_scopes, loop_scopes);
+
+        self.is_in_loop_condition = was_in_loop_condition;
+
+        result
+    }
+
     fn with_parent_def<T, F>(&mut self, parent_id: NodeId, f: F) -> T
         where F: FnOnce(&mut LoweringContext) -> T
     {
@@ -271,17 +333,24 @@ fn lower_opt_sp_ident(&mut self, o_id: Option<Spanned<Ident>>) -> Option<Spanned
         o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name))
     }
 
-    fn lower_label(&mut self, id: NodeId, label: Option<Spanned<Ident>>) -> Option<hir::Label> {
-        label.map(|sp_ident| {
-            hir::Label {
-                span: sp_ident.span,
-                name: sp_ident.node.name,
-                loop_id: match self.expect_full_def(id) {
-                    Def::Label(loop_id) => loop_id,
-                    _ => DUMMY_NODE_ID
+    fn lower_destination(&mut self, destination: Option<(NodeId, Spanned<Ident>)>)
+        -> hir::Destination
+    {
+        match destination {
+            Some((id, label_ident)) => hir::Destination {
+                ident: Some(label_ident),
+                loop_id: if let Def::Label(loop_id) = self.expect_full_def(id) {
+                    hir::LoopIdResult::Ok(loop_id)
+                } else {
+                    hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel)
                 }
+            },
+            None => hir::Destination {
+                ident: None,
+                loop_id: self.loop_scopes.last().map(|innermost_loop_id| Ok(*innermost_loop_id))
+                            .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)).into()
             }
-        })
+        }
     }
 
     fn lower_attrs(&mut self, attrs: &Vec<Attribute>) -> hir::HirVec<Attribute> {
@@ -463,7 +532,7 @@ fn lower_qpath(&mut self,
                         return n;
                     }
                     assert!(!def_id.is_local());
-                    let (n, _) = self.sess.cstore.item_generics_own_param_counts(def_id);
+                    let n = self.sess.cstore.item_generics_cloned(def_id).regions.len();
                     self.type_def_lifetime_params.insert(def_id, n);
                     n
                 });
@@ -992,15 +1061,17 @@ fn lower_item_kind(&mut self,
                                self.record_body(value, None))
             }
             ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
-                let body = self.lower_block(body);
-                let body = self.expr_block(body, ThinVec::new());
-                let body_id = self.record_body(body, Some(decl));
-                hir::ItemFn(self.lower_fn_decl(decl),
-                            self.lower_unsafety(unsafety),
-                            self.lower_constness(constness),
-                            abi,
-                            self.lower_generics(generics),
-                            body_id)
+                self.with_new_loop_scopes(|this| {
+                    let body = this.lower_block(body);
+                    let body = this.expr_block(body, ThinVec::new());
+                    let body_id = this.record_body(body, Some(decl));
+                    hir::ItemFn(this.lower_fn_decl(decl),
+                                              this.lower_unsafety(unsafety),
+                                              this.lower_constness(constness),
+                                              abi,
+                                              this.lower_generics(generics),
+                                              body_id)
+                })
             }
             ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)),
             ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)),
@@ -1025,14 +1096,27 @@ fn lower_item_kind(&mut self,
                 hir::ItemUnion(vdata, self.lower_generics(generics))
             }
             ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
+                let trait_ref = self.lower_trait_ref(trait_ref);
+
+                if let Def::Trait(def_id) = trait_ref.path.def {
+                    self.trait_default_impl.insert(def_id, id);
+                }
+
                 hir::ItemDefaultImpl(self.lower_unsafety(unsafety),
-                                     self.lower_trait_ref(trait_ref))
+                                     trait_ref)
             }
             ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => {
                 let new_impl_items = impl_items.iter()
                                                .map(|item| self.lower_impl_item_ref(item))
                                                .collect();
                 let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref));
+
+                if let Some(ref trait_ref) = ifce {
+                    if let Def::Trait(def_id) = trait_ref.path.def {
+                        self.trait_impls.entry(def_id).or_insert(vec![]).push(id);
+                    }
+                }
+
                 hir::ItemImpl(self.lower_unsafety(unsafety),
                               self.lower_impl_polarity(polarity),
                               self.lower_generics(generics),
@@ -1562,13 +1646,17 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                     hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk), else_opt)
                 }
                 ExprKind::While(ref cond, ref body, opt_ident) => {
-                    hir::ExprWhile(P(self.lower_expr(cond)), self.lower_block(body),
-                                   self.lower_opt_sp_ident(opt_ident))
+                    self.with_loop_scope(e.id, |this|
+                        hir::ExprWhile(
+                            this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
+                            this.lower_block(body),
+                            this.lower_opt_sp_ident(opt_ident)))
                 }
                 ExprKind::Loop(ref body, opt_ident) => {
-                    hir::ExprLoop(self.lower_block(body),
-                                  self.lower_opt_sp_ident(opt_ident),
-                                  hir::LoopSource::Loop)
+                    self.with_loop_scope(e.id, |this|
+                        hir::ExprLoop(this.lower_block(body),
+                                      this.lower_opt_sp_ident(opt_ident),
+                                      hir::LoopSource::Loop))
                 }
                 ExprKind::Match(ref expr, ref arms) => {
                     hir::ExprMatch(P(self.lower_expr(expr)),
@@ -1576,12 +1664,14 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
                                    hir::MatchSource::Normal)
                 }
                 ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => {
-                    self.with_parent_def(e.id, |this| {
-                        let expr = this.lower_expr(body);
-                        hir::ExprClosure(this.lower_capture_clause(capture_clause),
-                                         this.lower_fn_decl(decl),
-                                         this.record_body(expr, Some(decl)),
-                                         fn_decl_span)
+                    self.with_new_loop_scopes(|this| {
+                        this.with_parent_def(e.id, |this| {
+                            let expr = this.lower_expr(body);
+                            hir::ExprClosure(this.lower_capture_clause(capture_clause),
+                                             this.lower_fn_decl(decl),
+                                             this.record_body(expr, Some(decl)),
+                                             fn_decl_span)
+                        })
                     })
                 }
                 ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk)),
@@ -1660,10 +1750,29 @@ fn make_struct(this: &mut LoweringContext,
                     hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional))
                 }
                 ExprKind::Break(opt_ident, ref opt_expr) => {
-                    hir::ExprBreak(self.lower_label(e.id, opt_ident),
-                                   opt_expr.as_ref().map(|x| P(self.lower_expr(x))))
+                    let label_result = if self.is_in_loop_condition && opt_ident.is_none() {
+                        hir::Destination {
+                            ident: opt_ident,
+                            loop_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
+                        }
+                    } else {
+                        self.lower_destination(opt_ident.map(|ident| (e.id, ident)))
+                    };
+                    hir::ExprBreak(
+                            label_result,
+                            opt_expr.as_ref().map(|x| P(self.lower_expr(x))))
                 }
-                ExprKind::Continue(opt_ident) => hir::ExprAgain(self.lower_label(e.id, opt_ident)),
+                ExprKind::Continue(opt_ident) =>
+                    hir::ExprAgain(
+                        if self.is_in_loop_condition && opt_ident.is_none() {
+                            hir::Destination {
+                                ident: opt_ident,
+                                loop_id: Err(
+                                    hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
+                            }
+                        } else {
+                            self.lower_destination(opt_ident.map( |ident| (e.id, ident)))
+                        }),
                 ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))),
                 ExprKind::InlineAsm(ref asm) => {
                     let hir_asm = hir::InlineAsm {
@@ -1804,9 +1913,16 @@ fn make_struct(this: &mut LoweringContext,
                     //     }
                     //   }
 
+                    // Note that the block AND the condition are evaluated in the loop scope.
+                    // This is done to allow `break` from inside the condition of the loop.
+                    let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| (
+                        this.lower_block(body),
+                        this.expr_break(e.span, ThinVec::new()),
+                        this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))),
+                    ));
+
                     // `<pat> => <body>`
                     let pat_arm = {
-                        let body = self.lower_block(body);
                         let body_expr = P(self.expr_block(body, ThinVec::new()));
                         let pat = self.lower_pat(pat);
                         self.arm(hir_vec![pat], body_expr)
@@ -1815,13 +1931,11 @@ fn make_struct(this: &mut LoweringContext,
                     // `_ => break`
                     let break_arm = {
                         let pat_under = self.pat_wild(e.span);
-                        let break_expr = self.expr_break(e.span, ThinVec::new());
                         self.arm(hir_vec![pat_under], break_expr)
                     };
 
                     // `match <sub_expr> { ... }`
                     let arms = hir_vec![pat_arm, break_arm];
-                    let sub_expr = P(self.lower_expr(sub_expr));
                     let match_expr = self.expr(e.span,
                                                hir::ExprMatch(sub_expr,
                                                               arms,
@@ -1863,7 +1977,7 @@ fn make_struct(this: &mut LoweringContext,
 
                     // `::std::option::Option::Some(<pat>) => <body>`
                     let pat_arm = {
-                        let body_block = self.lower_block(body);
+                        let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body));
                         let body_expr = P(self.expr_block(body_block, ThinVec::new()));
                         let pat = self.lower_pat(pat);
                         let some_pat = self.pat_some(e.span, pat);
@@ -1873,7 +1987,8 @@ fn make_struct(this: &mut LoweringContext,
 
                     // `::std::option::Option::None => break`
                     let break_arm = {
-                        let break_expr = self.expr_break(e.span, ThinVec::new());
+                        let break_expr = self.with_loop_scope(e.id, |this|
+                            this.expr_break(e.span, ThinVec::new()));
                         let pat = self.pat_none(e.span);
                         self.arm(hir_vec![pat], break_expr)
                     };
@@ -2151,7 +2266,8 @@ fn field(&mut self, name: Name, expr: P<hir::Expr>, span: Span) -> hir::Field {
     }
 
     fn expr_break(&mut self, span: Span, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
-        P(self.expr(span, hir::ExprBreak(None, None), attrs))
+        let expr_break = hir::ExprBreak(self.lower_destination(None), None);
+        P(self.expr(span, expr_break, attrs))
     }
 
     fn expr_call(&mut self, span: Span, e: P<hir::Expr>, args: hir::HirVec<hir::Expr>)
index 9f31b5b456b9f27c7446d88fc636cd240b96610a..20b4d8d8a8f031b71be26fe141630fef933d1fdd 100644 (file)
@@ -437,6 +437,50 @@ pub fn body_owner_def_id(&self, id: BodyId) -> DefId {
         self.local_def_id(self.body_owner(id))
     }
 
+    pub fn ty_param_owner(&self, id: NodeId) -> NodeId {
+        match self.get(id) {
+            NodeItem(&Item { node: ItemTrait(..), .. }) => id,
+            NodeTyParam(_) => self.get_parent_node(id),
+            _ => {
+                bug!("ty_param_owner: {} not a type parameter",
+                    self.node_to_string(id))
+            }
+        }
+    }
+
+    pub fn ty_param_name(&self, id: NodeId) -> Name {
+        match self.get(id) {
+            NodeItem(&Item { node: ItemTrait(..), .. }) => {
+                keywords::SelfType.name()
+            }
+            NodeTyParam(tp) => tp.name,
+            _ => {
+                bug!("ty_param_name: {} not a type parameter",
+                    self.node_to_string(id))
+            }
+        }
+    }
+
+    pub fn trait_impls(&self, trait_did: DefId) -> &'hir [NodeId] {
+        self.dep_graph.read(DepNode::TraitImpls(trait_did));
+
+        // NB: intentionally bypass `self.forest.krate()` so that we
+        // do not trigger a read of the whole krate here
+        self.forest.krate.trait_impls.get(&trait_did).map_or(&[], |xs| &xs[..])
+    }
+
+    pub fn trait_default_impl(&self, trait_did: DefId) -> Option<NodeId> {
+        self.dep_graph.read(DepNode::TraitImpls(trait_did));
+
+        // NB: intentionally bypass `self.forest.krate()` so that we
+        // do not trigger a read of the whole krate here
+        self.forest.krate.trait_default_impl.get(&trait_did).cloned()
+    }
+
+    pub fn trait_is_auto(&self, trait_did: DefId) -> bool {
+        self.trait_default_impl(trait_did).is_some()
+    }
+
     /// Get the attributes on the krate. This is preferable to
     /// invoking `krate.attrs` because it registers a tighter
     /// dep-graph access.
index 4ebe416e1bfe67c12300b0b9b7d6a62cf3b55019..8b6c75886baa8121ff62903a2c773202766531f3 100644 (file)
@@ -36,7 +36,7 @@
 use syntax_pos::{Span, ExpnId, DUMMY_SP};
 use syntax::codemap::{self, Spanned};
 use syntax::abi::Abi;
-use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect};
+use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
 use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
 use syntax::ptr::P;
 use syntax::symbol::{Symbol, keywords};
@@ -410,6 +410,9 @@ pub struct Crate {
     pub trait_items: BTreeMap<TraitItemId, TraitItem>,
     pub impl_items: BTreeMap<ImplItemId, ImplItem>,
     pub bodies: FxHashMap<BodyId, Body>,
+
+    pub trait_impls: BTreeMap<DefId, Vec<NodeId>>,
+    pub trait_default_impl: BTreeMap<DefId, NodeId>,
 }
 
 impl Crate {
@@ -959,9 +962,9 @@ pub enum Expr_ {
     /// A referencing operation (`&a` or `&mut a`)
     ExprAddrOf(Mutability, P<Expr>),
     /// A `break`, with an optional label to break
-    ExprBreak(Option<Label>, Option<P<Expr>>),
+    ExprBreak(Destination, Option<P<Expr>>),
     /// A `continue`, with an optional label
-    ExprAgain(Option<Label>),
+    ExprAgain(Destination),
     /// A `return`, with an optional value to be returned
     ExprRet(Option<P<Expr>>),
 
@@ -1030,12 +1033,56 @@ pub enum LoopSource {
     ForLoop,
 }
 
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum LoopIdError {
+    OutsideLoopScope,
+    UnlabeledCfInWhileCondition,
+    UnresolvedLabel,
+}
 
+impl fmt::Display for LoopIdError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(match *self {
+            LoopIdError::OutsideLoopScope => "not inside loop scope",
+            LoopIdError::UnlabeledCfInWhileCondition =>
+                "unlabeled control flow (break or continue) in while condition",
+            LoopIdError::UnresolvedLabel => "label not found",
+        }, f)
+    }
+}
+
+// FIXME(cramertj) this should use `Result` once master compiles w/ a vesion of Rust where
+// `Result` implements `Encodable`/`Decodable`
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub struct Label {
-    pub span: Span,
-    pub name: Name,
-    pub loop_id: NodeId
+pub enum LoopIdResult {
+    Ok(NodeId),
+    Err(LoopIdError),
+}
+impl Into<Result<NodeId, LoopIdError>> for LoopIdResult {
+    fn into(self) -> Result<NodeId, LoopIdError> {
+        match self {
+            LoopIdResult::Ok(ok) => Ok(ok),
+            LoopIdResult::Err(err) => Err(err),
+        }
+    }
+}
+impl From<Result<NodeId, LoopIdError>> for LoopIdResult {
+    fn from(res: Result<NodeId, LoopIdError>) -> Self {
+        match res {
+            Ok(ok) => LoopIdResult::Ok(ok),
+            Err(err) => LoopIdResult::Err(err),
+        }
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub struct Destination {
+    // This is `Some(_)` iff there is an explicit user-specified `label
+    pub ident: Option<Spanned<Ident>>,
+
+    // These errors are caught and then reported during the diagnostics pass in
+    // librustc_passes/loops.rs
+    pub loop_id: LoopIdResult,
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
index e058c48c59149b2995a5d8393e0887423d504e35..3411de9bb5df11356b753f08bb2c49c5946c74f4 100644 (file)
@@ -1354,11 +1354,11 @@ pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> {
             hir::ExprPath(ref qpath) => {
                 self.print_qpath(qpath, true)?
             }
-            hir::ExprBreak(opt_label, ref opt_expr) => {
+            hir::ExprBreak(label, ref opt_expr) => {
                 word(&mut self.s, "break")?;
                 space(&mut self.s)?;
-                if let Some(label) = opt_label {
-                    self.print_name(label.name)?;
+                if let Some(label_ident) = label.ident {
+                    self.print_name(label_ident.node.name)?;
                     space(&mut self.s)?;
                 }
                 if let Some(ref expr) = *opt_expr {
@@ -1366,11 +1366,11 @@ pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> {
                     space(&mut self.s)?;
                 }
             }
-            hir::ExprAgain(opt_label) => {
+            hir::ExprAgain(label) => {
                 word(&mut self.s, "continue")?;
                 space(&mut self.s)?;
-                if let Some(label) = opt_label {
-                    self.print_name(label.name)?;
+                if let Some(label_ident) = label.ident {
+                    self.print_name(label_ident.node.name)?;
                     space(&mut self.s)?
                 }
             }
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
deleted file mode 100644 (file)
index 9295fb2..0000000
+++ /dev/null
@@ -1,1146 +0,0 @@
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Error Reporting Code for the inference engine
-//!
-//! Because of the way inference, and in particular region inference,
-//! works, it often happens that errors are not detected until far after
-//! the relevant line of code has been type-checked. Therefore, there is
-//! an elaborate system to track why a particular constraint in the
-//! inference graph arose so that we can explain to the user what gave
-//! rise to a particular error.
-//!
-//! The basis of the system are the "origin" types. An "origin" is the
-//! reason that a constraint or inference variable arose. There are
-//! different "origin" enums for different kinds of constraints/variables
-//! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has
-//! a span, but also more information so that we can generate a meaningful
-//! error message.
-//!
-//! Having a catalogue of all the different reasons an error can arise is
-//! also useful for other reasons, like cross-referencing FAQs etc, though
-//! we are not really taking advantage of this yet.
-//!
-//! # Region Inference
-//!
-//! Region inference is particularly tricky because it always succeeds "in
-//! the moment" and simply registers a constraint. Then, at the end, we
-//! can compute the full graph and report errors, so we need to be able to
-//! store and later report what gave rise to the conflicting constraints.
-//!
-//! # Subtype Trace
-//!
-//! Determining whether `T1 <: T2` often involves a number of subtypes and
-//! subconstraints along the way. A "TypeTrace" is an extended version
-//! of an origin that traces the types and other values that were being
-//! compared. It is not necessarily comprehensive (in fact, at the time of
-//! this writing it only tracks the root values being compared) but I'd
-//! like to extend it to include significant "waypoints". For example, if
-//! you are comparing `(T1, T2) <: (T3, T4)`, and the problem is that `T2
-//! <: T4` fails, I'd like the trace to include enough information to say
-//! "in the 2nd element of the tuple". Similarly, failures when comparing
-//! arguments or return types in fn types should be able to cite the
-//! specific position, etc.
-//!
-//! # Reality vs plan
-//!
-//! Of course, there is still a LOT of code in typeck that has yet to be
-//! ported to this system, and which relies on string concatenation at the
-//! time of error detection.
-
-use super::InferCtxt;
-use super::TypeTrace;
-use super::SubregionOrigin;
-use super::RegionVariableOrigin;
-use super::ValuePairs;
-use super::region_inference::RegionResolutionError;
-use super::region_inference::ConcreteFailure;
-use super::region_inference::SubSupConflict;
-use super::region_inference::GenericBoundFailure;
-use super::region_inference::GenericKind;
-
-use hir::map as hir_map;
-use hir;
-
-use hir::def_id::DefId;
-use infer;
-use middle::region;
-use traits::{ObligationCause, ObligationCauseCode};
-use ty::{self, TyCtxt, TypeFoldable};
-use ty::{Region, Issue32330};
-use ty::error::TypeError;
-
-use std::fmt;
-use syntax_pos::{Pos, Span};
-use errors::DiagnosticBuilder;
-
-impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-    pub fn note_and_explain_region(self,
-                                   err: &mut DiagnosticBuilder,
-                                   prefix: &str,
-                                   region: &'tcx ty::Region,
-                                   suffix: &str) {
-        fn item_scope_tag(item: &hir::Item) -> &'static str {
-            match item.node {
-                hir::ItemImpl(..) => "impl",
-                hir::ItemStruct(..) => "struct",
-                hir::ItemUnion(..) => "union",
-                hir::ItemEnum(..) => "enum",
-                hir::ItemTrait(..) => "trait",
-                hir::ItemFn(..) => "function body",
-                _ => "item"
-            }
-        }
-
-        fn trait_item_scope_tag(item: &hir::TraitItem) -> &'static str {
-            match item.node {
-                hir::TraitItemKind::Method(..) => "method body",
-                hir::TraitItemKind::Const(..) |
-                hir::TraitItemKind::Type(..) => "associated item"
-            }
-        }
-
-        fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str {
-            match item.node {
-                hir::ImplItemKind::Method(..) => "method body",
-                hir::ImplItemKind::Const(..) |
-                hir::ImplItemKind::Type(_) => "associated item"
-            }
-        }
-
-        fn explain_span<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                        heading: &str, span: Span)
-                                        -> (String, Option<Span>) {
-            let lo = tcx.sess.codemap().lookup_char_pos_adj(span.lo);
-            (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize()),
-             Some(span))
-        }
-
-        let (description, span) = match *region {
-            ty::ReScope(scope) => {
-                let new_string;
-                let unknown_scope = || {
-                    format!("{}unknown scope: {:?}{}.  Please report a bug.",
-                            prefix, scope, suffix)
-                };
-                let span = match scope.span(&self.region_maps, &self.hir) {
-                    Some(s) => s,
-                    None => {
-                        err.note(&unknown_scope());
-                        return;
-                    }
-                };
-                let tag = match self.hir.find(scope.node_id(&self.region_maps)) {
-                    Some(hir_map::NodeBlock(_)) => "block",
-                    Some(hir_map::NodeExpr(expr)) => match expr.node {
-                        hir::ExprCall(..) => "call",
-                        hir::ExprMethodCall(..) => "method call",
-                        hir::ExprMatch(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
-                        hir::ExprMatch(.., hir::MatchSource::WhileLetDesugar) =>  "while let",
-                        hir::ExprMatch(.., hir::MatchSource::ForLoopDesugar) =>  "for",
-                        hir::ExprMatch(..) => "match",
-                        _ => "expression",
-                    },
-                    Some(hir_map::NodeStmt(_)) => "statement",
-                    Some(hir_map::NodeItem(it)) => item_scope_tag(&it),
-                    Some(hir_map::NodeTraitItem(it)) => trait_item_scope_tag(&it),
-                    Some(hir_map::NodeImplItem(it)) => impl_item_scope_tag(&it),
-                    Some(_) | None => {
-                        err.span_note(span, &unknown_scope());
-                        return;
-                    }
-                };
-                let scope_decorated_tag = match self.region_maps.code_extent_data(scope) {
-                    region::CodeExtentData::Misc(_) => tag,
-                    region::CodeExtentData::CallSiteScope { .. } => {
-                        "scope of call-site for function"
-                    }
-                    region::CodeExtentData::ParameterScope { .. } => {
-                        "scope of function body"
-                    }
-                    region::CodeExtentData::DestructionScope(_) => {
-                        new_string = format!("destruction scope surrounding {}", tag);
-                        &new_string[..]
-                    }
-                    region::CodeExtentData::Remainder(r) => {
-                        new_string = format!("block suffix following statement {}",
-                                             r.first_statement_index);
-                        &new_string[..]
-                    }
-                };
-                explain_span(self, scope_decorated_tag, span)
-            }
-
-            ty::ReFree(ref fr) => {
-                let prefix = match fr.bound_region {
-                    ty::BrAnon(idx) => {
-                        format!("the anonymous lifetime #{} defined on", idx + 1)
-                    }
-                    ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(),
-                    _ => {
-                        format!("the lifetime {} as defined on",
-                                fr.bound_region)
-                    }
-                };
-
-                let node = fr.scope.node_id(&self.region_maps);
-                let unknown;
-                let tag = match self.hir.find(node) {
-                    Some(hir_map::NodeBlock(_)) |
-                    Some(hir_map::NodeExpr(_)) => "body",
-                    Some(hir_map::NodeItem(it)) => item_scope_tag(&it),
-                    Some(hir_map::NodeTraitItem(it)) => trait_item_scope_tag(&it),
-                    Some(hir_map::NodeImplItem(it)) => impl_item_scope_tag(&it),
-
-                    // this really should not happen, but it does:
-                    // FIXME(#27942)
-                    Some(_) => {
-                        unknown = format!("unexpected node ({}) for scope {:?}.  \
-                                           Please report a bug.",
-                                          self.hir.node_to_string(node), fr.scope);
-                        &unknown
-                    }
-                    None => {
-                        unknown = format!("unknown node for scope {:?}.  \
-                                           Please report a bug.", fr.scope);
-                        &unknown
-                    }
-                };
-                let (msg, opt_span) = explain_span(self, tag, self.hir.span(node));
-                (format!("{} {}", prefix, msg), opt_span)
-            }
-
-            ty::ReStatic => ("the static lifetime".to_owned(), None),
-
-            ty::ReEmpty => ("the empty lifetime".to_owned(), None),
-
-            ty::ReEarlyBound(ref data) => (data.name.to_string(), None),
-
-            // FIXME(#13998) ReSkolemized should probably print like
-            // ReFree rather than dumping Debug output on the user.
-            //
-            // We shouldn't really be having unification failures with ReVar
-            // and ReLateBound though.
-            ty::ReSkolemized(..) |
-            ty::ReVar(_) |
-            ty::ReLateBound(..) |
-            ty::ReErased => {
-                (format!("lifetime {:?}", region), None)
-            }
-        };
-        let message = format!("{}{}{}", prefix, description, suffix);
-        if let Some(span) = span {
-            err.span_note(span, &message);
-        } else {
-            err.note(&message);
-        }
-    }
-}
-
-impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-    pub fn report_region_errors(&self,
-                                errors: &Vec<RegionResolutionError<'tcx>>) {
-        debug!("report_region_errors(): {} errors to start", errors.len());
-
-        // try to pre-process the errors, which will group some of them
-        // together into a `ProcessedErrors` group:
-        let errors = self.process_errors(errors);
-
-        debug!("report_region_errors: {} errors after preprocessing", errors.len());
-
-        for error in errors {
-            debug!("report_region_errors: error = {:?}", error);
-            match error.clone() {
-                ConcreteFailure(origin, sub, sup) => {
-                    self.report_concrete_failure(origin, sub, sup).emit();
-                }
-
-                GenericBoundFailure(kind, param_ty, sub) => {
-                    self.report_generic_bound_failure(kind, param_ty, sub);
-                }
-
-                SubSupConflict(var_origin,
-                               sub_origin, sub_r,
-                               sup_origin, sup_r) => {
-                    self.report_sub_sup_conflict(var_origin,
-                                                 sub_origin, sub_r,
-                                                 sup_origin, sup_r);
-                }
-            }
-        }
-    }
-
-    // This method goes through all the errors and try to group certain types
-    // of error together, for the purpose of suggesting explicit lifetime
-    // parameters to the user. This is done so that we can have a more
-    // complete view of what lifetimes should be the same.
-    // If the return value is an empty vector, it means that processing
-    // failed (so the return value of this method should not be used).
-    //
-    // The method also attempts to weed out messages that seem like
-    // duplicates that will be unhelpful to the end-user. But
-    // obviously it never weeds out ALL errors.
-    fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
-                      -> Vec<RegionResolutionError<'tcx>> {
-        debug!("process_errors()");
-
-        // We want to avoid reporting generic-bound failures if we can
-        // avoid it: these have a very high rate of being unhelpful in
-        // practice. This is because they are basically secondary
-        // checks that test the state of the region graph after the
-        // rest of inference is done, and the other kinds of errors
-        // indicate that the region constraint graph is internally
-        // inconsistent, so these test results are likely to be
-        // meaningless.
-        //
-        // Therefore, we filter them out of the list unless they are
-        // the only thing in the list.
-
-        let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e {
-            ConcreteFailure(..) => false,
-            SubSupConflict(..) => false,
-            GenericBoundFailure(..) => true,
-        };
-
-        if errors.iter().all(|e| is_bound_failure(e)) {
-            errors.clone()
-        } else {
-            errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect()
-        }
-    }
-
-    /// Adds a note if the types come from similarly named crates
-    fn check_and_note_conflicting_crates(&self,
-                                         err: &mut DiagnosticBuilder,
-                                         terr: &TypeError<'tcx>,
-                                         sp: Span) {
-        let report_path_match = |err: &mut DiagnosticBuilder, did1: DefId, did2: DefId| {
-            // Only external crates, if either is from a local
-            // module we could have false positives
-            if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate {
-                let exp_path = self.tcx.item_path_str(did1);
-                let found_path = self.tcx.item_path_str(did2);
-                // We compare strings because DefPath can be different
-                // for imported and non-imported crates
-                if exp_path == found_path {
-                    let crate_name = self.tcx.sess.cstore.crate_name(did1.krate);
-                    err.span_note(sp, &format!("Perhaps two different versions \
-                                                of crate `{}` are being used?",
-                                               crate_name));
-                }
-            }
-        };
-        match *terr {
-            TypeError::Sorts(ref exp_found) => {
-                // if they are both "path types", there's a chance of ambiguity
-                // due to different versions of the same crate
-                match (&exp_found.expected.sty, &exp_found.found.sty) {
-                    (&ty::TyAdt(exp_adt, _), &ty::TyAdt(found_adt, _)) => {
-                        report_path_match(err, exp_adt.did, found_adt.did);
-                    },
-                    _ => ()
-                }
-            },
-            TypeError::Traits(ref exp_found) => {
-                report_path_match(err, exp_found.expected, exp_found.found);
-            },
-            _ => () // FIXME(#22750) handle traits and stuff
-        }
-    }
-
-    fn note_error_origin(&self,
-                         err: &mut DiagnosticBuilder<'tcx>,
-                         cause: &ObligationCause<'tcx>)
-    {
-        match cause.code {
-            ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source {
-                hir::MatchSource::IfLetDesugar {..} => {
-                    err.span_note(arm_span, "`if let` arm with an incompatible type");
-                }
-                _ => {
-                    err.span_note(arm_span, "match arm with an incompatible type");
-                }
-            },
-            _ => ()
-        }
-    }
-
-    pub fn note_type_err(&self,
-                         diag: &mut DiagnosticBuilder<'tcx>,
-                         cause: &ObligationCause<'tcx>,
-                         secondary_span: Option<(Span, String)>,
-                         values: Option<ValuePairs<'tcx>>,
-                         terr: &TypeError<'tcx>)
-    {
-        let expected_found = match values {
-            None => None,
-            Some(values) => match self.values_str(&values) {
-                Some((expected, found)) => Some((expected, found)),
-                None => {
-                    // Derived error. Cancel the emitter.
-                    self.tcx.sess.diagnostic().cancel(diag);
-                    return
-                }
-            }
-        };
-
-        let span = cause.span;
-
-        if let Some((expected, found)) = expected_found {
-            let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
-                values.expected.is_primitive() && values.found.is_primitive()
-            } else {
-                false
-            };
-
-            if !is_simple_error {
-                if expected == found {
-                    if let &TypeError::Sorts(ref values) = terr {
-                        diag.note_expected_found_extra(
-                            &"type", &expected, &found,
-                            &format!(" ({})", values.expected.sort_string(self.tcx)),
-                            &format!(" ({})", values.found.sort_string(self.tcx)));
-                    } else {
-                        diag.note_expected_found(&"type", &expected, &found);
-                    }
-                } else {
-                    diag.note_expected_found(&"type", &expected, &found);
-                }
-            }
-        }
-
-        diag.span_label(span, &terr);
-        if let Some((sp, msg)) = secondary_span {
-            diag.span_label(sp, &msg);
-        }
-
-        self.note_error_origin(diag, &cause);
-        self.check_and_note_conflicting_crates(diag, terr, span);
-        self.tcx.note_and_explain_type_err(diag, terr, span);
-    }
-
-    pub fn note_issue_32330(&self,
-                            diag: &mut DiagnosticBuilder<'tcx>,
-                            terr: &TypeError<'tcx>)
-    {
-        debug!("note_issue_32330: terr={:?}", terr);
-        match *terr {
-            TypeError::RegionsInsufficientlyPolymorphic(_, &Region::ReVar(vid)) |
-            TypeError::RegionsOverlyPolymorphic(_, &Region::ReVar(vid)) => {
-                match self.region_vars.var_origin(vid) {
-                    RegionVariableOrigin::EarlyBoundRegion(_, _, Some(Issue32330 {
-                        fn_def_id,
-                        region_name
-                    })) => {
-                        diag.note(
-                            &format!("lifetime parameter `{0}` declared on fn `{1}` \
-                                      appears only in the return type, \
-                                      but here is required to be higher-ranked, \
-                                      which means that `{0}` must appear in both \
-                                      argument and return types",
-                                     region_name,
-                                     self.tcx.item_path_str(fn_def_id)));
-                        diag.note(
-                            &format!("this error is the result of a recent bug fix; \
-                                      for more information, see issue #33685 \
-                                      <https://github.com/rust-lang/rust/issues/33685>"));
-                    }
-                    _ => { }
-                }
-            }
-            _ => { }
-        }
-    }
-
-    pub fn report_and_explain_type_error(&self,
-                                         trace: TypeTrace<'tcx>,
-                                         terr: &TypeError<'tcx>)
-                                         -> DiagnosticBuilder<'tcx>
-    {
-        let span = trace.cause.span;
-        let failure_str = trace.cause.as_failure_str();
-        let mut diag = match trace.cause.code {
-            ObligationCauseCode::IfExpressionWithNoElse => {
-                struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
-            }
-            ObligationCauseCode::MainFunctionType => {
-                struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str)
-            }
-            _ => {
-                struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str)
-            }
-        };
-        self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr);
-        self.note_issue_32330(&mut diag, terr);
-        diag
-    }
-
-    /// Returns a string of the form "expected `{}`, found `{}`".
-    fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> {
-        match *values {
-            infer::Types(ref exp_found) => self.expected_found_str(exp_found),
-            infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
-            infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found),
-        }
-    }
-
-    fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
-        &self,
-        exp_found: &ty::error::ExpectedFound<T>)
-        -> Option<(String, String)>
-    {
-        let exp_found = self.resolve_type_vars_if_possible(exp_found);
-        if exp_found.references_error() {
-            return None;
-        }
-
-        Some((format!("{}", exp_found.expected), format!("{}", exp_found.found)))
-    }
-
-    fn report_generic_bound_failure(&self,
-                                    origin: SubregionOrigin<'tcx>,
-                                    bound_kind: GenericKind<'tcx>,
-                                    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
-        // where the error was detected. But that span is not readily
-        // accessible.
-
-        let labeled_user_string = match bound_kind {
-            GenericKind::Param(ref p) =>
-                format!("the parameter type `{}`", p),
-            GenericKind::Projection(ref p) =>
-                format!("the associated type `{}`", p),
-        };
-
-        if let SubregionOrigin::CompareImplMethodObligation {
-            span, item_name, impl_item_def_id, trait_item_def_id, lint_id
-        } = origin {
-            self.report_extra_impl_obligation(span,
-                                              item_name,
-                                              impl_item_def_id,
-                                              trait_item_def_id,
-                                              &format!("`{}: {}`", bound_kind, sub),
-                                              lint_id)
-                .emit();
-            return;
-        }
-
-        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,
-                                               origin.span(),
-                                               E0309,
-                                               "{} may not live long enough",
-                                               labeled_user_string);
-                err.help(&format!("consider adding an explicit lifetime bound `{}: {}`...",
-                         bound_kind,
-                         sub));
-                err
-            }
-
-            ty::ReStatic => {
-                // Does the required lifetime have a nice name we can print?
-                let mut err = struct_span_err!(self.tcx.sess,
-                                               origin.span(),
-                                               E0310,
-                                               "{} may not live long enough",
-                                               labeled_user_string);
-                err.help(&format!("consider adding an explicit lifetime \
-                                   bound `{}: 'static`...",
-                                  bound_kind));
-                err
-            }
-
-            _ => {
-                // If not, be less specific.
-                let mut err = struct_span_err!(self.tcx.sess,
-                                               origin.span(),
-                                               E0311,
-                                               "{} may not live long enough",
-                                               labeled_user_string);
-                err.help(&format!("consider adding an explicit lifetime bound for `{}`",
-                                  bound_kind));
-                self.tcx.note_and_explain_region(
-                    &mut err,
-                    &format!("{} must be valid for ", labeled_user_string),
-                    sub,
-                    "...");
-                err
-            }
-        };
-
-        self.note_region_origin(&mut err, &origin);
-        err.emit();
-    }
-
-    fn report_concrete_failure(&self,
-                               origin: SubregionOrigin<'tcx>,
-                               sub: &'tcx Region,
-                               sup: &'tcx Region)
-                                -> DiagnosticBuilder<'tcx> {
-        match origin {
-            infer::Subtype(trace) => {
-                let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
-                self.report_and_explain_type_error(trace, &terr)
-            }
-            infer::Reborrow(span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0312,
-                    "lifetime of reference outlives \
-                     lifetime of borrowed content...");
-                self.tcx.note_and_explain_region(&mut err,
-                    "...the reference is valid for ",
-                    sub,
-                    "...");
-                self.tcx.note_and_explain_region(&mut err,
-                    "...but the borrowed content is only valid for ",
-                    sup,
-                    "");
-                err
-            }
-            infer::ReborrowUpvar(span, ref upvar_id) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0313,
-                    "lifetime of borrowed pointer outlives \
-                            lifetime of captured variable `{}`...",
-                            self.tcx.local_var_name_str(upvar_id.var_id));
-                self.tcx.note_and_explain_region(&mut err,
-                    "...the borrowed pointer is valid for ",
-                    sub,
-                    "...");
-                self.tcx.note_and_explain_region(&mut err,
-                    &format!("...but `{}` is only valid for ",
-                             self.tcx.local_var_name_str(upvar_id.var_id)),
-                    sup,
-                    "");
-                err
-            }
-            infer::InfStackClosure(span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0314,
-                    "closure outlives stack frame");
-                self.tcx.note_and_explain_region(&mut err,
-                    "...the closure must be valid for ",
-                    sub,
-                    "...");
-                self.tcx.note_and_explain_region(&mut err,
-                    "...but the closure's stack frame is only valid for ",
-                    sup,
-                    "");
-                err
-            }
-            infer::InvokeClosure(span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0315,
-                    "cannot invoke closure outside of its lifetime");
-                self.tcx.note_and_explain_region(&mut err,
-                    "the closure is only valid for ",
-                    sup,
-                    "");
-                err
-            }
-            infer::DerefPointer(span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0473,
-                          "dereference of reference outside its lifetime");
-                self.tcx.note_and_explain_region(&mut err,
-                    "the reference is only valid for ",
-                    sup,
-                    "");
-                err
-            }
-            infer::FreeVariable(span, id) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0474,
-                          "captured variable `{}` does not outlive the enclosing closure",
-                          self.tcx.local_var_name_str(id));
-                self.tcx.note_and_explain_region(&mut err,
-                    "captured variable is valid for ",
-                    sup,
-                    "");
-                self.tcx.note_and_explain_region(&mut err,
-                    "closure is valid for ",
-                    sub,
-                    "");
-                err
-            }
-            infer::IndexSlice(span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0475,
-                          "index of slice outside its lifetime");
-                self.tcx.note_and_explain_region(&mut err,
-                    "the slice is only valid for ",
-                    sup,
-                    "");
-                err
-            }
-            infer::RelateObjectBound(span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0476,
-                          "lifetime of the source pointer does not outlive \
-                           lifetime bound of the object type");
-                self.tcx.note_and_explain_region(&mut err,
-                    "object type is valid for ",
-                    sub,
-                    "");
-                self.tcx.note_and_explain_region(&mut err,
-                    "source pointer is only valid for ",
-                    sup,
-                    "");
-                err
-            }
-            infer::RelateParamBound(span, ty) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0477,
-                          "the type `{}` does not fulfill the required lifetime",
-                          self.ty_to_string(ty));
-                self.tcx.note_and_explain_region(&mut err,
-                                        "type must outlive ",
-                                        sub,
-                                        "");
-                err
-            }
-            infer::RelateRegionParamBound(span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0478,
-                          "lifetime bound not satisfied");
-                self.tcx.note_and_explain_region(&mut err,
-                    "lifetime parameter instantiated with ",
-                    sup,
-                    "");
-                self.tcx.note_and_explain_region(&mut err,
-                    "but lifetime parameter must outlive ",
-                    sub,
-                    "");
-                err
-            }
-            infer::RelateDefaultParamBound(span, ty) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0479,
-                          "the type `{}` (provided as the value of \
-                           a type parameter) is not valid at this point",
-                          self.ty_to_string(ty));
-                self.tcx.note_and_explain_region(&mut err,
-                                        "type must outlive ",
-                                        sub,
-                                        "");
-                err
-            }
-            infer::CallRcvr(span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0480,
-                          "lifetime of method receiver does not outlive \
-                           the method call");
-                self.tcx.note_and_explain_region(&mut err,
-                    "the receiver is only valid for ",
-                    sup,
-                    "");
-                err
-            }
-            infer::CallArg(span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0481,
-                          "lifetime of function argument does not outlive \
-                           the function call");
-                self.tcx.note_and_explain_region(&mut err,
-                    "the function argument is only valid for ",
-                    sup,
-                    "");
-                err
-            }
-            infer::CallReturn(span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0482,
-                          "lifetime of return value does not outlive \
-                           the function call");
-                self.tcx.note_and_explain_region(&mut err,
-                    "the return value is only valid for ",
-                    sup,
-                    "");
-                err
-            }
-            infer::Operand(span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0483,
-                          "lifetime of operand does not outlive \
-                           the operation");
-                self.tcx.note_and_explain_region(&mut err,
-                    "the operand is only valid for ",
-                    sup,
-                    "");
-                err
-            }
-            infer::AddrOf(span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0484,
-                          "reference is not valid at the time of borrow");
-                self.tcx.note_and_explain_region(&mut err,
-                    "the borrow is only valid for ",
-                    sup,
-                    "");
-                err
-            }
-            infer::AutoBorrow(span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0485,
-                          "automatically reference is not valid \
-                           at the time of borrow");
-                self.tcx.note_and_explain_region(&mut err,
-                    "the automatic borrow is only valid for ",
-                    sup,
-                    "");
-                err
-            }
-            infer::ExprTypeIsNotInScope(t, span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0486,
-                          "type of expression contains references \
-                           that are not valid during the expression: `{}`",
-                          self.ty_to_string(t));
-                self.tcx.note_and_explain_region(&mut err,
-                    "type is only valid for ",
-                    sup,
-                    "");
-                err
-            }
-            infer::SafeDestructor(span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0487,
-                          "unsafe use of destructor: destructor might be called \
-                           while references are dead");
-                // FIXME (22171): terms "super/subregion" are suboptimal
-                self.tcx.note_and_explain_region(&mut err,
-                    "superregion: ",
-                    sup,
-                    "");
-                self.tcx.note_and_explain_region(&mut err,
-                    "subregion: ",
-                    sub,
-                    "");
-                err
-            }
-            infer::BindingTypeIsNotValidAtDecl(span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0488,
-                          "lifetime of variable does not enclose its declaration");
-                self.tcx.note_and_explain_region(&mut err,
-                    "the variable is only valid for ",
-                    sup,
-                    "");
-                err
-            }
-            infer::ParameterInScope(_, span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0489,
-                          "type/lifetime parameter not in scope here");
-                self.tcx.note_and_explain_region(&mut err,
-                    "the parameter is only valid for ",
-                    sub,
-                    "");
-                err
-            }
-            infer::DataBorrowed(ty, span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0490,
-                          "a value of type `{}` is borrowed for too long",
-                          self.ty_to_string(ty));
-                self.tcx.note_and_explain_region(&mut err, "the type is valid for ", sub, "");
-                self.tcx.note_and_explain_region(&mut err, "but the borrow lasts for ", sup, "");
-                err
-            }
-            infer::ReferenceOutlivesReferent(ty, span) => {
-                let mut err = struct_span_err!(self.tcx.sess, span, E0491,
-                          "in type `{}`, reference has a longer lifetime \
-                           than the data it references",
-                          self.ty_to_string(ty));
-                self.tcx.note_and_explain_region(&mut err,
-                    "the pointer is valid for ",
-                    sub,
-                    "");
-                self.tcx.note_and_explain_region(&mut err,
-                    "but the referenced data is only valid for ",
-                    sup,
-                    "");
-                err
-            }
-            infer::CompareImplMethodObligation { span,
-                                                 item_name,
-                                                 impl_item_def_id,
-                                                 trait_item_def_id,
-                                                 lint_id } => {
-                self.report_extra_impl_obligation(span,
-                                                  item_name,
-                                                  impl_item_def_id,
-                                                  trait_item_def_id,
-                                                  &format!("`{}: {}`", sup, sub),
-                                                  lint_id)
-            }
-        }
-    }
-
-    fn report_sub_sup_conflict(&self,
-                               var_origin: RegionVariableOrigin,
-                               sub_origin: SubregionOrigin<'tcx>,
-                               sub_region: &'tcx Region,
-                               sup_origin: SubregionOrigin<'tcx>,
-                               sup_region: &'tcx Region) {
-        let mut err = self.report_inference_failure(var_origin);
-
-        self.tcx.note_and_explain_region(&mut err,
-            "first, the lifetime cannot outlive ",
-            sup_region,
-            "...");
-
-        self.note_region_origin(&mut err, &sup_origin);
-
-        self.tcx.note_and_explain_region(&mut err,
-            "but, the lifetime must be valid for ",
-            sub_region,
-            "...");
-
-        self.note_region_origin(&mut err, &sub_origin);
-        err.emit();
-    }
-}
-
-impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-    fn report_inference_failure(&self,
-                                var_origin: RegionVariableOrigin)
-                                -> DiagnosticBuilder<'tcx> {
-        let br_string = |br: ty::BoundRegion| {
-            let mut s = br.to_string();
-            if !s.is_empty() {
-                s.push_str(" ");
-            }
-            s
-        };
-        let var_description = match var_origin {
-            infer::MiscVariable(_) => "".to_string(),
-            infer::PatternRegion(_) => " for pattern".to_string(),
-            infer::AddrOfRegion(_) => " for borrow expression".to_string(),
-            infer::Autoref(_) => " for autoref".to_string(),
-            infer::Coercion(_) => " for automatic coercion".to_string(),
-            infer::LateBoundRegion(_, br, infer::FnCall) => {
-                format!(" for lifetime parameter {}in function call",
-                        br_string(br))
-            }
-            infer::LateBoundRegion(_, br, infer::HigherRankedType) => {
-                format!(" for lifetime parameter {}in generic type", br_string(br))
-            }
-            infer::LateBoundRegion(_, br, infer::AssocTypeProjection(type_name)) => {
-                format!(" for lifetime parameter {}in trait containing associated type `{}`",
-                        br_string(br), type_name)
-            }
-            infer::EarlyBoundRegion(_, name, _) => {
-                format!(" for lifetime parameter `{}`",
-                        name)
-            }
-            infer::BoundRegionInCoherence(name) => {
-                format!(" for lifetime parameter `{}` in coherence check",
-                        name)
-            }
-            infer::UpvarRegion(ref upvar_id, _) => {
-                format!(" for capture of `{}` by closure",
-                        self.tcx.local_var_name_str(upvar_id.var_id).to_string())
-            }
-        };
-
-        struct_span_err!(self.tcx.sess, var_origin.span(), E0495,
-                  "cannot infer an appropriate lifetime{} \
-                   due to conflicting requirements",
-                  var_description)
-    }
-
-    fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) {
-        match *origin {
-            infer::Subtype(ref trace) => {
-                if let Some((expected, found)) = self.values_str(&trace.values) {
-                    // FIXME: do we want a "the" here?
-                    err.span_note(
-                        trace.cause.span,
-                        &format!("...so that {} (expected {}, found {})",
-                                 trace.cause.as_requirement_str(), expected, found));
-                } else {
-                    // FIXME: this really should be handled at some earlier stage. Our
-                    // handling of region checking when type errors are present is
-                    // *terrible*.
-
-                    err.span_note(
-                        trace.cause.span,
-                        &format!("...so that {}",
-                                 trace.cause.as_requirement_str()));
-                }
-            }
-            infer::Reborrow(span) => {
-                err.span_note(
-                    span,
-                    "...so that reference does not outlive \
-                    borrowed content");
-            }
-            infer::ReborrowUpvar(span, ref upvar_id) => {
-                err.span_note(
-                    span,
-                    &format!(
-                        "...so that closure can access `{}`",
-                        self.tcx.local_var_name_str(upvar_id.var_id)
-                            .to_string()));
-            }
-            infer::InfStackClosure(span) => {
-                err.span_note(
-                    span,
-                    "...so that closure does not outlive its stack frame");
-            }
-            infer::InvokeClosure(span) => {
-                err.span_note(
-                    span,
-                    "...so that closure is not invoked outside its lifetime");
-            }
-            infer::DerefPointer(span) => {
-                err.span_note(
-                    span,
-                    "...so that pointer is not dereferenced \
-                    outside its lifetime");
-            }
-            infer::FreeVariable(span, id) => {
-                err.span_note(
-                    span,
-                    &format!("...so that captured variable `{}` \
-                            does not outlive the enclosing closure",
-                            self.tcx.local_var_name_str(id)));
-            }
-            infer::IndexSlice(span) => {
-                err.span_note(
-                    span,
-                    "...so that slice is not indexed outside the lifetime");
-            }
-            infer::RelateObjectBound(span) => {
-                err.span_note(
-                    span,
-                    "...so that it can be closed over into an object");
-            }
-            infer::CallRcvr(span) => {
-                err.span_note(
-                    span,
-                    "...so that method receiver is valid for the method call");
-            }
-            infer::CallArg(span) => {
-                err.span_note(
-                    span,
-                    "...so that argument is valid for the call");
-            }
-            infer::CallReturn(span) => {
-                err.span_note(
-                    span,
-                    "...so that return value is valid for the call");
-            }
-            infer::Operand(span) => {
-                err.span_note(
-                    span,
-                    "...so that operand is valid for operation");
-            }
-            infer::AddrOf(span) => {
-                err.span_note(
-                    span,
-                    "...so that reference is valid \
-                     at the time of borrow");
-            }
-            infer::AutoBorrow(span) => {
-                err.span_note(
-                    span,
-                    "...so that auto-reference is valid \
-                     at the time of borrow");
-            }
-            infer::ExprTypeIsNotInScope(t, span) => {
-                err.span_note(
-                    span,
-                    &format!("...so type `{}` of expression is valid during the \
-                             expression",
-                            self.ty_to_string(t)));
-            }
-            infer::BindingTypeIsNotValidAtDecl(span) => {
-                err.span_note(
-                    span,
-                    "...so that variable is valid at time of its declaration");
-            }
-            infer::ParameterInScope(_, span) => {
-                err.span_note(
-                    span,
-                    "...so that a type/lifetime parameter is in scope here");
-            }
-            infer::DataBorrowed(ty, span) => {
-                err.span_note(
-                    span,
-                    &format!("...so that the type `{}` is not borrowed for too long",
-                             self.ty_to_string(ty)));
-            }
-            infer::ReferenceOutlivesReferent(ty, span) => {
-                err.span_note(
-                    span,
-                    &format!("...so that the reference type `{}` \
-                             does not outlive the data it points at",
-                            self.ty_to_string(ty)));
-            }
-            infer::RelateParamBound(span, t) => {
-                err.span_note(
-                    span,
-                    &format!("...so that the type `{}` \
-                             will meet its required lifetime bounds",
-                            self.ty_to_string(t)));
-            }
-            infer::RelateDefaultParamBound(span, t) => {
-                err.span_note(
-                    span,
-                    &format!("...so that type parameter \
-                             instantiated with `{}`, \
-                             will meet its declared lifetime bounds",
-                            self.ty_to_string(t)));
-            }
-            infer::RelateRegionParamBound(span) => {
-                err.span_note(
-                    span,
-                    "...so that the declared lifetime parameter bounds \
-                                are satisfied");
-            }
-            infer::SafeDestructor(span) => {
-                err.span_note(
-                    span,
-                    "...so that references are valid when the destructor \
-                     runs");
-            }
-            infer::CompareImplMethodObligation { span, .. } => {
-                err.span_note(
-                    span,
-                    "...so that the definition in impl matches the definition from the trait");
-            }
-        }
-    }
-}
-
-impl<'tcx> ObligationCause<'tcx> {
-    fn as_failure_str(&self) -> &'static str {
-        use traits::ObligationCauseCode::*;
-        match self.code {
-            CompareImplMethodObligation { .. } => "method not compatible with trait",
-            MatchExpressionArm { source, .. } => match source {
-                hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
-                _ => "match arms have incompatible types",
-            },
-            IfExpression => "if and else have incompatible types",
-            IfExpressionWithNoElse => "if may be missing an else clause",
-            EquatePredicate => "equality predicate not satisfied",
-            MainFunctionType => "main function has wrong type",
-            StartFunctionType => "start function has wrong type",
-            IntrinsicType => "intrinsic has wrong type",
-            MethodReceiver => "mismatched method receiver",
-            _ => "mismatched types",
-        }
-    }
-
-    fn as_requirement_str(&self) -> &'static str {
-        use traits::ObligationCauseCode::*;
-        match self.code {
-            CompareImplMethodObligation { .. } => "method type is compatible with trait",
-            ExprAssignable => "expression is assignable",
-            MatchExpressionArm { source, .. } => match source {
-                hir::MatchSource::IfLetDesugar{..} => "`if let` arms have compatible types",
-                _ => "match arms have compatible types",
-            },
-            IfExpression => "if and else have compatible types",
-            IfExpressionWithNoElse => "if missing an else returns ()",
-            EquatePredicate => "equality where clause is satisfied",
-            MainFunctionType => "`main` function has the correct type",
-            StartFunctionType => "`start` function has the correct type",
-            IntrinsicType => "intrinsic has the correct type",
-            MethodReceiver => "method receiver has the correct type",
-            _ => "types are compatible",
-        }
-    }
-}
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
new file mode 100644 (file)
index 0000000..21139c8
--- /dev/null
@@ -0,0 +1,693 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Error Reporting Code for the inference engine
+//!
+//! Because of the way inference, and in particular region inference,
+//! works, it often happens that errors are not detected until far after
+//! the relevant line of code has been type-checked. Therefore, there is
+//! an elaborate system to track why a particular constraint in the
+//! inference graph arose so that we can explain to the user what gave
+//! rise to a particular error.
+//!
+//! The basis of the system are the "origin" types. An "origin" is the
+//! reason that a constraint or inference variable arose. There are
+//! different "origin" enums for different kinds of constraints/variables
+//! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has
+//! a span, but also more information so that we can generate a meaningful
+//! error message.
+//!
+//! Having a catalogue of all the different reasons an error can arise is
+//! also useful for other reasons, like cross-referencing FAQs etc, though
+//! we are not really taking advantage of this yet.
+//!
+//! # Region Inference
+//!
+//! Region inference is particularly tricky because it always succeeds "in
+//! the moment" and simply registers a constraint. Then, at the end, we
+//! can compute the full graph and report errors, so we need to be able to
+//! store and later report what gave rise to the conflicting constraints.
+//!
+//! # Subtype Trace
+//!
+//! Determining whether `T1 <: T2` often involves a number of subtypes and
+//! subconstraints along the way. A "TypeTrace" is an extended version
+//! of an origin that traces the types and other values that were being
+//! compared. It is not necessarily comprehensive (in fact, at the time of
+//! this writing it only tracks the root values being compared) but I'd
+//! like to extend it to include significant "waypoints". For example, if
+//! you are comparing `(T1, T2) <: (T3, T4)`, and the problem is that `T2
+//! <: T4` fails, I'd like the trace to include enough information to say
+//! "in the 2nd element of the tuple". Similarly, failures when comparing
+//! arguments or return types in fn types should be able to cite the
+//! specific position, etc.
+//!
+//! # Reality vs plan
+//!
+//! Of course, there is still a LOT of code in typeck that has yet to be
+//! ported to this system, and which relies on string concatenation at the
+//! time of error detection.
+
+use infer;
+use super::{InferCtxt, TypeTrace, SubregionOrigin, RegionVariableOrigin, ValuePairs};
+use super::region_inference::{RegionResolutionError, ConcreteFailure, SubSupConflict,
+                              GenericBoundFailure, GenericKind};
+
+use std::fmt;
+use hir;
+use hir::map as hir_map;
+use hir::def_id::DefId;
+use middle::region;
+use traits::{ObligationCause, ObligationCauseCode};
+use ty::{self, TyCtxt, TypeFoldable};
+use ty::{Region, Issue32330};
+use ty::error::TypeError;
+use syntax_pos::{Pos, Span};
+use errors::DiagnosticBuilder;
+
+mod note;
+
+impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
+    pub fn note_and_explain_region(self,
+                                   err: &mut DiagnosticBuilder,
+                                   prefix: &str,
+                                   region: &'tcx ty::Region,
+                                   suffix: &str) {
+        fn item_scope_tag(item: &hir::Item) -> &'static str {
+            match item.node {
+                hir::ItemImpl(..) => "impl",
+                hir::ItemStruct(..) => "struct",
+                hir::ItemUnion(..) => "union",
+                hir::ItemEnum(..) => "enum",
+                hir::ItemTrait(..) => "trait",
+                hir::ItemFn(..) => "function body",
+                _ => "item"
+            }
+        }
+
+        fn trait_item_scope_tag(item: &hir::TraitItem) -> &'static str {
+            match item.node {
+                hir::TraitItemKind::Method(..) => "method body",
+                hir::TraitItemKind::Const(..) |
+                hir::TraitItemKind::Type(..) => "associated item"
+            }
+        }
+
+        fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str {
+            match item.node {
+                hir::ImplItemKind::Method(..) => "method body",
+                hir::ImplItemKind::Const(..) |
+                hir::ImplItemKind::Type(_) => "associated item"
+            }
+        }
+
+        fn explain_span<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                        heading: &str, span: Span)
+                                        -> (String, Option<Span>) {
+            let lo = tcx.sess.codemap().lookup_char_pos_adj(span.lo);
+            (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize()),
+             Some(span))
+        }
+
+        let (description, span) = match *region {
+            ty::ReScope(scope) => {
+                let new_string;
+                let unknown_scope = || {
+                    format!("{}unknown scope: {:?}{}.  Please report a bug.",
+                            prefix, scope, suffix)
+                };
+                let span = match scope.span(&self.region_maps, &self.hir) {
+                    Some(s) => s,
+                    None => {
+                        err.note(&unknown_scope());
+                        return;
+                    }
+                };
+                let tag = match self.hir.find(scope.node_id(&self.region_maps)) {
+                    Some(hir_map::NodeBlock(_)) => "block",
+                    Some(hir_map::NodeExpr(expr)) => match expr.node {
+                        hir::ExprCall(..) => "call",
+                        hir::ExprMethodCall(..) => "method call",
+                        hir::ExprMatch(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
+                        hir::ExprMatch(.., hir::MatchSource::WhileLetDesugar) =>  "while let",
+                        hir::ExprMatch(.., hir::MatchSource::ForLoopDesugar) =>  "for",
+                        hir::ExprMatch(..) => "match",
+                        _ => "expression",
+                    },
+                    Some(hir_map::NodeStmt(_)) => "statement",
+                    Some(hir_map::NodeItem(it)) => item_scope_tag(&it),
+                    Some(hir_map::NodeTraitItem(it)) => trait_item_scope_tag(&it),
+                    Some(hir_map::NodeImplItem(it)) => impl_item_scope_tag(&it),
+                    Some(_) | None => {
+                        err.span_note(span, &unknown_scope());
+                        return;
+                    }
+                };
+                let scope_decorated_tag = match self.region_maps.code_extent_data(scope) {
+                    region::CodeExtentData::Misc(_) => tag,
+                    region::CodeExtentData::CallSiteScope { .. } => {
+                        "scope of call-site for function"
+                    }
+                    region::CodeExtentData::ParameterScope { .. } => {
+                        "scope of function body"
+                    }
+                    region::CodeExtentData::DestructionScope(_) => {
+                        new_string = format!("destruction scope surrounding {}", tag);
+                        &new_string[..]
+                    }
+                    region::CodeExtentData::Remainder(r) => {
+                        new_string = format!("block suffix following statement {}",
+                                             r.first_statement_index);
+                        &new_string[..]
+                    }
+                };
+                explain_span(self, scope_decorated_tag, span)
+            }
+
+            ty::ReFree(ref fr) => {
+                let prefix = match fr.bound_region {
+                    ty::BrAnon(idx) => {
+                        format!("the anonymous lifetime #{} defined on", idx + 1)
+                    }
+                    ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(),
+                    _ => {
+                        format!("the lifetime {} as defined on",
+                                fr.bound_region)
+                    }
+                };
+
+                let node = fr.scope.node_id(&self.region_maps);
+                let unknown;
+                let tag = match self.hir.find(node) {
+                    Some(hir_map::NodeBlock(_)) |
+                    Some(hir_map::NodeExpr(_)) => "body",
+                    Some(hir_map::NodeItem(it)) => item_scope_tag(&it),
+                    Some(hir_map::NodeTraitItem(it)) => trait_item_scope_tag(&it),
+                    Some(hir_map::NodeImplItem(it)) => impl_item_scope_tag(&it),
+
+                    // this really should not happen, but it does:
+                    // FIXME(#27942)
+                    Some(_) => {
+                        unknown = format!("unexpected node ({}) for scope {:?}.  \
+                                           Please report a bug.",
+                                          self.hir.node_to_string(node), fr.scope);
+                        &unknown
+                    }
+                    None => {
+                        unknown = format!("unknown node for scope {:?}.  \
+                                           Please report a bug.", fr.scope);
+                        &unknown
+                    }
+                };
+                let (msg, opt_span) = explain_span(self, tag, self.hir.span(node));
+                (format!("{} {}", prefix, msg), opt_span)
+            }
+
+            ty::ReStatic => ("the static lifetime".to_owned(), None),
+
+            ty::ReEmpty => ("the empty lifetime".to_owned(), None),
+
+            ty::ReEarlyBound(ref data) => (data.name.to_string(), None),
+
+            // FIXME(#13998) ReSkolemized should probably print like
+            // ReFree rather than dumping Debug output on the user.
+            //
+            // We shouldn't really be having unification failures with ReVar
+            // and ReLateBound though.
+            ty::ReSkolemized(..) |
+            ty::ReVar(_) |
+            ty::ReLateBound(..) |
+            ty::ReErased => {
+                (format!("lifetime {:?}", region), None)
+            }
+        };
+        let message = format!("{}{}{}", prefix, description, suffix);
+        if let Some(span) = span {
+            err.span_note(span, &message);
+        } else {
+            err.note(&message);
+        }
+    }
+}
+
+impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
+    pub fn report_region_errors(&self,
+                                errors: &Vec<RegionResolutionError<'tcx>>) {
+        debug!("report_region_errors(): {} errors to start", errors.len());
+
+        // try to pre-process the errors, which will group some of them
+        // together into a `ProcessedErrors` group:
+        let errors = self.process_errors(errors);
+
+        debug!("report_region_errors: {} errors after preprocessing", errors.len());
+
+        for error in errors {
+            debug!("report_region_errors: error = {:?}", error);
+            match error.clone() {
+                ConcreteFailure(origin, sub, sup) => {
+                    self.report_concrete_failure(origin, sub, sup).emit();
+                }
+
+                GenericBoundFailure(kind, param_ty, sub) => {
+                    self.report_generic_bound_failure(kind, param_ty, sub);
+                }
+
+                SubSupConflict(var_origin,
+                               sub_origin, sub_r,
+                               sup_origin, sup_r) => {
+                    self.report_sub_sup_conflict(var_origin,
+                                                 sub_origin, sub_r,
+                                                 sup_origin, sup_r);
+                }
+            }
+        }
+    }
+
+    // This method goes through all the errors and try to group certain types
+    // of error together, for the purpose of suggesting explicit lifetime
+    // parameters to the user. This is done so that we can have a more
+    // complete view of what lifetimes should be the same.
+    // If the return value is an empty vector, it means that processing
+    // failed (so the return value of this method should not be used).
+    //
+    // The method also attempts to weed out messages that seem like
+    // duplicates that will be unhelpful to the end-user. But
+    // obviously it never weeds out ALL errors.
+    fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
+                      -> Vec<RegionResolutionError<'tcx>> {
+        debug!("process_errors()");
+
+        // We want to avoid reporting generic-bound failures if we can
+        // avoid it: these have a very high rate of being unhelpful in
+        // practice. This is because they are basically secondary
+        // checks that test the state of the region graph after the
+        // rest of inference is done, and the other kinds of errors
+        // indicate that the region constraint graph is internally
+        // inconsistent, so these test results are likely to be
+        // meaningless.
+        //
+        // Therefore, we filter them out of the list unless they are
+        // the only thing in the list.
+
+        let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e {
+            ConcreteFailure(..) => false,
+            SubSupConflict(..) => false,
+            GenericBoundFailure(..) => true,
+        };
+
+        if errors.iter().all(|e| is_bound_failure(e)) {
+            errors.clone()
+        } else {
+            errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect()
+        }
+    }
+
+    /// Adds a note if the types come from similarly named crates
+    fn check_and_note_conflicting_crates(&self,
+                                         err: &mut DiagnosticBuilder,
+                                         terr: &TypeError<'tcx>,
+                                         sp: Span) {
+        let report_path_match = |err: &mut DiagnosticBuilder, did1: DefId, did2: DefId| {
+            // Only external crates, if either is from a local
+            // module we could have false positives
+            if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate {
+                let exp_path = self.tcx.item_path_str(did1);
+                let found_path = self.tcx.item_path_str(did2);
+                // We compare strings because DefPath can be different
+                // for imported and non-imported crates
+                if exp_path == found_path {
+                    let crate_name = self.tcx.sess.cstore.crate_name(did1.krate);
+                    err.span_note(sp, &format!("Perhaps two different versions \
+                                                of crate `{}` are being used?",
+                                               crate_name));
+                }
+            }
+        };
+        match *terr {
+            TypeError::Sorts(ref exp_found) => {
+                // if they are both "path types", there's a chance of ambiguity
+                // due to different versions of the same crate
+                match (&exp_found.expected.sty, &exp_found.found.sty) {
+                    (&ty::TyAdt(exp_adt, _), &ty::TyAdt(found_adt, _)) => {
+                        report_path_match(err, exp_adt.did, found_adt.did);
+                    },
+                    _ => ()
+                }
+            },
+            TypeError::Traits(ref exp_found) => {
+                report_path_match(err, exp_found.expected, exp_found.found);
+            },
+            _ => () // FIXME(#22750) handle traits and stuff
+        }
+    }
+
+    fn note_error_origin(&self,
+                         err: &mut DiagnosticBuilder<'tcx>,
+                         cause: &ObligationCause<'tcx>)
+    {
+        match cause.code {
+            ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source {
+                hir::MatchSource::IfLetDesugar {..} => {
+                    err.span_note(arm_span, "`if let` arm with an incompatible type");
+                }
+                _ => {
+                    err.span_note(arm_span, "match arm with an incompatible type");
+                }
+            },
+            _ => ()
+        }
+    }
+
+    pub fn note_type_err(&self,
+                         diag: &mut DiagnosticBuilder<'tcx>,
+                         cause: &ObligationCause<'tcx>,
+                         secondary_span: Option<(Span, String)>,
+                         values: Option<ValuePairs<'tcx>>,
+                         terr: &TypeError<'tcx>)
+    {
+        let (expected_found, is_simple_error) = match values {
+            None => (None, false),
+            Some(values) => {
+                let is_simple_error = match values {
+                    ValuePairs::Types(exp_found) => {
+                        exp_found.expected.is_primitive() && exp_found.found.is_primitive()
+                    }
+                    _ => false,
+                };
+                let vals = match self.values_str(&values) {
+                    Some((expected, found)) => Some((expected, found)),
+                    None => {
+                        // Derived error. Cancel the emitter.
+                        self.tcx.sess.diagnostic().cancel(diag);
+                        return
+                    }
+                };
+                (vals, is_simple_error)
+            }
+        };
+
+        let span = cause.span;
+
+        if let Some((expected, found)) = expected_found {
+            match (terr, is_simple_error, expected == found) {
+                (&TypeError::Sorts(ref values), false,  true) => {
+                    diag.note_expected_found_extra(
+                        &"type", &expected, &found,
+                        &format!(" ({})", values.expected.sort_string(self.tcx)),
+                        &format!(" ({})", values.found.sort_string(self.tcx)));
+                }
+                (_, false,  _) => {
+                    diag.note_expected_found(&"type", &expected, &found);
+                }
+                _ => (),
+            }
+        }
+
+        diag.span_label(span, &terr);
+        if let Some((sp, msg)) = secondary_span {
+            diag.span_label(sp, &msg);
+        }
+
+        self.note_error_origin(diag, &cause);
+        self.check_and_note_conflicting_crates(diag, terr, span);
+        self.tcx.note_and_explain_type_err(diag, terr, span);
+    }
+
+    pub fn note_issue_32330(&self,
+                            diag: &mut DiagnosticBuilder<'tcx>,
+                            terr: &TypeError<'tcx>)
+    {
+        debug!("note_issue_32330: terr={:?}", terr);
+        match *terr {
+            TypeError::RegionsInsufficientlyPolymorphic(_, &Region::ReVar(vid)) |
+            TypeError::RegionsOverlyPolymorphic(_, &Region::ReVar(vid)) => {
+                match self.region_vars.var_origin(vid) {
+                    RegionVariableOrigin::EarlyBoundRegion(_, _, Some(Issue32330 {
+                        fn_def_id,
+                        region_name
+                    })) => {
+                        diag.note(
+                            &format!("lifetime parameter `{0}` declared on fn `{1}` \
+                                      appears only in the return type, \
+                                      but here is required to be higher-ranked, \
+                                      which means that `{0}` must appear in both \
+                                      argument and return types",
+                                     region_name,
+                                     self.tcx.item_path_str(fn_def_id)));
+                        diag.note(
+                            &format!("this error is the result of a recent bug fix; \
+                                      for more information, see issue #33685 \
+                                      <https://github.com/rust-lang/rust/issues/33685>"));
+                    }
+                    _ => { }
+                }
+            }
+            _ => { }
+        }
+    }
+
+    pub fn report_and_explain_type_error(&self,
+                                         trace: TypeTrace<'tcx>,
+                                         terr: &TypeError<'tcx>)
+                                         -> DiagnosticBuilder<'tcx>
+    {
+        let span = trace.cause.span;
+        let failure_str = trace.cause.as_failure_str();
+        let mut diag = match trace.cause.code {
+            ObligationCauseCode::IfExpressionWithNoElse => {
+                struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
+            }
+            ObligationCauseCode::MainFunctionType => {
+                struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str)
+            }
+            _ => {
+                struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str)
+            }
+        };
+        self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr);
+        self.note_issue_32330(&mut diag, terr);
+        diag
+    }
+
+    /// Returns a string of the form "expected `{}`, found `{}`".
+    fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> {
+        match *values {
+            infer::Types(ref exp_found) => self.expected_found_str(exp_found),
+            infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
+            infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found),
+        }
+    }
+
+    fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
+        &self,
+        exp_found: &ty::error::ExpectedFound<T>)
+        -> Option<(String, String)>
+    {
+        let exp_found = self.resolve_type_vars_if_possible(exp_found);
+        if exp_found.references_error() {
+            return None;
+        }
+
+        Some((format!("{}", exp_found.expected), format!("{}", exp_found.found)))
+    }
+
+    fn report_generic_bound_failure(&self,
+                                    origin: SubregionOrigin<'tcx>,
+                                    bound_kind: GenericKind<'tcx>,
+                                    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
+        // where the error was detected. But that span is not readily
+        // accessible.
+
+        let labeled_user_string = match bound_kind {
+            GenericKind::Param(ref p) =>
+                format!("the parameter type `{}`", p),
+            GenericKind::Projection(ref p) =>
+                format!("the associated type `{}`", p),
+        };
+
+        if let SubregionOrigin::CompareImplMethodObligation {
+            span, item_name, impl_item_def_id, trait_item_def_id, lint_id
+        } = origin {
+            self.report_extra_impl_obligation(span,
+                                              item_name,
+                                              impl_item_def_id,
+                                              trait_item_def_id,
+                                              &format!("`{}: {}`", bound_kind, sub),
+                                              lint_id)
+                .emit();
+            return;
+        }
+
+        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,
+                                               origin.span(),
+                                               E0309,
+                                               "{} may not live long enough",
+                                               labeled_user_string);
+                err.help(&format!("consider adding an explicit lifetime bound `{}: {}`...",
+                         bound_kind,
+                         sub));
+                err
+            }
+
+            ty::ReStatic => {
+                // Does the required lifetime have a nice name we can print?
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               origin.span(),
+                                               E0310,
+                                               "{} may not live long enough",
+                                               labeled_user_string);
+                err.help(&format!("consider adding an explicit lifetime \
+                                   bound `{}: 'static`...",
+                                  bound_kind));
+                err
+            }
+
+            _ => {
+                // If not, be less specific.
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               origin.span(),
+                                               E0311,
+                                               "{} may not live long enough",
+                                               labeled_user_string);
+                err.help(&format!("consider adding an explicit lifetime bound for `{}`",
+                                  bound_kind));
+                self.tcx.note_and_explain_region(
+                    &mut err,
+                    &format!("{} must be valid for ", labeled_user_string),
+                    sub,
+                    "...");
+                err
+            }
+        };
+
+        self.note_region_origin(&mut err, &origin);
+        err.emit();
+    }
+
+    fn report_sub_sup_conflict(&self,
+                               var_origin: RegionVariableOrigin,
+                               sub_origin: SubregionOrigin<'tcx>,
+                               sub_region: &'tcx Region,
+                               sup_origin: SubregionOrigin<'tcx>,
+                               sup_region: &'tcx Region) {
+        let mut err = self.report_inference_failure(var_origin);
+
+        self.tcx.note_and_explain_region(&mut err,
+            "first, the lifetime cannot outlive ",
+            sup_region,
+            "...");
+
+        self.note_region_origin(&mut err, &sup_origin);
+
+        self.tcx.note_and_explain_region(&mut err,
+            "but, the lifetime must be valid for ",
+            sub_region,
+            "...");
+
+        self.note_region_origin(&mut err, &sub_origin);
+        err.emit();
+    }
+}
+
+impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
+    fn report_inference_failure(&self,
+                                var_origin: RegionVariableOrigin)
+                                -> DiagnosticBuilder<'tcx> {
+        let br_string = |br: ty::BoundRegion| {
+            let mut s = br.to_string();
+            if !s.is_empty() {
+                s.push_str(" ");
+            }
+            s
+        };
+        let var_description = match var_origin {
+            infer::MiscVariable(_) => "".to_string(),
+            infer::PatternRegion(_) => " for pattern".to_string(),
+            infer::AddrOfRegion(_) => " for borrow expression".to_string(),
+            infer::Autoref(_) => " for autoref".to_string(),
+            infer::Coercion(_) => " for automatic coercion".to_string(),
+            infer::LateBoundRegion(_, br, infer::FnCall) => {
+                format!(" for lifetime parameter {}in function call",
+                        br_string(br))
+            }
+            infer::LateBoundRegion(_, br, infer::HigherRankedType) => {
+                format!(" for lifetime parameter {}in generic type", br_string(br))
+            }
+            infer::LateBoundRegion(_, br, infer::AssocTypeProjection(type_name)) => {
+                format!(" for lifetime parameter {}in trait containing associated type `{}`",
+                        br_string(br), type_name)
+            }
+            infer::EarlyBoundRegion(_, name, _) => {
+                format!(" for lifetime parameter `{}`",
+                        name)
+            }
+            infer::BoundRegionInCoherence(name) => {
+                format!(" for lifetime parameter `{}` in coherence check",
+                        name)
+            }
+            infer::UpvarRegion(ref upvar_id, _) => {
+                format!(" for capture of `{}` by closure",
+                        self.tcx.local_var_name_str(upvar_id.var_id).to_string())
+            }
+        };
+
+        struct_span_err!(self.tcx.sess, var_origin.span(), E0495,
+                  "cannot infer an appropriate lifetime{} \
+                   due to conflicting requirements",
+                  var_description)
+    }
+}
+
+impl<'tcx> ObligationCause<'tcx> {
+    fn as_failure_str(&self) -> &'static str {
+        use traits::ObligationCauseCode::*;
+        match self.code {
+            CompareImplMethodObligation { .. } => "method not compatible with trait",
+            MatchExpressionArm { source, .. } => match source {
+                hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
+                _ => "match arms have incompatible types",
+            },
+            IfExpression => "if and else have incompatible types",
+            IfExpressionWithNoElse => "if may be missing an else clause",
+            EquatePredicate => "equality predicate not satisfied",
+            MainFunctionType => "main function has wrong type",
+            StartFunctionType => "start function has wrong type",
+            IntrinsicType => "intrinsic has wrong type",
+            MethodReceiver => "mismatched method receiver",
+            _ => "mismatched types",
+        }
+    }
+
+    fn as_requirement_str(&self) -> &'static str {
+        use traits::ObligationCauseCode::*;
+        match self.code {
+            CompareImplMethodObligation { .. } => "method type is compatible with trait",
+            ExprAssignable => "expression is assignable",
+            MatchExpressionArm { source, .. } => match source {
+                hir::MatchSource::IfLetDesugar{..} => "`if let` arms have compatible types",
+                _ => "match arms have compatible types",
+            },
+            IfExpression => "if and else have compatible types",
+            IfExpressionWithNoElse => "if missing an else returns ()",
+            EquatePredicate => "equality where clause is satisfied",
+            MainFunctionType => "`main` function has the correct type",
+            StartFunctionType => "`start` function has the correct type",
+            IntrinsicType => "intrinsic has the correct type",
+            MethodReceiver => "method receiver has the correct type",
+            _ => "types are compatible",
+        }
+    }
+}
diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs
new file mode 100644 (file)
index 0000000..8f8b260
--- /dev/null
@@ -0,0 +1,432 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use infer::{self, InferCtxt, SubregionOrigin};
+use ty::Region;
+use ty::error::TypeError;
+use errors::DiagnosticBuilder;
+
+impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
+    pub(super) fn note_region_origin(&self,
+                                     err: &mut DiagnosticBuilder,
+                                     origin: &SubregionOrigin<'tcx>) {
+        match *origin {
+            infer::Subtype(ref trace) => {
+                if let Some((expected, found)) = self.values_str(&trace.values) {
+                    // FIXME: do we want a "the" here?
+                    err.span_note(trace.cause.span,
+                                  &format!("...so that {} (expected {}, found {})",
+                                           trace.cause.as_requirement_str(),
+                                           expected,
+                                           found));
+                } else {
+                    // FIXME: this really should be handled at some earlier stage. Our
+                    // handling of region checking when type errors are present is
+                    // *terrible*.
+
+                    err.span_note(trace.cause.span,
+                                  &format!("...so that {}", trace.cause.as_requirement_str()));
+                }
+            }
+            infer::Reborrow(span) => {
+                err.span_note(span,
+                              "...so that reference does not outlive borrowed content");
+            }
+            infer::ReborrowUpvar(span, ref upvar_id) => {
+                err.span_note(span,
+                              &format!("...so that closure can access `{}`",
+                                       self.tcx
+                                           .local_var_name_str(upvar_id.var_id)
+                                           .to_string()));
+            }
+            infer::InfStackClosure(span) => {
+                err.span_note(span, "...so that closure does not outlive its stack frame");
+            }
+            infer::InvokeClosure(span) => {
+                err.span_note(span,
+                              "...so that closure is not invoked outside its lifetime");
+            }
+            infer::DerefPointer(span) => {
+                err.span_note(span,
+                              "...so that pointer is not dereferenced outside its lifetime");
+            }
+            infer::FreeVariable(span, id) => {
+                err.span_note(span,
+                              &format!("...so that captured variable `{}` does not outlive the \
+                                        enclosing closure",
+                                       self.tcx.local_var_name_str(id)));
+            }
+            infer::IndexSlice(span) => {
+                err.span_note(span, "...so that slice is not indexed outside the lifetime");
+            }
+            infer::RelateObjectBound(span) => {
+                err.span_note(span, "...so that it can be closed over into an object");
+            }
+            infer::CallRcvr(span) => {
+                err.span_note(span,
+                              "...so that method receiver is valid for the method call");
+            }
+            infer::CallArg(span) => {
+                err.span_note(span, "...so that argument is valid for the call");
+            }
+            infer::CallReturn(span) => {
+                err.span_note(span, "...so that return value is valid for the call");
+            }
+            infer::Operand(span) => {
+                err.span_note(span, "...so that operand is valid for operation");
+            }
+            infer::AddrOf(span) => {
+                err.span_note(span, "...so that reference is valid at the time of borrow");
+            }
+            infer::AutoBorrow(span) => {
+                err.span_note(span,
+                              "...so that auto-reference is valid at the time of borrow");
+            }
+            infer::ExprTypeIsNotInScope(t, span) => {
+                err.span_note(span,
+                              &format!("...so type `{}` of expression is valid during the \
+                                        expression",
+                                       self.ty_to_string(t)));
+            }
+            infer::BindingTypeIsNotValidAtDecl(span) => {
+                err.span_note(span,
+                              "...so that variable is valid at time of its declaration");
+            }
+            infer::ParameterInScope(_, span) => {
+                err.span_note(span,
+                              "...so that a type/lifetime parameter is in scope here");
+            }
+            infer::DataBorrowed(ty, span) => {
+                err.span_note(span,
+                              &format!("...so that the type `{}` is not borrowed for too long",
+                                       self.ty_to_string(ty)));
+            }
+            infer::ReferenceOutlivesReferent(ty, span) => {
+                err.span_note(span,
+                              &format!("...so that the reference type `{}` does not outlive the \
+                                        data it points at",
+                                       self.ty_to_string(ty)));
+            }
+            infer::RelateParamBound(span, t) => {
+                err.span_note(span,
+                              &format!("...so that the type `{}` will meet its required \
+                                        lifetime bounds",
+                                       self.ty_to_string(t)));
+            }
+            infer::RelateDefaultParamBound(span, t) => {
+                err.span_note(span,
+                              &format!("...so that type parameter instantiated with `{}`, will \
+                                        meet its declared lifetime bounds",
+                                       self.ty_to_string(t)));
+            }
+            infer::RelateRegionParamBound(span) => {
+                err.span_note(span,
+                              "...so that the declared lifetime parameter bounds are satisfied");
+            }
+            infer::SafeDestructor(span) => {
+                err.span_note(span,
+                              "...so that references are valid when the destructor runs");
+            }
+            infer::CompareImplMethodObligation { span, .. } => {
+                err.span_note(span,
+                              "...so that the definition in impl matches the definition from the \
+                               trait");
+            }
+        }
+    }
+
+    pub(super) fn report_concrete_failure(&self,
+                                          origin: SubregionOrigin<'tcx>,
+                                          sub: &'tcx Region,
+                                          sup: &'tcx Region)
+                                          -> DiagnosticBuilder<'tcx> {
+        match origin {
+            infer::Subtype(trace) => {
+                let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
+                self.report_and_explain_type_error(trace, &terr)
+            }
+            infer::Reborrow(span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0312,
+                                               "lifetime of reference outlives lifetime of \
+                                                borrowed content...");
+                self.tcx.note_and_explain_region(&mut err,
+                                                 "...the reference is valid for ",
+                                                 sub,
+                                                 "...");
+                self.tcx.note_and_explain_region(&mut err,
+                                                 "...but the borrowed content is only valid for ",
+                                                 sup,
+                                                 "");
+                err
+            }
+            infer::ReborrowUpvar(span, ref upvar_id) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0313,
+                                               "lifetime of borrowed pointer outlives lifetime \
+                                                of captured variable `{}`...",
+                                               self.tcx.local_var_name_str(upvar_id.var_id));
+                self.tcx.note_and_explain_region(&mut err,
+                                                 "...the borrowed pointer is valid for ",
+                                                 sub,
+                                                 "...");
+                self.tcx
+                    .note_and_explain_region(&mut err,
+                                             &format!("...but `{}` is only valid for ",
+                                                      self.tcx
+                                                          .local_var_name_str(upvar_id.var_id)),
+                                             sup,
+                                             "");
+                err
+            }
+            infer::InfStackClosure(span) => {
+                let mut err =
+                    struct_span_err!(self.tcx.sess, span, E0314, "closure outlives stack frame");
+                self.tcx.note_and_explain_region(&mut err,
+                                                 "...the closure must be valid for ",
+                                                 sub,
+                                                 "...");
+                self.tcx.note_and_explain_region(&mut err,
+                                                 "...but the closure's stack frame is only valid \
+                                                  for ",
+                                                 sup,
+                                                 "");
+                err
+            }
+            infer::InvokeClosure(span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0315,
+                                               "cannot invoke closure outside of its lifetime");
+                self.tcx
+                    .note_and_explain_region(&mut err, "the closure is only valid for ", sup, "");
+                err
+            }
+            infer::DerefPointer(span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0473,
+                                               "dereference of reference outside its lifetime");
+                self.tcx
+                    .note_and_explain_region(&mut err, "the reference is only valid for ", sup, "");
+                err
+            }
+            infer::FreeVariable(span, id) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0474,
+                                               "captured variable `{}` does not outlive the \
+                                                enclosing closure",
+                                               self.tcx.local_var_name_str(id));
+                self.tcx
+                    .note_and_explain_region(&mut err, "captured variable is valid for ", sup, "");
+                self.tcx.note_and_explain_region(&mut err, "closure is valid for ", sub, "");
+                err
+            }
+            infer::IndexSlice(span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0475,
+                                               "index of slice outside its lifetime");
+                self.tcx.note_and_explain_region(&mut err, "the slice is only valid for ", sup, "");
+                err
+            }
+            infer::RelateObjectBound(span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0476,
+                                               "lifetime of the source pointer does not outlive \
+                                                lifetime bound of the object type");
+                self.tcx.note_and_explain_region(&mut err, "object type is valid for ", sub, "");
+                self.tcx.note_and_explain_region(&mut err,
+                                                 "source pointer is only valid for ",
+                                                 sup,
+                                                 "");
+                err
+            }
+            infer::RelateParamBound(span, ty) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0477,
+                                               "the type `{}` does not fulfill the required \
+                                                lifetime",
+                                               self.ty_to_string(ty));
+                self.tcx.note_and_explain_region(&mut err, "type must outlive ", sub, "");
+                err
+            }
+            infer::RelateRegionParamBound(span) => {
+                let mut err =
+                    struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
+                self.tcx.note_and_explain_region(&mut err,
+                                                 "lifetime parameter instantiated with ",
+                                                 sup,
+                                                 "");
+                self.tcx.note_and_explain_region(&mut err,
+                                                 "but lifetime parameter must outlive ",
+                                                 sub,
+                                                 "");
+                err
+            }
+            infer::RelateDefaultParamBound(span, ty) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0479,
+                                               "the type `{}` (provided as the value of a type \
+                                                parameter) is not valid at this point",
+                                               self.ty_to_string(ty));
+                self.tcx.note_and_explain_region(&mut err, "type must outlive ", sub, "");
+                err
+            }
+            infer::CallRcvr(span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0480,
+                                               "lifetime of method receiver does not outlive the \
+                                                method call");
+                self.tcx
+                    .note_and_explain_region(&mut err, "the receiver is only valid for ", sup, "");
+                err
+            }
+            infer::CallArg(span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0481,
+                                               "lifetime of function argument does not outlive \
+                                                the function call");
+                self.tcx.note_and_explain_region(&mut err,
+                                                 "the function argument is only valid for ",
+                                                 sup,
+                                                 "");
+                err
+            }
+            infer::CallReturn(span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0482,
+                                               "lifetime of return value does not outlive the \
+                                                function call");
+                self.tcx.note_and_explain_region(&mut err,
+                                                 "the return value is only valid for ",
+                                                 sup,
+                                                 "");
+                err
+            }
+            infer::Operand(span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0483,
+                                               "lifetime of operand does not outlive the \
+                                                operation");
+                self.tcx
+                    .note_and_explain_region(&mut err, "the operand is only valid for ", sup, "");
+                err
+            }
+            infer::AddrOf(span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0484,
+                                               "reference is not valid at the time of borrow");
+                self.tcx
+                    .note_and_explain_region(&mut err, "the borrow is only valid for ", sup, "");
+                err
+            }
+            infer::AutoBorrow(span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0485,
+                                               "automatically reference is not valid at the time \
+                                                of borrow");
+                self.tcx.note_and_explain_region(&mut err,
+                                                 "the automatic borrow is only valid for ",
+                                                 sup,
+                                                 "");
+                err
+            }
+            infer::ExprTypeIsNotInScope(t, span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0486,
+                                               "type of expression contains references that are \
+                                                not valid during the expression: `{}`",
+                                               self.ty_to_string(t));
+                self.tcx.note_and_explain_region(&mut err, "type is only valid for ", sup, "");
+                err
+            }
+            infer::SafeDestructor(span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0487,
+                                               "unsafe use of destructor: destructor might be \
+                                                called while references are dead");
+                // FIXME (22171): terms "super/subregion" are suboptimal
+                self.tcx.note_and_explain_region(&mut err, "superregion: ", sup, "");
+                self.tcx.note_and_explain_region(&mut err, "subregion: ", sub, "");
+                err
+            }
+            infer::BindingTypeIsNotValidAtDecl(span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0488,
+                                               "lifetime of variable does not enclose its \
+                                                declaration");
+                self.tcx
+                    .note_and_explain_region(&mut err, "the variable is only valid for ", sup, "");
+                err
+            }
+            infer::ParameterInScope(_, span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0489,
+                                               "type/lifetime parameter not in scope here");
+                self.tcx
+                    .note_and_explain_region(&mut err, "the parameter is only valid for ", sub, "");
+                err
+            }
+            infer::DataBorrowed(ty, span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0490,
+                                               "a value of type `{}` is borrowed for too long",
+                                               self.ty_to_string(ty));
+                self.tcx.note_and_explain_region(&mut err, "the type is valid for ", sub, "");
+                self.tcx.note_and_explain_region(&mut err, "but the borrow lasts for ", sup, "");
+                err
+            }
+            infer::ReferenceOutlivesReferent(ty, span) => {
+                let mut err = struct_span_err!(self.tcx.sess,
+                                               span,
+                                               E0491,
+                                               "in type `{}`, reference has a longer lifetime \
+                                                than the data it references",
+                                               self.ty_to_string(ty));
+                self.tcx.note_and_explain_region(&mut err, "the pointer is valid for ", sub, "");
+                self.tcx.note_and_explain_region(&mut err,
+                                                 "but the referenced data is only valid for ",
+                                                 sup,
+                                                 "");
+                err
+            }
+            infer::CompareImplMethodObligation { span,
+                                                 item_name,
+                                                 impl_item_def_id,
+                                                 trait_item_def_id,
+                                                 lint_id } => {
+                self.report_extra_impl_obligation(span,
+                                                  item_name,
+                                                  impl_item_def_id,
+                                                  trait_item_def_id,
+                                                  &format!("`{}: {}`", sup, sub),
+                                                  lint_id)
+            }
+        }
+    }
+}
index c3a6a62764d0b56ce327ada6900b82cb57835ee8..b07ef4dfd448e45f1a3651110b4dd6b79838e836 100644 (file)
@@ -210,7 +210,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 /// region that each late-bound region was replaced with.
 pub type SkolemizationMap<'tcx> = FxHashMap<ty::BoundRegion, &'tcx ty::Region>;
 
-/// See `error_reporting.rs` for more details
+/// See `error_reporting` module for more details
 #[derive(Clone, Debug)]
 pub enum ValuePairs<'tcx> {
     Types(ExpectedFound<Ty<'tcx>>),
@@ -221,7 +221,7 @@ pub enum ValuePairs<'tcx> {
 /// The trace designates the path through inference that we took to
 /// encounter an error or subtyping constraint.
 ///
-/// See `error_reporting.rs` for more details.
+/// See `error_reporting` module for more details.
 #[derive(Clone)]
 pub struct TypeTrace<'tcx> {
     cause: ObligationCause<'tcx>,
@@ -230,7 +230,7 @@ pub struct TypeTrace<'tcx> {
 
 /// The origin of a `r1 <= r2` constraint.
 ///
-/// See `error_reporting.rs` for more details
+/// See `error_reporting` module for more details
 #[derive(Clone, Debug)]
 pub enum SubregionOrigin<'tcx> {
     // Arose from a subtyping relation
@@ -348,7 +348,7 @@ pub enum LateBoundRegionConversionTime {
 
 /// Reasons to create a region inference variable
 ///
-/// See `error_reporting.rs` for more details
+/// See `error_reporting` module for more details
 #[derive(Clone, Debug)]
 pub enum RegionVariableOrigin {
     // Region variables created for ill-categorized reasons,
@@ -505,7 +505,7 @@ pub fn borrowck_fake_infer_ctxt(self, body: hir::BodyId)
             evaluation_cache: traits::EvaluationCache::new(),
             projection_cache: RefCell::new(traits::ProjectionCache::new()),
             reported_trait_errors: RefCell::new(FxHashSet()),
-            projection_mode: Reveal::NotSpecializable,
+            projection_mode: Reveal::UserFacing,
             tainted_by_errors_flag: Cell::new(false),
             err_count_on_creation: self.sess.err_count(),
             obligations_in_snapshot: Cell::new(false),
@@ -600,7 +600,7 @@ fn trans_normalize<'a, 'tcx>(&self,
     Ty<'gcx>,
     &'gcx Substs<'gcx>,
     ty::FnSig<'gcx>,
-    &'gcx ty::BareFnTy<'gcx>,
+    ty::PolyFnSig<'gcx>,
     ty::ClosureSubsts<'gcx>,
     ty::PolyTraitRef<'gcx>,
     ty::ExistentialTraitRef<'gcx>
@@ -1197,16 +1197,19 @@ pub fn region_var_for_def(&self,
     /// as the substitutions for the default, `(T, U)`.
     pub fn type_var_for_def(&self,
                             span: Span,
-                            def: &ty::TypeParameterDef<'tcx>,
+                            def: &ty::TypeParameterDef,
                             substs: &[Kind<'tcx>])
                             -> Ty<'tcx> {
-        let default = def.default.map(|default| {
-            type_variable::Default {
+        let default = if def.has_default {
+            let default = self.tcx.item_type(def.def_id);
+            Some(type_variable::Default {
                 ty: default.subst_spanned(self.tcx, substs, Some(span)),
                 origin_span: span,
-                def_id: def.default_def_id
-            }
-        });
+                def_id: def.def_id
+            })
+        } else {
+            None
+        };
 
 
         let ty_var_id = self.type_variables
@@ -1292,7 +1295,7 @@ pub fn resolve_regions_and_report_errors(&self,
             // this infcx was in use.  This is totally hokey but
             // otherwise we have a hard time separating legit region
             // errors from silly ones.
-            self.report_region_errors(&errors); // see error_reporting.rs
+            self.report_region_errors(&errors); // see error_reporting module
         }
     }
 
@@ -1646,20 +1649,16 @@ pub fn closure_kind(&self,
         Some(self.tcx.closure_kind(def_id))
     }
 
-    pub fn closure_type(&self,
-                        def_id: DefId,
-                        substs: ty::ClosureSubsts<'tcx>)
-                        -> ty::ClosureTy<'tcx>
-    {
+    pub fn closure_type(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
         if let InferTables::InProgress(tables) = self.tables {
             if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
-                if let Some(ty) = tables.borrow().closure_tys.get(&id) {
-                    return ty.subst(self.tcx, substs.substs);
+                if let Some(&ty) = tables.borrow().closure_tys.get(&id) {
+                    return ty;
                 }
             }
         }
 
-        self.tcx.closure_type(def_id, substs)
+        self.tcx.closure_type(def_id)
     }
 }
 
index d144f7575a2e2dfa4e7d36d0a224c9f417084cf9..c4fccdcb9eb6220ce01c6727797aa487ca098e88 100644 (file)
@@ -39,6 +39,7 @@
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
 #![feature(slice_patterns)]
+#![feature(specialization)]
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
 
@@ -75,7 +76,6 @@
 pub mod lint;
 
 pub mod middle {
-    pub mod astconv_util;
     pub mod expr_use_visitor;
     pub mod const_val;
     pub mod cstore;
index 70f03e02f46d9b9c6a8dd7c22c7afaa2cd4f31ae..e681d55cf94b893db2fd37f65eb7e5a422bc4dda 100644 (file)
     "uses of #[derive] with raw pointers are rarely correct"
 }
 
-declare_lint! {
-    pub TRANSMUTE_FROM_FN_ITEM_TYPES,
-    Deny,
-    "transmute from function item type to pointer-sized type erroneously allowed"
-}
-
 declare_lint! {
     pub HR_LIFETIME_IN_ASSOC_TYPE,
     Deny,
     "detects use of struct constructors that would be invisible with new visibility rules"
 }
 
+declare_lint! {
+    pub MISSING_FRAGMENT_SPECIFIER,
+    Warn,
+    "detects missing fragment specifiers in unused `macro_rules!` patterns"
+}
+
 declare_lint! {
     pub DEPRECATED,
     Warn,
@@ -273,7 +273,6 @@ fn get_lints(&self) -> LintArray {
             ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
             CONST_ERR,
             RAW_POINTER_DERIVE,
-            TRANSMUTE_FROM_FN_ITEM_TYPES,
             OVERLAPPING_INHERENT_IMPLS,
             RENAMED_AND_REMOVED_LINTS,
             SUPER_OR_SELF_IN_GLOBAL_PATH,
@@ -286,6 +285,7 @@ fn get_lints(&self) -> LintArray {
             LEGACY_DIRECTORY_OWNERSHIP,
             LEGACY_IMPORTS,
             LEGACY_CONSTRUCTOR_VISIBILITY,
+            MISSING_FRAGMENT_SPECIFIER,
             DEPRECATED
         )
     }
diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs
deleted file mode 100644 (file)
index 3418034..0000000
+++ /dev/null
@@ -1,83 +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.
-
-/*!
- * This module contains a simple utility routine
- * used by both `typeck` and `const_eval`.
- * Almost certainly this could (and should) be refactored out of existence.
- */
-
-use hir;
-use hir::def::Def;
-use ty::{Ty, TyCtxt};
-
-use syntax_pos::Span;
-
-impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-    pub fn prohibit_type_params(self, segments: &[hir::PathSegment]) {
-        for segment in segments {
-            for typ in segment.parameters.types() {
-                struct_span_err!(self.sess, typ.span, E0109,
-                                 "type parameters are not allowed on this type")
-                    .span_label(typ.span, &format!("type parameter not allowed"))
-                    .emit();
-                break;
-            }
-            for lifetime in segment.parameters.lifetimes() {
-                struct_span_err!(self.sess, lifetime.span, E0110,
-                                 "lifetime parameters are not allowed on this type")
-                    .span_label(lifetime.span,
-                                &format!("lifetime parameter not allowed on this type"))
-                    .emit();
-                break;
-            }
-            for binding in segment.parameters.bindings() {
-                self.prohibit_projection(binding.span);
-                break;
-            }
-        }
-    }
-
-    pub fn prohibit_projection(self, span: Span)
-    {
-        let mut err = struct_span_err!(self.sess, span, E0229,
-                                       "associated type bindings are not allowed here");
-        err.span_label(span, &format!("associate type not allowed here")).emit();
-    }
-
-    pub fn prim_ty_to_ty(self,
-                         segments: &[hir::PathSegment],
-                         nty: hir::PrimTy)
-                         -> Ty<'tcx> {
-        self.prohibit_type_params(segments);
-        match nty {
-            hir::TyBool => self.types.bool,
-            hir::TyChar => self.types.char,
-            hir::TyInt(it) => self.mk_mach_int(it),
-            hir::TyUint(uit) => self.mk_mach_uint(uit),
-            hir::TyFloat(ft) => self.mk_mach_float(ft),
-            hir::TyStr => self.mk_str()
-        }
-    }
-
-    /// If a type in the AST is a primitive type, return the ty::Ty corresponding
-    /// to it.
-    pub fn ast_ty_to_prim_ty(self, ast_ty: &hir::Ty) -> Option<Ty<'tcx>> {
-        if let hir::TyPath(hir::QPath::Resolved(None, ref path)) = ast_ty.node {
-            if let Def::PrimTy(nty) = path.def {
-                Some(self.prim_ty_to_ty(&path.segments, nty))
-            } else {
-                None
-            }
-        } else {
-            None
-        }
-    }
-}
index 11919db479c1a790778811e90c82aa804ca90821..d81f89827d93814de111839dc33661c97fc282cf 100644 (file)
 use syntax::ast;
 use std::rc::Rc;
 use hir::def_id::DefId;
+use ty::subst::Substs;
 use rustc_const_math::*;
+
 use self::ConstVal::*;
 pub use rustc_const_math::ConstInt;
 
 use std::collections::BTreeMap;
 
 #[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
-pub enum ConstVal {
+pub enum ConstVal<'tcx> {
     Float(ConstFloat),
     Integral(ConstInt),
     Str(InternedString),
     ByteStr(Rc<Vec<u8>>),
     Bool(bool),
-    Function(DefId),
-    Struct(BTreeMap<ast::Name, ConstVal>),
-    Tuple(Vec<ConstVal>),
-    Array(Vec<ConstVal>),
-    Repeat(Box<ConstVal>, u64),
+    Function(DefId, &'tcx Substs<'tcx>),
+    Struct(BTreeMap<ast::Name, ConstVal<'tcx>>),
+    Tuple(Vec<ConstVal<'tcx>>),
+    Array(Vec<ConstVal<'tcx>>),
+    Repeat(Box<ConstVal<'tcx>>, u64),
     Char(char),
 }
 
-impl ConstVal {
+impl<'tcx> ConstVal<'tcx> {
     pub fn description(&self) -> &'static str {
         match *self {
             Float(f) => f.description(),
@@ -43,7 +45,7 @@ pub fn description(&self) -> &'static str {
             Bool(_) => "boolean",
             Struct(_) => "struct",
             Tuple(_) => "tuple",
-            Function(_) => "function definition",
+            Function(..) => "function definition",
             Array(..) => "array",
             Repeat(..) => "repeat",
             Char(..) => "char",
@@ -53,8 +55,7 @@ pub fn description(&self) -> &'static str {
     pub fn to_const_int(&self) -> Option<ConstInt> {
         match *self {
             ConstVal::Integral(i) => Some(i),
-            ConstVal::Bool(true) => Some(ConstInt::Infer(1)),
-            ConstVal::Bool(false) => Some(ConstInt::Infer(0)),
+            ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)),
             ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)),
             _ => None
         }
index 2d80fc32c469dc111f37eb8487811ea9940c24ba..4a7027b8997a5854befdef64121af1d4b96a373e 100644 (file)
 use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData};
 use hir::svh::Svh;
 use middle::lang_items;
-use middle::resolve_lifetime::ObjectLifetimeDefault;
-use ty::{self, Ty, TyCtxt};
-use mir::Mir;
+use ty::{self, TyCtxt};
 use session::Session;
 use session::search_paths::PathKind;
 use util::nodemap::{NodeSet, DefIdMap};
 
+use std::any::Any;
 use std::collections::BTreeMap;
 use std::path::PathBuf;
 use std::rc::Rc;
@@ -164,32 +163,18 @@ pub struct ExternCrate {
 
 /// A store of Rust crates, through with their metadata
 /// can be accessed.
-pub trait CrateStore<'tcx> {
+pub trait CrateStore {
+    fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any>;
+
     // item info
     fn describe_def(&self, def: DefId) -> Option<Def>;
     fn def_span(&self, sess: &Session, def: DefId) -> Span;
     fn stability(&self, def: DefId) -> Option<attr::Stability>;
     fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>;
     fn visibility(&self, def: DefId) -> ty::Visibility;
-    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) -> Vec<ty::Variance>;
-    fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                     -> Ty<'tcx>;
     fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>>;
-    fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                           -> ty::GenericPredicates<'tcx>;
-    fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                                 -> ty::GenericPredicates<'tcx>;
-    fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                         -> ty::Generics<'tcx>;
-    fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize);
-    fn item_generics_object_lifetime_defaults(&self, def: DefId)
-                                              -> Vec<ObjectLifetimeDefault>;
+    fn item_generics_cloned(&self, def: DefId) -> ty::Generics;
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
-    fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef;
-    fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef;
     fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>;
     fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId>;
 
@@ -197,21 +182,15 @@ fn item_generics_object_lifetime_defaults(&self, def: DefId)
     fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>;
 
     // impl info
-    fn associated_item_def_ids(&self, def_id: DefId) -> Vec<DefId>;
-    fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                          -> Option<ty::TraitRef<'tcx>>;
     fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity;
-    fn custom_coerce_unsized_kind(&self, def: DefId)
-                                  -> Option<ty::adjustment::CustomCoerceUnsized>;
     fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
 
     // trait/impl-item info
     fn trait_of_item(&self, def_id: DefId) -> Option<DefId>;
-    fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem>;
+    fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem;
 
     // flags
     fn is_const_fn(&self, did: DefId) -> bool;
-    fn is_defaulted_trait(&self, did: DefId) -> bool;
     fn is_default_impl(&self, impl_did: DefId) -> bool;
     fn is_foreign_item(&self, did: DefId) -> bool;
     fn is_dllimport_foreign_item(&self, def: DefId) -> bool;
@@ -257,12 +236,11 @@ fn retrace_path(&self,
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
 
     // misc. metadata
-    fn maybe_get_item_body<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                               -> Option<&'tcx hir::Body>;
+    fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                                     -> Option<&'tcx hir::Body>;
     fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body>;
     fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool;
 
-    fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx>;
     fn is_item_mir_available(&self, def: DefId) -> bool;
 
     // This is basically a 1-based range of ints, which is a little
@@ -277,10 +255,10 @@ fn maybe_get_item_body<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
     fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>;
     fn used_crate_source(&self, cnum: CrateNum) -> CrateSource;
     fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum>;
-    fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                           reexports: &def::ExportMap,
-                           link_meta: &LinkMeta,
-                           reachable: &NodeSet) -> Vec<u8>;
+    fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                 reexports: &def::ExportMap,
+                                 link_meta: &LinkMeta,
+                                 reachable: &NodeSet) -> Vec<u8>;
     fn metadata_encoding_version(&self) -> &[u8];
 }
 
@@ -314,39 +292,23 @@ pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
 /// A dummy crate store that does not support any non-local crates,
 /// for test purposes.
 pub struct DummyCrateStore;
+
 #[allow(unused_variables)]
-impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
+impl CrateStore for DummyCrateStore {
+    fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any>
+        { bug!("crate_data_as_rc_any") }
     // item info
     fn describe_def(&self, def: DefId) -> Option<Def> { bug!("describe_def") }
     fn def_span(&self, sess: &Session, def: DefId) -> Span { bug!("def_span") }
     fn stability(&self, def: DefId) -> Option<attr::Stability> { bug!("stability") }
     fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> { bug!("deprecation") }
     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) -> Vec<ty::Variance> { bug!("item_variances") }
-    fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                     -> Ty<'tcx> { bug!("item_type") }
     fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>> {
         bug!("visible_parent_map")
     }
-    fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                           -> ty::GenericPredicates<'tcx> { bug!("item_predicates") }
-    fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                                 -> ty::GenericPredicates<'tcx> { bug!("item_super_predicates") }
-    fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                         -> ty::Generics<'tcx> { bug!("item_generics") }
-    fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize)
-        { bug!("item_generics_own_param_counts") }
-    fn item_generics_object_lifetime_defaults(&self, def: DefId)
-                                              -> Vec<ObjectLifetimeDefault>
-        { bug!("item_generics_object_lifetime_defaults") }
+    fn item_generics_cloned(&self, def: DefId) -> ty::Generics
+        { bug!("item_generics_cloned") }
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute> { bug!("item_attrs") }
-    fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef
-        { bug!("trait_def") }
-    fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef
-        { bug!("adt_def") }
     fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name> { bug!("fn_arg_names") }
     fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId> { vec![] }
 
@@ -354,23 +316,16 @@ fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId> { vec![
     fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId> { vec![] }
 
     // impl info
-    fn associated_item_def_ids(&self, def_id: DefId) -> Vec<DefId>
-        { bug!("associated_items") }
-    fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                          -> Option<ty::TraitRef<'tcx>> { bug!("impl_trait_ref") }
     fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") }
-    fn custom_coerce_unsized_kind(&self, def: DefId)
-                                  -> Option<ty::adjustment::CustomCoerceUnsized>
-        { bug!("custom_coerce_unsized_kind") }
     fn impl_parent(&self, def: DefId) -> Option<DefId> { bug!("impl_parent") }
 
     // trait/impl-item info
     fn trait_of_item(&self, def_id: DefId) -> Option<DefId> { bug!("trait_of_item") }
-    fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem> { bug!("associated_item") }
+    fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem
+        { bug!("associated_item_cloned") }
 
     // flags
     fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") }
-    fn is_defaulted_trait(&self, did: DefId) -> bool { bug!("is_defaulted_trait") }
     fn is_default_impl(&self, impl_did: DefId) -> bool { bug!("is_default_impl") }
     fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") }
     fn is_dllimport_foreign_item(&self, id: DefId) -> bool { false }
@@ -429,8 +384,8 @@ fn item_children(&self, did: DefId) -> Vec<def::Export> { bug!("item_children")
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
 
     // misc. metadata
-    fn maybe_get_item_body<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                               -> Option<&'tcx hir::Body> {
+    fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                                     -> Option<&'tcx hir::Body> {
         bug!("maybe_get_item_body")
     }
     fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
@@ -440,8 +395,6 @@ fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool {
         bug!("const_is_rvalue_promotable_to_static")
     }
 
-    fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                        -> Mir<'tcx> { bug!("get_item_mir") }
     fn is_item_mir_available(&self, def: DefId) -> bool {
         bug!("is_item_mir_available")
     }
@@ -459,7 +412,7 @@ fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>
         { vec![] }
     fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { bug!("used_crate_source") }
     fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> { None }
-    fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            reexports: &def::ExportMap,
                            link_meta: &LinkMeta,
                            reachable: &NodeSet) -> Vec<u8> { vec![] }
index ae349667f9dc67826d36c80692865dc46a187836..cc6d6e88dee4ee068424be59d0d10ee853903fe1 100644 (file)
@@ -159,10 +159,9 @@ fn visit_node(&mut self, node: &hir_map::Node<'tcx>) {
             hir_map::NodeItem(item) => {
                 match item.node {
                     hir::ItemStruct(..) | hir::ItemUnion(..) => {
-                        self.struct_has_extern_repr = item.attrs.iter().any(|attr| {
-                            attr::find_repr_attrs(self.tcx.sess.diagnostic(), attr)
-                                .contains(&attr::ReprExtern)
-                        });
+                        let def_id = self.tcx.hir.local_def_id(item.id);
+                        let def = self.tcx.lookup_adt_def(def_id);
+                        self.struct_has_extern_repr = def.repr.c;
 
                         intravisit::walk_item(self, &item);
                     }
@@ -478,7 +477,7 @@ fn symbol_is_live(&mut self,
         // method of a private type is used, but the type itself is never
         // called directly.
         if let Some(impl_list) =
-                self.tcx.inherent_impls.borrow().get(&self.tcx.hir.local_def_id(id)) {
+                self.tcx.maps.inherent_impls.borrow().get(&self.tcx.hir.local_def_id(id)) {
             for &impl_did in impl_list.iter() {
                 for &item_did in &self.tcx.associated_item_def_ids(impl_did)[..] {
                     if let Some(item_node_id) = self.tcx.hir.as_local_node_id(item_did) {
index ab33c3843aae5d6c0a9a1db6fe8b3726dfc19888..5af8e7e52d888407f57518c0bfd4addaedda1f6e 100644 (file)
@@ -44,8 +44,8 @@ enum RootUnsafeContext {
 
 fn type_is_unsafe_function(ty: Ty) -> bool {
     match ty.sty {
-        ty::TyFnDef(.., ref f) |
-        ty::TyFnPtr(ref f) => f.unsafety == hir::Unsafety::Unsafe,
+        ty::TyFnDef(.., f) |
+        ty::TyFnPtr(f) => f.unsafety() == hir::Unsafety::Unsafe,
         _ => false,
     }
 }
index 2ca0069560cb7c1686b431861606d188cf5269c6..a44679b0b3e0e5cab0389ca356159c4960e46c29 100644 (file)
@@ -715,6 +715,7 @@ fn walk_adjustment(&mut self, expr: &hir::Expr) {
                 adjustment::Adjust::NeverToAny |
                 adjustment::Adjust::ReifyFnPointer |
                 adjustment::Adjust::UnsafeFnPointer |
+                adjustment::Adjust::ClosureFnPointer |
                 adjustment::Adjust::MutToConstPointer => {
                     // Creating a closure/fn-pointer or unsizing consumes
                     // the input and stores it into the resulting rvalue.
index 05be35df959915f79434d403ad137ecd4fb84c14..c9722adc9510cc6f7eaa8f6a37e9295c4d983931 100644 (file)
@@ -17,7 +17,6 @@
 use ty::layout::{LayoutError, Pointer, SizeSkeleton};
 
 use syntax::abi::Abi::RustIntrinsic;
-use syntax::ast;
 use syntax_pos::Span;
 use hir::intravisit::{self, Visitor, NestedVisitorMap};
 use hir;
@@ -37,16 +36,45 @@ struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>
 }
 
+/// If the type is `Option<T>`, it will return `T`, otherwise
+/// the type itself. Works on most `Option`-like types.
+fn unpack_option_like<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                ty: Ty<'tcx>)
+                                -> Ty<'tcx> {
+    let (def, substs) = match ty.sty {
+        ty::TyAdt(def, substs) => (def, substs),
+        _ => return ty
+    };
+
+    if def.variants.len() == 2 && !def.repr.c && def.repr.int.is_none() {
+        let data_idx;
+
+        if def.variants[0].fields.is_empty() {
+            data_idx = 1;
+        } else if def.variants[1].fields.is_empty() {
+            data_idx = 0;
+        } else {
+            return ty;
+        }
+
+        if def.variants[data_idx].fields.len() == 1 {
+            return def.variants[data_idx].fields[0].ty(tcx, substs);
+        }
+    }
+
+    ty
+}
+
 impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
     fn def_id_is_transmute(&self, def_id: DefId) -> bool {
         let intrinsic = match self.infcx.tcx.item_type(def_id).sty {
-            ty::TyFnDef(.., ref bfty) => bfty.abi == RustIntrinsic,
+            ty::TyFnDef(.., bfty) => bfty.abi() == RustIntrinsic,
             _ => return false
         };
         intrinsic && self.infcx.tcx.item_name(def_id) == "transmute"
     }
 
-    fn check_transmute(&self, span: Span, from: Ty<'gcx>, to: Ty<'gcx>, id: ast::NodeId) {
+    fn check_transmute(&self, span: Span, from: Ty<'gcx>, to: Ty<'gcx>) {
         let sk_from = SizeSkeleton::compute(from, self.infcx);
         let sk_to = SizeSkeleton::compute(to, self.infcx);
 
@@ -56,15 +84,17 @@ fn check_transmute(&self, span: Span, from: Ty<'gcx>, to: Ty<'gcx>, id: ast::Nod
                 return;
             }
 
+            // Special-case transmutting from `typeof(function)` and
+            // `Option<typeof(function)>` to present a clearer error.
+            let from = unpack_option_like(self.infcx.tcx.global_tcx(), from);
             match (&from.sty, sk_to) {
                 (&ty::TyFnDef(..), SizeSkeleton::Known(size_to))
                         if size_to == Pointer.size(&self.infcx.tcx.data_layout) => {
-                    // FIXME #19925 Remove this warning after a release cycle.
-                    let msg = format!("`{}` is now zero-sized and has to be cast \
-                                       to a pointer before transmuting to `{}`",
-                                      from, to);
-                    self.infcx.tcx.sess.add_lint(
-                        ::lint::builtin::TRANSMUTE_FROM_FN_ITEM_TYPES, id, span, msg);
+                    struct_span_err!(self.infcx.tcx.sess, span, E0591,
+                                     "`{}` is zero-sized and can't be transmuted to `{}`",
+                                     from, to)
+                        .span_note(span, &format!("cast with `as` to a pointer instead"))
+                        .emit();
                     return;
                 }
                 _ => {}
@@ -137,10 +167,10 @@ fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
                 let typ = self.infcx.tables.borrow().node_id_to_type(expr.id);
                 let typ = self.infcx.tcx.lift_to_global(&typ).unwrap();
                 match typ.sty {
-                    ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
-                        let from = bare_fn_ty.sig.skip_binder().inputs()[0];
-                        let to = bare_fn_ty.sig.skip_binder().output();
-                        self.check_transmute(expr.span, from, to, expr.id);
+                    ty::TyFnDef(.., sig) if sig.abi() == RustIntrinsic => {
+                        let from = sig.inputs().skip_binder()[0];
+                        let to = *sig.output().skip_binder();
+                        self.check_transmute(expr.span, from, to);
                     }
                     _ => {
                         span_bug!(expr.span, "transmute wasn't a bare fn?!");
index 7fa3365694c269967868deb358faa7be9bd75250..a8c1559ae2373b309ca0072d0c0ec90790d1f917 100644 (file)
@@ -675,23 +675,6 @@ fn write_vars<F>(&self,
         Ok(())
     }
 
-    fn find_loop_scope(&self,
-                       opt_label: Option<hir::Label>,
-                       sp: Span)
-                       -> NodeId {
-        match opt_label {
-            Some(label) => label.loop_id,
-            None => {
-                // Vanilla 'break' or 'continue', so use the enclosing
-                // loop scope
-                if self.loop_scope.is_empty() {
-                    span_bug!(sp, "break outside loop");
-                } else {
-                    *self.loop_scope.last().unwrap()
-                }
-            }
-        }
-    }
 
     #[allow(unused_must_use)]
     fn ln_str(&self, ln: LiveNode) -> String {
@@ -1018,9 +1001,12 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
             self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), exit_ln)
           }
 
-          hir::ExprBreak(opt_label, ref opt_expr) => {
+          hir::ExprBreak(label, ref opt_expr) => {
               // Find which label this break jumps to
-              let sc = self.find_loop_scope(opt_label, expr.span);
+              let sc = match label.loop_id.into() {
+                  Ok(loop_id) => loop_id,
+                  Err(err) => span_bug!(expr.span, "loop scope error: {}", err),
+              };
 
               // Now that we know the label we're going to,
               // look it up in the break loop nodes table
@@ -1031,9 +1017,13 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
               }
           }
 
-          hir::ExprAgain(opt_label) => {
+          hir::ExprAgain(label) => {
               // Find which label this expr continues to
-              let sc = self.find_loop_scope(opt_label, expr.span);
+              let sc = match label.loop_id.into() {
+                  Ok(loop_id) => loop_id,
+                  Err(err) => span_bug!(expr.span, "loop scope error: {}", err),
+              };
+
 
               // Now that we know the label we're going to,
               // look it up in the continue loop nodes table
@@ -1297,12 +1287,13 @@ fn propagate_through_loop(&mut self,
         debug!("propagate_through_loop: using id for loop body {} {}",
                expr.id, self.ir.tcx.hir.node_to_pretty_string(body.id));
 
-        let cond_ln = match kind {
-            LoopLoop => ln,
-            WhileLoop(ref cond) => self.propagate_through_expr(&cond, ln),
-        };
-        let body_ln = self.with_loop_nodes(expr.id, succ, ln, |this| {
-            this.propagate_through_block(body, cond_ln)
+        let (cond_ln, body_ln) = self.with_loop_nodes(expr.id, succ, ln, |this| {
+            let cond_ln = match kind {
+                LoopLoop => ln,
+                WhileLoop(ref cond) => this.propagate_through_expr(&cond, ln),
+            };
+            let body_ln = this.propagate_through_block(body, cond_ln);
+            (cond_ln, body_ln)
         });
 
         // repeat until fixed point is reached:
@@ -1441,12 +1432,16 @@ fn check_ret(&self,
                  body: &hir::Body)
     {
         let fn_ty = self.ir.tcx.item_type(self.ir.tcx.hir.local_def_id(id));
-        let fn_ret = match fn_ty.sty {
-            ty::TyClosure(closure_def_id, substs) =>
-                self.ir.tcx.closure_type(closure_def_id, substs).sig.output(),
-            _ => fn_ty.fn_ret()
+        let fn_sig = match fn_ty.sty {
+            ty::TyClosure(closure_def_id, substs) => {
+                self.ir.tcx.closure_type(closure_def_id)
+                    .subst(self.ir.tcx, substs.substs)
+            }
+            _ => fn_ty.fn_sig()
         };
 
+        let fn_ret = fn_sig.output();
+
         // within the fn body, late-bound regions are liberated
         // and must outlive the *call-site* of the function.
         let fn_ret =
index 627753039bae3af63540160913ace07d18d34f0c..b0c85e2ef4cd48438df7796f250cc04dd45ad477 100644 (file)
@@ -464,6 +464,7 @@ pub fn cat_expr(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
                     adjustment::Adjust::NeverToAny |
                     adjustment::Adjust::ReifyFnPointer |
                     adjustment::Adjust::UnsafeFnPointer |
+                    adjustment::Adjust::ClosureFnPointer |
                     adjustment::Adjust::MutToConstPointer |
                     adjustment::Adjust::DerefRef {..} => {
                         debug!("cat_expr({:?}): {:?}",
index 9bad98dda83f83383725584e960187ebc4b43e4f..37749816eb153c725300a0eddba7f66cdc21b917 100644 (file)
@@ -995,7 +995,9 @@ fn visit_segment_parameters(&mut self,
             } else {
                 let cstore = &self.sess.cstore;
                 self.xcrate_object_lifetime_defaults.entry(def_id).or_insert_with(|| {
-                    cstore.item_generics_object_lifetime_defaults(def_id)
+                    cstore.item_generics_cloned(def_id).types.into_iter().map(|def| {
+                        def.object_lifetime_default
+                    }).collect()
                 })
             };
             unsubst.iter().map(|set| {
index 487e13b47fec2755effb15a351d6cd056cd592ad..baa22d706143519e6b20605b77d4bfebe2f399a7 100644 (file)
@@ -433,23 +433,27 @@ struct Checker<'a, 'tcx: 'a> {
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     // (See issue #38412)
-    fn skip_stability_check_due_to_privacy(self, def_id: DefId) -> bool {
-        let visibility = {
-            // Check if `def_id` is a trait method.
-            match self.sess.cstore.associated_item(def_id) {
-                Some(ty::AssociatedItem { container: ty::TraitContainer(trait_def_id), .. }) => {
-                    // Trait methods do not declare visibility (even
-                    // for visibility info in cstore). Use containing
-                    // trait instead, so methods of pub traits are
-                    // themselves considered pub.
-                    self.sess.cstore.visibility(trait_def_id)
-                }
-                _ => {
-                    // Otherwise, cstore info works directly.
-                    self.sess.cstore.visibility(def_id)
+    fn skip_stability_check_due_to_privacy(self, mut def_id: DefId) -> bool {
+        // Check if `def_id` is a trait method.
+        match self.sess.cstore.describe_def(def_id) {
+            Some(Def::Method(_)) |
+            Some(Def::AssociatedTy(_)) |
+            Some(Def::AssociatedConst(_)) => {
+                match self.associated_item(def_id).container {
+                    ty::TraitContainer(trait_def_id) => {
+                        // Trait methods do not declare visibility (even
+                        // for visibility info in cstore). Use containing
+                        // trait instead, so methods of pub traits are
+                        // themselves considered pub.
+                        def_id = trait_def_id;
+                    }
+                    _ => {}
                 }
             }
-        };
+            _ => {}
+        }
+
+        let visibility = self.sess.cstore.visibility(def_id);
 
         match visibility {
             // must check stability for pub items.
index 3403cf0477450005d7156bd027b4dd746608e029..10761a03bec0cabd1d05f7dfd669458479d85272 100644 (file)
@@ -542,7 +542,7 @@ pub fn successors_mut(&mut self) -> Vec<&mut BasicBlock> {
 impl<'tcx> TerminatorKind<'tcx> {
     pub fn if_<'a, 'gcx>(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>,
                          t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
-        static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::Infer(0)];
+        static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::U8(0)];
         TerminatorKind::SwitchInt {
             discr: cond,
             switch_ty: tcx.types.bool,
@@ -983,7 +983,7 @@ pub enum Rvalue<'tcx> {
     Use(Operand<'tcx>),
 
     /// [x; 32]
-    Repeat(Operand<'tcx>, TypedConstVal<'tcx>),
+    Repeat(Operand<'tcx>, ConstUsize),
 
     /// &x or &mut x
     Ref(&'tcx Region, BorrowKind, Lvalue<'tcx>),
@@ -1022,6 +1022,9 @@ pub enum CastKind {
     /// Convert unique, zero-sized type for a fn to fn()
     ReifyFnPointer,
 
+    /// Convert non capturing closure to fn()
+    ClosureFnPointer,
+
     /// Convert safe fn() to unsafe fn()
     UnsafeFnPointer,
 
@@ -1035,7 +1038,8 @@ pub enum CastKind {
 
 #[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum AggregateKind<'tcx> {
-    Array,
+    /// The type is of the element
+    Array(Ty<'tcx>),
     Tuple,
     /// The second field is variant number (discriminant), it's equal to 0
     /// for struct and union expressions. The fourth field is active field
@@ -1132,7 +1136,7 @@ fn fmt_tuple(fmt: &mut Formatter, lvs: &[Operand]) -> fmt::Result {
                 }
 
                 match *kind {
-                    AggregateKind::Array => write!(fmt, "{:?}", lvs),
+                    AggregateKind::Array(_) => write!(fmt, "{:?}", lvs),
 
                     AggregateKind::Tuple => {
                         match lvs.len() {
@@ -1199,19 +1203,6 @@ pub struct Constant<'tcx> {
     pub literal: Literal<'tcx>,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable)]
-pub struct TypedConstVal<'tcx> {
-    pub ty: Ty<'tcx>,
-    pub span: Span,
-    pub value: ConstUsize,
-}
-
-impl<'tcx> Debug for TypedConstVal<'tcx> {
-    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
-        write!(fmt, "const {}", ConstInt::Usize(self.value))
-    }
-}
-
 newtype_index!(Promoted, "promoted");
 
 #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
@@ -1221,7 +1212,7 @@ pub enum Literal<'tcx> {
         substs: &'tcx Substs<'tcx>,
     },
     Value {
-        value: ConstVal,
+        value: ConstVal<'tcx>,
     },
     Promoted {
         // Index into the `promoted` vector of `Mir`.
@@ -1268,7 +1259,7 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
             write!(fmt, "b\"{}\"", escaped)
         }
         Bool(b) => write!(fmt, "{:?}", b),
-        Function(def_id) => write!(fmt, "{}", item_path_str(def_id)),
+        Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
         Struct(_) | Tuple(_) | Array(_) | Repeat(..) =>
             bug!("ConstVal `{:?}` should not be in MIR", const_val),
         Char(c) => write!(fmt, "{:?}", c),
index 5c8d031caf60dafc365bcba535d7fb41a204b4fe..14d3876a66e5522a1c4e07a7e659045077369163 100644 (file)
@@ -134,46 +134,45 @@ pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Lval
 }
 
 impl<'tcx> Rvalue<'tcx> {
-    pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Ty<'tcx>>
+    pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>
     {
         match *self {
-            Rvalue::Use(ref operand) => Some(operand.ty(mir, tcx)),
+            Rvalue::Use(ref operand) => operand.ty(mir, tcx),
             Rvalue::Repeat(ref operand, ref count) => {
                 let op_ty = operand.ty(mir, tcx);
-                let count = count.value.as_u64(tcx.sess.target.uint_type);
+                let count = count.as_u64(tcx.sess.target.uint_type);
                 assert_eq!(count as usize as u64, count);
-                Some(tcx.mk_array(op_ty, count as usize))
+                tcx.mk_array(op_ty, count as usize)
             }
             Rvalue::Ref(reg, bk, ref lv) => {
                 let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
-                Some(tcx.mk_ref(reg,
+                tcx.mk_ref(reg,
                     ty::TypeAndMut {
                         ty: lv_ty,
                         mutbl: bk.to_mutbl_lossy()
                     }
-                ))
+                )
             }
-            Rvalue::Len(..) => Some(tcx.types.usize),
-            Rvalue::Cast(.., ty) => Some(ty),
+            Rvalue::Len(..) => tcx.types.usize,
+            Rvalue::Cast(.., ty) => ty,
             Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
                 let lhs_ty = lhs.ty(mir, tcx);
                 let rhs_ty = rhs.ty(mir, tcx);
-                Some(op.ty(tcx, lhs_ty, rhs_ty))
+                op.ty(tcx, lhs_ty, rhs_ty)
             }
             Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
                 let lhs_ty = lhs.ty(mir, tcx);
                 let rhs_ty = rhs.ty(mir, tcx);
                 let ty = op.ty(tcx, lhs_ty, rhs_ty);
-                let ty = tcx.intern_tup(&[ty, tcx.types.bool], false);
-                Some(ty)
+                tcx.intern_tup(&[ty, tcx.types.bool], false)
             }
             Rvalue::UnaryOp(_, ref operand) => {
-                Some(operand.ty(mir, tcx))
+                operand.ty(mir, tcx)
             }
             Rvalue::Discriminant(ref lval) => {
                 let ty = lval.ty(mir, tcx).to_ty(tcx);
                 if let ty::TyAdt(adt_def, _) = ty.sty {
-                    Some(adt_def.discr_ty.to_ty(tcx))
+                    adt_def.repr.discr_type().to_ty(tcx)
                 } else {
                     // Undefined behaviour, bug for now; may want to return something for
                     // the `discriminant` intrinsic later.
@@ -181,29 +180,24 @@ pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Opti
                 }
             }
             Rvalue::Box(t) => {
-                Some(tcx.mk_box(t))
+                tcx.mk_box(t)
             }
             Rvalue::Aggregate(ref ak, ref ops) => {
                 match *ak {
-                    AggregateKind::Array => {
-                        if let Some(operand) = ops.get(0) {
-                            let ty = operand.ty(mir, tcx);
-                            Some(tcx.mk_array(ty, ops.len()))
-                        } else {
-                            None
-                        }
+                    AggregateKind::Array(ty) => {
+                        tcx.mk_array(ty, ops.len())
                     }
                     AggregateKind::Tuple => {
-                        Some(tcx.mk_tup(
+                        tcx.mk_tup(
                             ops.iter().map(|op| op.ty(mir, tcx)),
                             false
-                        ))
+                        )
                     }
                     AggregateKind::Adt(def, _, substs, _) => {
-                        Some(tcx.item_type(def.did).subst(tcx, substs))
+                        tcx.item_type(def.did).subst(tcx, substs)
                     }
                     AggregateKind::Closure(did, substs) => {
-                        Some(tcx.mk_closure_from_closure_substs(did, substs))
+                        tcx.mk_closure_from_closure_substs(did, substs)
                     }
                 }
             }
index 652fef76f288a486b6ab6df8ef82bd4c15c1f16a..4cbbb67c7e43d8a1cd1caa7648b2064a2c215407 100644 (file)
@@ -114,14 +114,14 @@ fn run_pass<'a>(&mut self,
                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     hooks: &mut [Box<for<'s> MirPassHook<'s>>])
     {
-        let def_ids = tcx.mir_map.borrow().keys();
+        let def_ids = tcx.maps.mir.borrow().keys();
         for def_id in def_ids {
             if !def_id.is_local() {
                 continue;
             }
 
             let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
-            let mir = &mut tcx.mir_map.borrow()[&def_id].borrow_mut();
+            let mir = &mut tcx.maps.mir.borrow()[&def_id].borrow_mut();
             tcx.dep_graph.write(DepNode::Mir(def_id));
 
             let id = tcx.hir.as_local_node_id(def_id).unwrap();
index 7cdbd5cae061fc0f8b7100ae1ec9a2cbffab6fee..980d1806e78f8b34d60f94bc3816044b835cf128 100644 (file)
@@ -235,12 +235,6 @@ fn visit_const_usize(&mut self,
                 self.super_const_usize(const_usize);
             }
 
-            fn visit_typed_const_val(&mut self,
-                                     val: & $($mutability)* TypedConstVal<'tcx>,
-                                     location: Location) {
-                self.super_typed_const_val(val, location);
-            }
-
             fn visit_local_decl(&mut self,
                                 local_decl: & $($mutability)* LocalDecl<'tcx>) {
                 self.super_local_decl(local_decl);
@@ -467,9 +461,9 @@ fn super_rvalue(&mut self,
                     }
 
                     Rvalue::Repeat(ref $($mutability)* value,
-                                   ref $($mutability)* typed_const_val) => {
+                                   ref $($mutability)* length) => {
                         self.visit_operand(value, location);
-                        self.visit_typed_const_val(typed_const_val, location);
+                        self.visit_const_usize(length, location);
                     }
 
                     Rvalue::Ref(r, bk, ref $($mutability)* path) => {
@@ -515,7 +509,8 @@ fn super_rvalue(&mut self,
                     Rvalue::Aggregate(ref $($mutability)* kind,
                                       ref $($mutability)* operands) => {
                         match *kind {
-                            AggregateKind::Array => {
+                            AggregateKind::Array(ref $($mutability)* ty) => {
+                                self.visit_ty(ty);
                             }
                             AggregateKind::Tuple => {
                             }
@@ -647,20 +642,6 @@ fn super_constant(&mut self,
                 self.visit_literal(literal, location);
             }
 
-            fn super_typed_const_val(&mut self,
-                                     constant: & $($mutability)* TypedConstVal<'tcx>,
-                                     location: Location) {
-                let TypedConstVal {
-                    ref $($mutability)* span,
-                    ref $($mutability)* ty,
-                    ref $($mutability)* value,
-                } = *constant;
-
-                self.visit_span(span);
-                self.visit_ty(ty);
-                self.visit_const_usize(value, location);
-            }
-
             fn super_literal(&mut self,
                              literal: & $($mutability)* Literal<'tcx>,
                              location: Location) {
index 24615f2fa699213346c07cb91034d79e4a60161b..5fff03dabcecef2f41fe9cb57169f51db6eae4d9 100644 (file)
@@ -51,7 +51,7 @@ pub struct Config {
     pub uint_type: UintTy,
 }
 
-#[derive(Clone)]
+#[derive(Clone, Hash)]
 pub enum Sanitizer {
     Address,
     Leak,
@@ -288,7 +288,7 @@ pub struct Options {
         //            much sense: The search path can stay the same while the
         //            things discovered there might have changed on disk.
         search_paths: SearchPaths [TRACKED],
-        libs: Vec<(String, Option<String>, cstore::NativeLibraryKind)> [TRACKED],
+        libs: Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> [TRACKED],
         maybe_sysroot: Option<PathBuf> [TRACKED],
 
         target_triple: String [TRACKED],
@@ -804,6 +804,8 @@ fn parse_sanitizer(slote: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
         "save all temporary output files during compilation"),
     rpath: bool = (false, parse_bool, [UNTRACKED],
         "set rpath values in libs/exes"),
+    overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "use overflow checks for integer arithmetic"),
     no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
         "don't pre-populate the pass manager with a list of passes"),
     no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
@@ -970,7 +972,7 @@ fn parse_sanitizer(slote: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
           "encode MIR of all functions into the crate metadata"),
     osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
           "pass `-install_name @rpath/...` to the OSX linker"),
-    sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [UNTRACKED],
+    sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
                                    "Use a sanitizer"),
 }
 
@@ -1495,18 +1497,18 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
         let mut parts = s.splitn(2, '=');
         let kind = parts.next().unwrap();
         let (name, kind) = match (parts.next(), kind) {
-            (None, name) |
-            (Some(name), "dylib") => (name, cstore::NativeUnknown),
-            (Some(name), "framework") => (name, cstore::NativeFramework),
-            (Some(name), "static") => (name, cstore::NativeStatic),
-            (Some(name), "static-nobundle") => (name, cstore::NativeStaticNobundle),
+            (None, name) => (name, None),
+            (Some(name), "dylib") => (name, Some(cstore::NativeUnknown)),
+            (Some(name), "framework") => (name, Some(cstore::NativeFramework)),
+            (Some(name), "static") => (name, Some(cstore::NativeStatic)),
+            (Some(name), "static-nobundle") => (name, Some(cstore::NativeStaticNobundle)),
             (_, s) => {
                 early_error(error_format, &format!("unknown library kind `{}`, expected \
                                                   one of dylib, framework, or static",
                                                  s));
             }
         };
-        if kind == cstore::NativeStaticNobundle && !nightly_options::is_nightly_build() {
+        if kind == Some(cstore::NativeStaticNobundle) && !nightly_options::is_nightly_build() {
             early_error(error_format, &format!("the library kind 'static-nobundle' is only \
                                                 accepted on the nightly compiler"));
         }
@@ -1728,7 +1730,7 @@ mod dep_tracking {
     use std::path::PathBuf;
     use std::collections::hash_map::DefaultHasher;
     use super::{Passes, CrateType, OptLevel, DebugInfoLevel,
-                OutputTypes, Externs, ErrorOutputType};
+                OutputTypes, Externs, ErrorOutputType, Sanitizer};
     use syntax::feature_gate::UnstableFeatures;
     use rustc_back::PanicStrategy;
 
@@ -1772,6 +1774,7 @@ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
     impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
     impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
     impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
+    impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
     impl_dep_tracking_hash_via_hash!(CrateType);
     impl_dep_tracking_hash_via_hash!(PanicStrategy);
     impl_dep_tracking_hash_via_hash!(Passes);
@@ -1781,12 +1784,14 @@ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
     impl_dep_tracking_hash_via_hash!(Externs);
     impl_dep_tracking_hash_via_hash!(OutputTypes);
     impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
+    impl_dep_tracking_hash_via_hash!(Sanitizer);
+    impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
 
     impl_dep_tracking_hash_for_sortable_vec_of!(String);
     impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
     impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
     impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>,
-                                                 cstore::NativeLibraryKind));
+                                                 Option<cstore::NativeLibraryKind>));
     impl DepTrackingHash for SearchPaths {
         fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
             let mut elems: Vec<_> = self
@@ -2230,24 +2235,24 @@ fn test_native_libs_tracking_hash_different_values() {
         let mut v4 = super::basic_options();
 
         // Reference
-        v1.libs = vec![(String::from("a"), None, cstore::NativeStatic),
-                       (String::from("b"), None, cstore::NativeFramework),
-                       (String::from("c"), None, cstore::NativeUnknown)];
+        v1.libs = vec![(String::from("a"), None, Some(cstore::NativeStatic)),
+                       (String::from("b"), None, Some(cstore::NativeFramework)),
+                       (String::from("c"), None, Some(cstore::NativeUnknown))];
 
         // Change label
-        v2.libs = vec![(String::from("a"), None, cstore::NativeStatic),
-                       (String::from("X"), None, cstore::NativeFramework),
-                       (String::from("c"), None, cstore::NativeUnknown)];
+        v2.libs = vec![(String::from("a"), None, Some(cstore::NativeStatic)),
+                       (String::from("X"), None, Some(cstore::NativeFramework)),
+                       (String::from("c"), None, Some(cstore::NativeUnknown))];
 
         // Change kind
-        v3.libs = vec![(String::from("a"), None, cstore::NativeStatic),
-                       (String::from("b"), None, cstore::NativeStatic),
-                       (String::from("c"), None, cstore::NativeUnknown)];
+        v3.libs = vec![(String::from("a"), None, Some(cstore::NativeStatic)),
+                       (String::from("b"), None, Some(cstore::NativeStatic)),
+                       (String::from("c"), None, Some(cstore::NativeUnknown))];
 
         // Change new-name
-        v4.libs = vec![(String::from("a"), None, cstore::NativeStatic),
-                       (String::from("b"), Some(String::from("X")), cstore::NativeFramework),
-                       (String::from("c"), None, cstore::NativeUnknown)];
+        v4.libs = vec![(String::from("a"), None, Some(cstore::NativeStatic)),
+                       (String::from("b"), Some(String::from("X")), Some(cstore::NativeFramework)),
+                       (String::from("c"), None, Some(cstore::NativeUnknown))];
 
         assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
         assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
@@ -2267,17 +2272,17 @@ fn test_native_libs_tracking_hash_different_order() {
         let mut v3 = super::basic_options();
 
         // Reference
-        v1.libs = vec![(String::from("a"), None, cstore::NativeStatic),
-                       (String::from("b"), None, cstore::NativeFramework),
-                       (String::from("c"), None, cstore::NativeUnknown)];
+        v1.libs = vec![(String::from("a"), None, Some(cstore::NativeStatic)),
+                       (String::from("b"), None, Some(cstore::NativeFramework)),
+                       (String::from("c"), None, Some(cstore::NativeUnknown))];
 
-        v2.libs = vec![(String::from("b"), None, cstore::NativeFramework),
-                       (String::from("a"), None, cstore::NativeStatic),
-                       (String::from("c"), None, cstore::NativeUnknown)];
+        v2.libs = vec![(String::from("b"), None, Some(cstore::NativeFramework)),
+                       (String::from("a"), None, Some(cstore::NativeStatic)),
+                       (String::from("c"), None, Some(cstore::NativeUnknown))];
 
-        v3.libs = vec![(String::from("c"), None, cstore::NativeUnknown),
-                       (String::from("a"), None, cstore::NativeStatic),
-                       (String::from("b"), None, cstore::NativeFramework)];
+        v3.libs = vec![(String::from("c"), None, Some(cstore::NativeUnknown)),
+                       (String::from("a"), None, Some(cstore::NativeStatic)),
+                       (String::from("b"), None, Some(cstore::NativeFramework))];
 
         assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
         assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
@@ -2345,6 +2350,10 @@ fn test_codegen_options_tracking_hash() {
         opts.cg.llvm_args = vec![String::from("1"), String::from("2")];
         assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
 
+        opts = reference.clone();
+        opts.cg.overflow_checks = Some(true);
+        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
         opts = reference.clone();
         opts.cg.no_prepopulate_passes = true;
         assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
index f10ea3544f2cae7566189ae262e5ab43bce6ca63..3ba82f34c3266a804fece8554e94707fb562c796 100644 (file)
@@ -64,7 +64,7 @@ pub struct Session {
     pub target: config::Config,
     pub host: Target,
     pub opts: config::Options,
-    pub cstore: Rc<for<'a> CrateStore<'a>>,
+    pub cstore: Rc<CrateStore>,
     pub parse_sess: ParseSess,
     // For a library crate, this is always none
     pub entry_fn: RefCell<Option<(NodeId, Span)>>,
@@ -372,6 +372,11 @@ pub fn unstable_options(&self) -> bool {
     pub fn nonzeroing_move_hints(&self) -> bool {
         self.opts.debugging_opts.enable_nonzeroing_move_hints
     }
+    pub fn overflow_checks(&self) -> bool {
+        self.opts.cg.overflow_checks
+            .or(self.opts.debugging_opts.force_overflow_checks)
+            .unwrap_or(self.opts.debug_assertions)
+    }
 
     pub fn must_not_eliminate_frame_pointers(&self) -> bool {
         self.opts.debuginfo != DebugInfoLevel::NoDebugInfo ||
@@ -505,7 +510,7 @@ pub fn build_session(sopts: config::Options,
                      dep_graph: &DepGraph,
                      local_crate_source_file: Option<PathBuf>,
                      registry: errors::registry::Registry,
-                     cstore: Rc<for<'a> CrateStore<'a>>)
+                     cstore: Rc<CrateStore>)
                      -> Session {
     build_session_with_codemap(sopts,
                                dep_graph,
@@ -520,7 +525,7 @@ pub fn build_session_with_codemap(sopts: config::Options,
                                   dep_graph: &DepGraph,
                                   local_crate_source_file: Option<PathBuf>,
                                   registry: errors::registry::Registry,
-                                  cstore: Rc<for<'a> CrateStore<'a>>,
+                                  cstore: Rc<CrateStore>,
                                   codemap: Rc<codemap::CodeMap>,
                                   emitter_dest: Option<Box<Write + Send>>)
                                   -> Session {
@@ -570,7 +575,7 @@ pub fn build_session_(sopts: config::Options,
                       local_crate_source_file: Option<PathBuf>,
                       span_diagnostic: errors::Handler,
                       codemap: Rc<codemap::CodeMap>,
-                      cstore: Rc<for<'a> CrateStore<'a>>)
+                      cstore: Rc<CrateStore>)
                       -> Session {
     let host = match Target::search(config::host_triple()) {
         Ok(t) => t,
index 70ca5fe83a93299e3d529113426e60fef2af79b2..f850fd97727810ca3230bed219a0d9e2b579443b 100644 (file)
@@ -21,7 +21,6 @@
     SelectionContext,
     SelectionError,
     ObjectSafetyViolation,
-    MethodViolationCode,
 };
 
 use fmt_macros::{Parser, Piece, Position};
@@ -267,61 +266,63 @@ fn on_unimplemented_note(&self,
 
         let span = obligation.cause.span;
         let mut report = None;
-        for item in self.tcx.get_attrs(def_id).iter() {
-            if item.check_name("rustc_on_unimplemented") {
-                let err_sp = item.meta().span.substitute_dummy(span);
-                let trait_str = self.tcx.item_path_str(trait_ref.def_id);
-                if let Some(istring) = item.value_str() {
-                    let istring = &*istring.as_str();
-                    let generics = self.tcx.item_generics(trait_ref.def_id);
-                    let generic_map = generics.types.iter().map(|param| {
-                        (param.name.as_str().to_string(),
-                         trait_ref.substs.type_for_def(param).to_string())
-                    }).collect::<FxHashMap<String, String>>();
-                    let parser = Parser::new(istring);
-                    let mut errored = false;
-                    let err: String = parser.filter_map(|p| {
-                        match p {
-                            Piece::String(s) => Some(s),
-                            Piece::NextArgument(a) => match a.position {
-                                Position::ArgumentNamed(s) => match generic_map.get(s) {
-                                    Some(val) => Some(val),
-                                    None => {
-                                        span_err!(self.tcx.sess, err_sp, E0272,
-                                                       "the #[rustc_on_unimplemented] \
-                                                                attribute on \
-                                                                trait definition for {} refers to \
-                                                                non-existent type parameter {}",
-                                                               trait_str, s);
-                                        errored = true;
-                                        None
-                                    }
-                                },
-                                _ => {
-                                    span_err!(self.tcx.sess, err_sp, E0273,
-                                              "the #[rustc_on_unimplemented] attribute \
-                                               on trait definition for {} must have \
-                                               named format arguments, eg \
-                                               `#[rustc_on_unimplemented = \
-                                                \"foo {{T}}\"]`", trait_str);
+        if let Some(item) = self.tcx
+            .get_attrs(def_id)
+            .into_iter()
+            .filter(|a| a.check_name("rustc_on_unimplemented"))
+            .next()
+        {
+            let err_sp = item.meta().span.substitute_dummy(span);
+            let trait_str = self.tcx.item_path_str(trait_ref.def_id);
+            if let Some(istring) = item.value_str() {
+                let istring = &*istring.as_str();
+                let generics = self.tcx.item_generics(trait_ref.def_id);
+                let generic_map = generics.types.iter().map(|param| {
+                    (param.name.as_str().to_string(),
+                        trait_ref.substs.type_for_def(param).to_string())
+                }).collect::<FxHashMap<String, String>>();
+                let parser = Parser::new(istring);
+                let mut errored = false;
+                let err: String = parser.filter_map(|p| {
+                    match p {
+                        Piece::String(s) => Some(s),
+                        Piece::NextArgument(a) => match a.position {
+                            Position::ArgumentNamed(s) => match generic_map.get(s) {
+                                Some(val) => Some(val),
+                                None => {
+                                    span_err!(self.tcx.sess, err_sp, E0272,
+                                                    "the #[rustc_on_unimplemented] \
+                                                            attribute on \
+                                                            trait definition for {} refers to \
+                                                            non-existent type parameter {}",
+                                                            trait_str, s);
                                     errored = true;
                                     None
                                 }
+                            },
+                            _ => {
+                                span_err!(self.tcx.sess, err_sp, E0273,
+                                            "the #[rustc_on_unimplemented] attribute \
+                                            on trait definition for {} must have \
+                                            named format arguments, eg \
+                                            `#[rustc_on_unimplemented = \
+                                            \"foo {{T}}\"]`", trait_str);
+                                errored = true;
+                                None
                             }
                         }
-                    }).collect();
-                    // Report only if the format string checks out
-                    if !errored {
-                        report = Some(err);
                     }
-                } else {
-                    span_err!(self.tcx.sess, err_sp, E0274,
-                                            "the #[rustc_on_unimplemented] attribute on \
-                                                     trait definition for {} must have a value, \
-                                                     eg `#[rustc_on_unimplemented = \"foo\"]`",
-                                                     trait_str);
+                }).collect();
+                // Report only if the format string checks out
+                if !errored {
+                    report = Some(err);
                 }
-                break;
+            } else {
+                span_err!(self.tcx.sess, err_sp, E0274,
+                                        "the #[rustc_on_unimplemented] attribute on \
+                                                    trait definition for {} must have a value, \
+                                                    eg `#[rustc_on_unimplemented = \"foo\"]`",
+                                                    trait_str);
             }
         }
         report
@@ -359,34 +360,9 @@ fn find_similar_impl_candidates(&self,
     }
 
     fn report_similar_impl_candidates(&self,
-                                      trait_ref: ty::PolyTraitRef<'tcx>,
+                                      impl_candidates: Vec<ty::TraitRef<'tcx>>,
                                       err: &mut DiagnosticBuilder)
     {
-        let simp = fast_reject::simplify_type(self.tcx,
-                                              trait_ref.skip_binder().self_ty(),
-                                              true);
-        let mut impl_candidates = Vec::new();
-        let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id());
-
-        match simp {
-            Some(simp) => trait_def.for_each_impl(self.tcx, |def_id| {
-                let imp = self.tcx.impl_trait_ref(def_id).unwrap();
-                let imp_simp = fast_reject::simplify_type(self.tcx,
-                                                          imp.self_ty(),
-                                                          true);
-                if let Some(imp_simp) = imp_simp {
-                    if simp != imp_simp {
-                        return;
-                    }
-                }
-                impl_candidates.push(imp);
-            }),
-            None => trait_def.for_each_impl(self.tcx, |def_id| {
-                impl_candidates.push(
-                    self.tcx.impl_trait_ref(def_id).unwrap());
-            })
-        };
-
         if impl_candidates.is_empty() {
             return;
         }
@@ -525,127 +501,118 @@ pub fn report_selection_error(&self,
                         lint_id)
                         .emit();
                     return;
-                } else {
-                    match obligation.predicate {
-                        ty::Predicate::Trait(ref trait_predicate) => {
-                            let trait_predicate =
-                                self.resolve_type_vars_if_possible(trait_predicate);
-
-                            if self.tcx.sess.has_errors() && trait_predicate.references_error() {
-                                return;
-                            } else {
-                                let trait_ref = trait_predicate.to_poly_trait_ref();
-                                let (post_message, pre_message) = match self.get_parent_trait_ref(
-                                    &obligation.cause.code)
-                                {
-                                    Some(t) => {
-                                        (format!(" in `{}`", t), format!("within `{}`, ", t))
-                                    }
-                                    None => (String::new(), String::new()),
-                                };
-                                let mut err = struct_span_err!(
-                                    self.tcx.sess,
-                                    span,
-                                    E0277,
-                                    "the trait bound `{}` is not satisfied{}",
-                                    trait_ref.to_predicate(),
-                                    post_message);
-                                err.span_label(span,
-                                               &format!("{}the trait `{}` is not \
-                                                         implemented for `{}`",
-                                                        pre_message,
-                                                        trait_ref,
-                                                        trait_ref.self_ty()));
-
-                                // Try to report a help message
-
-                                if !trait_ref.has_infer_types() &&
-                                    self.predicate_can_apply(trait_ref) {
-                                    // If a where-clause may be useful, remind the
-                                    // user that they can add it.
-                                    //
-                                    // don't display an on-unimplemented note, as
-                                    // these notes will often be of the form
-                                    //     "the type `T` can't be frobnicated"
-                                    // which is somewhat confusing.
-                                    err.help(&format!("consider adding a `where {}` bound",
-                                                      trait_ref.to_predicate()));
-                                } else if let Some(s) = self.on_unimplemented_note(trait_ref,
-                                                                                   obligation) {
-                                    // If it has a custom "#[rustc_on_unimplemented]"
-                                    // error message, let's display it!
-                                    err.note(&s);
-                                } else {
-                                    // If we can't show anything useful, try to find
-                                    // similar impls.
-                                    let impl_candidates =
-                                        self.find_similar_impl_candidates(trait_ref);
-                                    if impl_candidates.len() > 0 {
-                                        self.report_similar_impl_candidates(trait_ref, &mut err);
-                                    }
-                                }
-                                err
-                            }
-                        }
+                }
+                match obligation.predicate {
+                    ty::Predicate::Trait(ref trait_predicate) => {
+                        let trait_predicate =
+                            self.resolve_type_vars_if_possible(trait_predicate);
 
-                        ty::Predicate::Equate(ref predicate) => {
-                            let predicate = self.resolve_type_vars_if_possible(predicate);
-                            let err = self.equality_predicate(&obligation.cause,
-                                                              &predicate).err().unwrap();
-                            struct_span_err!(self.tcx.sess, span, E0278,
-                                "the requirement `{}` is not satisfied (`{}`)",
-                                predicate, err)
+                        if self.tcx.sess.has_errors() && trait_predicate.references_error() {
+                            return;
                         }
-
-                        ty::Predicate::RegionOutlives(ref predicate) => {
-                            let predicate = self.resolve_type_vars_if_possible(predicate);
-                            let err = self.region_outlives_predicate(&obligation.cause,
-                                                                     &predicate).err().unwrap();
-                            struct_span_err!(self.tcx.sess, span, E0279,
-                                "the requirement `{}` is not satisfied (`{}`)",
-                                predicate, err)
+                        let trait_ref = trait_predicate.to_poly_trait_ref();
+                        let (post_message, pre_message) =
+                            self.get_parent_trait_ref(&obligation.cause.code)
+                                .map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
+                                .unwrap_or((String::new(), String::new()));
+                        let mut err = struct_span_err!(
+                            self.tcx.sess,
+                            span,
+                            E0277,
+                            "the trait bound `{}` is not satisfied{}",
+                            trait_ref.to_predicate(),
+                            post_message);
+                        err.span_label(span,
+                                        &format!("{}the trait `{}` is not \
+                                                    implemented for `{}`",
+                                                pre_message,
+                                                trait_ref,
+                                                trait_ref.self_ty()));
+
+                        // Try to report a help message
+
+                        if !trait_ref.has_infer_types() &&
+                            self.predicate_can_apply(trait_ref) {
+                            // If a where-clause may be useful, remind the
+                            // user that they can add it.
+                            //
+                            // don't display an on-unimplemented note, as
+                            // these notes will often be of the form
+                            //     "the type `T` can't be frobnicated"
+                            // which is somewhat confusing.
+                            err.help(&format!("consider adding a `where {}` bound",
+                                                trait_ref.to_predicate()));
+                        } else if let Some(s) = self.on_unimplemented_note(trait_ref,
+                                                                            obligation) {
+                            // If it has a custom "#[rustc_on_unimplemented]"
+                            // error message, let's display it!
+                            err.note(&s);
+                        } else {
+                            // If we can't show anything useful, try to find
+                            // similar impls.
+                            let impl_candidates = self.find_similar_impl_candidates(trait_ref);
+                            self.report_similar_impl_candidates(impl_candidates, &mut err);
                         }
+                        err
+                    }
 
-                        ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
-                            let predicate =
-                                self.resolve_type_vars_if_possible(&obligation.predicate);
-                            struct_span_err!(self.tcx.sess, span, E0280,
-                                "the requirement `{}` is not satisfied",
-                                predicate)
-                        }
+                    ty::Predicate::Equate(ref predicate) => {
+                        let predicate = self.resolve_type_vars_if_possible(predicate);
+                        let err = self.equality_predicate(&obligation.cause,
+                                                            &predicate).err().unwrap();
+                        struct_span_err!(self.tcx.sess, span, E0278,
+                            "the requirement `{}` is not satisfied (`{}`)",
+                            predicate, err)
+                    }
 
-                        ty::Predicate::ObjectSafe(trait_def_id) => {
-                            let violations = self.tcx.object_safety_violations(trait_def_id);
-                            self.tcx.report_object_safety_error(span,
-                                                                trait_def_id,
-                                                                violations)
-                        }
+                    ty::Predicate::RegionOutlives(ref predicate) => {
+                        let predicate = self.resolve_type_vars_if_possible(predicate);
+                        let err = self.region_outlives_predicate(&obligation.cause,
+                                                                    &predicate).err().unwrap();
+                        struct_span_err!(self.tcx.sess, span, E0279,
+                            "the requirement `{}` is not satisfied (`{}`)",
+                            predicate, err)
+                    }
 
-                        ty::Predicate::ClosureKind(closure_def_id, kind) => {
-                            let found_kind = self.closure_kind(closure_def_id).unwrap();
-                            let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap();
-                            let mut err = struct_span_err!(
-                                self.tcx.sess, closure_span, E0525,
-                                "expected a closure that implements the `{}` trait, \
-                                 but this closure only implements `{}`",
-                                kind,
-                                found_kind);
-                            err.span_note(
-                                obligation.cause.span,
-                                &format!("the requirement to implement \
-                                          `{}` derives from here", kind));
-                            err.emit();
-                            return;
-                        }
+                    ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
+                        let predicate =
+                            self.resolve_type_vars_if_possible(&obligation.predicate);
+                        struct_span_err!(self.tcx.sess, span, E0280,
+                            "the requirement `{}` is not satisfied",
+                            predicate)
+                    }
 
-                        ty::Predicate::WellFormed(ty) => {
-                            // WF predicates cannot themselves make
-                            // errors. They can only block due to
-                            // ambiguity; otherwise, they always
-                            // degenerate into other obligations
-                            // (which may fail).
-                            span_bug!(span, "WF predicate not satisfied for {:?}", ty);
-                        }
+                    ty::Predicate::ObjectSafe(trait_def_id) => {
+                        let violations = self.tcx.object_safety_violations(trait_def_id);
+                        self.tcx.report_object_safety_error(span,
+                                                            trait_def_id,
+                                                            violations)
+                    }
+
+                    ty::Predicate::ClosureKind(closure_def_id, kind) => {
+                        let found_kind = self.closure_kind(closure_def_id).unwrap();
+                        let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap();
+                        let mut err = struct_span_err!(
+                            self.tcx.sess, closure_span, E0525,
+                            "expected a closure that implements the `{}` trait, \
+                                but this closure only implements `{}`",
+                            kind,
+                            found_kind);
+                        err.span_note(
+                            obligation.cause.span,
+                            &format!("the requirement to implement \
+                                        `{}` derives from here", kind));
+                        err.emit();
+                        return;
+                    }
+
+                    ty::Predicate::WellFormed(ty) => {
+                        // WF predicates cannot themselves make
+                        // errors. They can only block due to
+                        // ambiguity; otherwise, they always
+                        // degenerate into other obligations
+                        // (which may fail).
+                        span_bug!(span, "WF predicate not satisfied for {:?}", ty);
                     }
                 }
             }
@@ -713,38 +680,7 @@ pub fn report_object_safety_error(self,
             if !reported_violations.insert(violation.clone()) {
                 continue;
             }
-            let buf;
-            let note = match violation {
-                ObjectSafetyViolation::SizedSelf => {
-                    "the trait cannot require that `Self : Sized`"
-                }
-
-                ObjectSafetyViolation::SupertraitSelf => {
-                    "the trait cannot use `Self` as a type parameter \
-                         in the supertrait listing"
-                }
-
-                ObjectSafetyViolation::Method(name,
-                                              MethodViolationCode::StaticMethod) => {
-                    buf = format!("method `{}` has no receiver", name);
-                    &buf
-                }
-
-                ObjectSafetyViolation::Method(name,
-                                              MethodViolationCode::ReferencesSelf) => {
-                    buf = format!("method `{}` references the `Self` type \
-                                       in its arguments or return type",
-                                  name);
-                    &buf
-                }
-
-                ObjectSafetyViolation::Method(name,
-                                              MethodViolationCode::Generic) => {
-                    buf = format!("method `{}` has generic type parameters", name);
-                    &buf
-                }
-            };
-            err.note(note);
+            err.note(&violation.error_msg());
         }
         err
     }
@@ -774,46 +710,46 @@ fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) {
                 let trait_ref = data.to_poly_trait_ref();
                 let self_ty = trait_ref.self_ty();
                 if predicate.references_error() {
-                } else {
-                    // Typically, this ambiguity should only happen if
-                    // there are unresolved type inference variables
-                    // (otherwise it would suggest a coherence
-                    // failure). But given #21974 that is not necessarily
-                    // the case -- we can have multiple where clauses that
-                    // are only distinguished by a region, which results
-                    // in an ambiguity even when all types are fully
-                    // known, since we don't dispatch based on region
-                    // relationships.
-
-                    // This is kind of a hack: it frequently happens that some earlier
-                    // error prevents types from being fully inferred, and then we get
-                    // a bunch of uninteresting errors saying something like "<generic
-                    // #0> doesn't implement Sized".  It may even be true that we
-                    // could just skip over all checks where the self-ty is an
-                    // inference variable, but I was afraid that there might be an
-                    // inference variable created, registered as an obligation, and
-                    // then never forced by writeback, and hence by skipping here we'd
-                    // be ignoring the fact that we don't KNOW the type works
-                    // out. Though even that would probably be harmless, given that
-                    // we're only talking about builtin traits, which are known to be
-                    // inhabited. But in any case I just threw in this check for
-                    // has_errors() to be sure that compilation isn't happening
-                    // anyway. In that case, why inundate the user.
-                    if !self.tcx.sess.has_errors() {
-                        if
-                            self.tcx.lang_items.sized_trait()
-                            .map_or(false, |sized_id| sized_id == trait_ref.def_id())
-                        {
-                            self.need_type_info(obligation, self_ty);
-                        } else {
-                            let mut err = struct_span_err!(self.tcx.sess,
-                                                           obligation.cause.span, E0283,
-                                                           "type annotations required: \
-                                                            cannot resolve `{}`",
-                                                           predicate);
-                            self.note_obligation_cause(&mut err, obligation);
-                            err.emit();
-                        }
+                    return;
+                }
+                // Typically, this ambiguity should only happen if
+                // there are unresolved type inference variables
+                // (otherwise it would suggest a coherence
+                // failure). But given #21974 that is not necessarily
+                // the case -- we can have multiple where clauses that
+                // are only distinguished by a region, which results
+                // in an ambiguity even when all types are fully
+                // known, since we don't dispatch based on region
+                // relationships.
+
+                // This is kind of a hack: it frequently happens that some earlier
+                // error prevents types from being fully inferred, and then we get
+                // a bunch of uninteresting errors saying something like "<generic
+                // #0> doesn't implement Sized".  It may even be true that we
+                // could just skip over all checks where the self-ty is an
+                // inference variable, but I was afraid that there might be an
+                // inference variable created, registered as an obligation, and
+                // then never forced by writeback, and hence by skipping here we'd
+                // be ignoring the fact that we don't KNOW the type works
+                // out. Though even that would probably be harmless, given that
+                // we're only talking about builtin traits, which are known to be
+                // inhabited. But in any case I just threw in this check for
+                // has_errors() to be sure that compilation isn't happening
+                // anyway. In that case, why inundate the user.
+                if !self.tcx.sess.has_errors() {
+                    if
+                        self.tcx.lang_items.sized_trait()
+                        .map_or(false, |sized_id| sized_id == trait_ref.def_id())
+                    {
+                        self.need_type_info(obligation, self_ty);
+                    } else {
+                        let mut err = struct_span_err!(self.tcx.sess,
+                                                        obligation.cause.span, E0283,
+                                                        "type annotations required: \
+                                                        cannot resolve `{}`",
+                                                        predicate);
+                        self.note_obligation_cause(&mut err, obligation);
+                        err.emit();
                     }
                 }
             }
index 23c28037a3c2d7b629f211c195446299032a6e0d..b87d18464377f6b3f4481210de7eb09651fff63b 100644 (file)
 use dep_graph::DepGraph;
 use infer::{InferCtxt, InferOk};
 use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate};
-use ty::subst::Subst;
 use rustc_data_structures::obligation_forest::{ObligationForest, Error};
 use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
 use std::marker::PhantomData;
-use std::mem;
 use syntax::ast;
 use util::nodemap::{FxHashSet, NodeMap};
 use hir::def_id::DefId;
@@ -23,9 +21,8 @@
 use super::CodeAmbiguity;
 use super::CodeProjectionError;
 use super::CodeSelectionError;
-use super::{FulfillmentError, FulfillmentErrorCode, SelectionError};
-use super::{ObligationCause, BuiltinDerivedObligation};
-use super::{PredicateObligation, TraitObligation, Obligation};
+use super::{FulfillmentError, FulfillmentErrorCode};
+use super::{ObligationCause, PredicateObligation, Obligation};
 use super::project;
 use super::select::SelectionContext;
 use super::Unimplemented;
@@ -82,10 +79,6 @@ pub struct FulfillmentContext<'tcx> {
     // obligations (otherwise, it's easy to fail to walk to a
     // particular node-id).
     region_obligations: NodeMap<Vec<RegionObligation<'tcx>>>,
-
-    // A list of obligations that need to be deferred to
-    // a later time for them to be properly fulfilled.
-    deferred_obligations: Vec<DeferredObligation<'tcx>>,
 }
 
 #[derive(Clone)]
@@ -101,100 +94,12 @@ pub struct PendingPredicateObligation<'tcx> {
     pub stalled_on: Vec<Ty<'tcx>>,
 }
 
-/// An obligation which cannot be fulfilled in the context
-/// it was registered in, such as auto trait obligations on
-/// `impl Trait`, which require the concrete type to be
-/// available, only guaranteed after finishing type-checking.
-#[derive(Clone, Debug)]
-pub struct DeferredObligation<'tcx> {
-    pub predicate: ty::PolyTraitPredicate<'tcx>,
-    pub cause: ObligationCause<'tcx>
-}
-
-impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> {
-    /// If possible, create a `DeferredObligation` from
-    /// a trait predicate which had failed selection,
-    /// but could succeed later.
-    pub fn from_select_error(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                             obligation: &TraitObligation<'tcx>,
-                             selection_err: &SelectionError<'tcx>)
-                             -> Option<DeferredObligation<'tcx>> {
-        if let Unimplemented = *selection_err {
-            if DeferredObligation::must_defer(tcx, &obligation.predicate) {
-                return Some(DeferredObligation {
-                    predicate: obligation.predicate.clone(),
-                    cause: obligation.cause.clone()
-                });
-            }
-        }
-
-        None
-    }
-
-    /// Returns true if the given trait predicate can be
-    /// fulfilled at a later time.
-    pub fn must_defer(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                      predicate: &ty::PolyTraitPredicate<'tcx>)
-                      -> bool {
-        // 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().count() == 1 && substs.regions().next().is_none() {
-                if let ty::TyAnon(..) = predicate.skip_binder().self_ty().sty {
-                    return true;
-                }
-            }
-        }
-
-        false
-    }
-
-    /// If possible, return the nested obligations required
-    /// to fulfill this obligation.
-    pub fn try_select(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
-                      -> Option<Vec<PredicateObligation<'tcx>>> {
-        if let ty::TyAnon(def_id, substs) = self.predicate.skip_binder().self_ty().sty {
-            let ty = if def_id.is_local() {
-                tcx.item_types.borrow().get(&def_id).cloned()
-            } else {
-                Some(tcx.item_type(def_id))
-            };
-            // We can resolve the `impl Trait` to its concrete type.
-            if let Some(concrete_ty) = ty.subst(tcx, substs) {
-                let predicate = ty::TraitRef {
-                    def_id: self.predicate.def_id(),
-                    substs: tcx.mk_substs_trait(concrete_ty, &[])
-                }.to_predicate();
-
-                let original_obligation = Obligation::new(self.cause.clone(),
-                                                          self.predicate.clone());
-                let cause = original_obligation.derived_cause(BuiltinDerivedObligation);
-                return Some(vec![Obligation::new(cause, predicate)]);
-            }
-        }
-
-        None
-    }
-
-    /// Return the `PredicateObligation` this was created from.
-    pub fn to_obligation(&self) -> PredicateObligation<'tcx> {
-        let predicate = ty::Predicate::Trait(self.predicate.clone());
-        Obligation::new(self.cause.clone(), predicate)
-    }
-
-    /// Return an error as if this obligation had failed.
-    pub fn to_error(&self) -> FulfillmentError<'tcx> {
-        FulfillmentError::new(self.to_obligation(), CodeSelectionError(Unimplemented))
-    }
-}
-
 impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
     /// Creates a new fulfillment context.
     pub fn new() -> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
             region_obligations: NodeMap(),
-            deferred_obligations: vec![],
         }
     }
 
@@ -294,16 +199,10 @@ pub fn select_all_or_error(&mut self,
     {
         self.select_where_possible(infcx)?;
 
-        // Fail all of the deferred obligations that haven't
-        // been otherwise removed from the context.
-        let deferred_errors = self.deferred_obligations.iter()
-                                  .map(|d| d.to_error());
-
         let errors: Vec<_> =
             self.predicates.to_errors(CodeAmbiguity)
                            .into_iter()
                            .map(|e| to_fulfillment_error(e))
-                           .chain(deferred_errors)
                            .collect();
         if errors.is_empty() {
             Ok(())
@@ -324,10 +223,6 @@ pub fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>> {
         self.predicates.pending_obligations()
     }
 
-    pub fn take_deferred_obligations(&mut self) -> Vec<DeferredObligation<'tcx>> {
-        mem::replace(&mut self.deferred_obligations, vec![])
-    }
-
     /// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it
     /// only attempts to select obligations that haven't been seen before.
     fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>)
@@ -343,7 +238,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,
-                deferred_obligations: &mut self.deferred_obligations
             });
             debug!("select: outcome={:?}", outcome);
 
@@ -378,7 +272,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>>>,
-    deferred_obligations: &'a mut Vec<DeferredObligation<'tcx>>
 }
 
 impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, 'tcx> {
@@ -391,8 +284,7 @@ fn process_obligation(&mut self,
     {
         process_predicate(self.selcx,
                           obligation,
-                          self.region_obligations,
-                          self.deferred_obligations)
+                          self.region_obligations)
             .map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation {
                 obligation: o,
                 stalled_on: vec![]
@@ -432,8 +324,7 @@ fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 't
 fn process_predicate<'a, 'gcx, 'tcx>(
     selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
     pending_obligation: &mut PendingPredicateObligation<'tcx>,
-    region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>,
-    deferred_obligations: &mut Vec<DeferredObligation<'tcx>>)
+    region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
     -> Result<Option<Vec<PredicateObligation<'tcx>>>,
               FulfillmentErrorCode<'tcx>>
 {
@@ -502,21 +393,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
                     info!("selecting trait `{:?}` at depth {} yielded Err",
                           data, obligation.recursion_depth);
 
-                    let defer = DeferredObligation::from_select_error(selcx.tcx(),
-                                                                      &trait_obligation,
-                                                                      &selection_err);
-                    if let Some(deferred_obligation) = defer {
-                        if let Some(nested) = deferred_obligation.try_select(selcx.tcx()) {
-                            Ok(Some(nested))
-                        } else {
-                            // Pretend that the obligation succeeded,
-                            // but record it for later.
-                            deferred_obligations.push(deferred_obligation);
-                            Ok(Some(vec![]))
-                        }
-                    } else {
-                        Err(CodeSelectionError(selection_err))
-                    }
+                    Err(CodeSelectionError(selection_err))
                 }
             }
         }
@@ -714,12 +591,6 @@ fn add_if_global(&mut self, tcx: TyCtxt<'a, 'gcx, 'tcx>, key: &ty::Predicate<'tc
             // already has the required read edges, so we don't need
             // to add any more edges here.
             if data.is_global() {
-                // Don't cache predicates which were fulfilled
-                // by deferring them for later fulfillment.
-                if DeferredObligation::must_defer(tcx, data) {
-                    return;
-                }
-
                 if let Some(data) = tcx.lift_to_global(data) {
                     if self.set.insert(data.clone()) {
                         debug!("add_if_global: global predicate `{:?}` added", data);
index 58ab713ef27308e220dd15cfe15ff5f6734dbf4f..7e7d06e4b814e681e025a1b33e5966582c7043c0 100644 (file)
@@ -31,7 +31,6 @@
 pub use self::coherence::overlapping_impls;
 pub use self::coherence::OrphanCheckErr;
 pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation};
-pub use self::fulfill::DeferredObligation;
 pub use self::project::MismatchedProjectionTypes;
 pub use self::project::{normalize, normalize_projection_type, Normalized};
 pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal};
@@ -474,7 +473,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
 
-    tcx.infer_ctxt(elaborated_env, Reveal::NotSpecializable).enter(|infcx| {
+    tcx.infer_ctxt(elaborated_env, Reveal::UserFacing).enter(|infcx| {
         let predicates = match fully_normalize(&infcx, cause,
                                                &infcx.parameter_environment.caller_bounds) {
             Ok(predicates) => predicates,
index 60808fbc741fb9898bde442a1f568641256b68d9..2ebe0d459fab1453451b02f4bc7fd208224ac76b 100644 (file)
@@ -23,6 +23,7 @@
 use traits;
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::subst::Substs;
+use std::borrow::Cow;
 use syntax::ast;
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -38,6 +39,25 @@ pub enum ObjectSafetyViolation {
     Method(ast::Name, MethodViolationCode),
 }
 
+impl ObjectSafetyViolation {
+    pub fn error_msg(&self) -> Cow<'static, str> {
+        match *self {
+            ObjectSafetyViolation::SizedSelf =>
+                "the trait cannot require that `Self : Sized`".into(),
+            ObjectSafetyViolation::SupertraitSelf =>
+                "the trait cannot use `Self` as a type parameter \
+                 in the supertrait listing".into(),
+            ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod) =>
+                format!("method `{}` has no receiver", name).into(),
+            ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf) =>
+                format!("method `{}` references the `Self` type \
+                         in its arguments or return type", name).into(),
+            ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
+                format!("method `{}` has generic type parameters", name).into(),
+        }
+    }
+}
+
 /// Reasons a method might not be object-safe.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub enum MethodViolationCode {
index 6f645b5f94d0084fe305f4e0ee69fe365733c91a..3d8f9e41c675b877e8fba6edf51f4155ceba7aed 100644 (file)
 /// more or less conservative.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum Reveal {
-    /// FIXME (#32205)
-    /// At coherence-checking time, we're still constructing the
-    /// specialization graph, and thus we only project
-    /// non-`default` associated types that are defined directly in
-    /// the applicable impl. (This behavior should be improved over
-    /// time, to allow for successful projections modulo cycles
-    /// between different impls).
-    ///
-    /// Here's an example that will fail due to the restriction:
-    ///
-    /// ```
-    /// trait Assoc {
-    ///     type Output;
-    /// }
-    ///
-    /// impl<T> Assoc for T {
-    ///     type Output = bool;
-    /// }
-    ///
-    /// impl Assoc for u8 {} // <- inherits the non-default type from above
-    ///
-    /// trait Foo {}
-    /// impl Foo for u32 {}
-    /// impl Foo for <u8 as Assoc>::Output {}  // <- this projection will fail
-    /// ```
-    ///
-    /// The projection would succeed if `Output` had been defined
-    /// directly in the impl for `u8`.
-    ExactMatch,
-
     /// At type-checking time, we refuse to project any associated
     /// type that is marked `default`. Non-`default` ("final") types
     /// are always projected. This is necessary in general for
@@ -90,7 +60,7 @@ pub enum Reveal {
     /// fn main() {
     ///     let <() as Assoc>::Output = true;
     /// }
-    NotSpecializable,
+    UserFacing,
 
     /// At trans time, all monomorphic projections will succeed.
     /// Also, `impl Trait` is normalized to the concrete type,
@@ -1208,7 +1178,8 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>(
     -> Progress<'tcx>
 {
     let closure_typer = selcx.closure_typer();
-    let closure_type = closure_typer.closure_type(vtable.closure_def_id, vtable.substs);
+    let closure_type = closure_typer.closure_type(vtable.closure_def_id)
+        .subst(selcx.tcx(), vtable.substs.substs);
     let Normalized {
         value: closure_type,
         obligations
@@ -1224,7 +1195,7 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>(
 
     confirm_callable_candidate(selcx,
                                obligation,
-                               &closure_type.sig,
+                               closure_type,
                                util::TupleArgumentsFlag::No)
         .with_addl_obligations(vtable.nested)
         .with_addl_obligations(obligations)
@@ -1233,7 +1204,7 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>(
 fn confirm_callable_candidate<'cx, 'gcx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    fn_sig: &ty::PolyFnSig<'tcx>,
+    fn_sig: ty::PolyFnSig<'tcx>,
     flag: util::TupleArgumentsFlag)
     -> Progress<'tcx>
 {
@@ -1346,8 +1317,9 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
     -> Option<specialization_graph::NodeItem<ty::AssociatedItem>>
 {
     let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id;
+    let trait_def = selcx.tcx().lookup_trait_def(trait_def_id);
 
-    if selcx.projection_mode() == Reveal::ExactMatch {
+    if !trait_def.is_complete(selcx.tcx()) {
         let impl_node = specialization_graph::Node::Impl(impl_def_id);
         for item in impl_node.items(selcx.tcx()) {
             if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name {
@@ -1359,7 +1331,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
         }
         None
     } else {
-        selcx.tcx().lookup_trait_def(trait_def_id)
+        trait_def
             .ancestors(impl_def_id)
             .defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type)
             .next()
index 40c62762c3cf3eab68a442ac242e0e59f8680331..4c4ace0d8baf9629d64a1cb7a0c805405e27d731 100644 (file)
@@ -1405,16 +1405,18 @@ fn assemble_fn_pointer_candidates(&mut self,
             }
 
             // provide an impl, but only for suitable `fn` pointers
-            ty::TyFnDef(.., &ty::BareFnTy {
+            ty::TyFnDef(.., ty::Binder(ty::FnSig {
                 unsafety: hir::Unsafety::Normal,
                 abi: Abi::Rust,
-                ref sig,
-            }) |
-            ty::TyFnPtr(&ty::BareFnTy {
+                variadic: false,
+                ..
+            })) |
+            ty::TyFnPtr(ty::Binder(ty::FnSig {
                 unsafety: hir::Unsafety::Normal,
                 abi: Abi::Rust,
-                ref sig
-            }) if !sig.variadic() => {
+                variadic: false,
+                ..
+            })) => {
                 candidates.vec.push(FnPointerCandidate);
             }
 
@@ -1476,8 +1478,7 @@ fn assemble_candidates_from_default_impls(&mut self,
                     // `assemble_candidates_from_object_ty`.
                 }
                 ty::TyParam(..) |
-                ty::TyProjection(..) |
-                ty::TyAnon(..) => {
+                ty::TyProjection(..) => {
                     // In these cases, we don't know what the actual
                     // type is.  Therefore, we cannot break it down
                     // into its constituent types. So we don't
@@ -1900,7 +1901,6 @@ fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> {
             ty::TyDynamic(..) |
             ty::TyParam(..) |
             ty::TyProjection(..) |
-            ty::TyAnon(..) |
             ty::TyInfer(ty::TyVar(_)) |
             ty::TyInfer(ty::FreshTy(_)) |
             ty::TyInfer(ty::FreshIntTy(_)) |
@@ -1945,6 +1945,13 @@ fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> {
                     .map(|f| f.ty(self.tcx(), substs))
                     .collect()
             }
+
+            ty::TyAnon(def_id, substs) => {
+                // We can resolve the `impl Trait` to its concrete type,
+                // which enforces a DAG between the functions requiring
+                // the auto trait bounds in question.
+                vec![self.tcx().item_type(def_id).subst(self.tcx(), substs)]
+            }
         }
     }
 
@@ -2777,11 +2784,12 @@ fn closure_trait_ref_unnormalized(&mut self,
                                       substs: ty::ClosureSubsts<'tcx>)
                                       -> ty::PolyTraitRef<'tcx>
     {
-        let closure_type = self.infcx.closure_type(closure_def_id, substs);
+        let closure_type = self.infcx.closure_type(closure_def_id)
+            .subst(self.tcx(), substs.substs);
         let ty::Binder((trait_ref, _)) =
             self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(),
                                                          obligation.predicate.0.self_ty(), // (1)
-                                                         &closure_type.sig,
+                                                         closure_type,
                                                          util::TupleArgumentsFlag::No);
         // (1) Feels icky to skip the binder here, but OTOH we know
         // that the self-type is an unboxed closure type and hence is
index 0fe054b30ba3174a1c1bfa3cbe6b6fbc0d1bc51f..79df7de04f540a9c955a0a942660c5336d3d41da 100644 (file)
@@ -189,7 +189,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              .subst(tcx, &penv.free_substs);
 
     // Create a infcx, taking the predicates of impl1 as assumptions:
-    let result = tcx.infer_ctxt(penv, Reveal::ExactMatch).enter(|infcx| {
+    let result = tcx.infer_ctxt(penv, Reveal::UserFacing).enter(|infcx| {
         // Normalize the trait reference. The WF rules ought to ensure
         // that this always succeeds.
         let impl1_trait_ref =
index 368b1fb4bcbd38ca4d61e0356fa993a2a19b860c..40eb69395678f2bd63d39a03d35b980e9d0524e9 100644 (file)
@@ -108,7 +108,7 @@ fn insert(&mut self,
             let possible_sibling = *slot;
 
             let tcx = tcx.global_tcx();
-            let (le, ge) = tcx.infer_ctxt((), Reveal::ExactMatch).enter(|infcx| {
+            let (le, ge) = tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
                 let overlap = traits::overlapping_impls(&infcx,
                                                         possible_sibling,
                                                         impl_def_id);
index dedb126d7ff6d6d40b5e304fa2385caed9fdf6b9..717c171db2ac7106a78ac11ff92dab42fbea2df1 100644 (file)
@@ -269,20 +269,6 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lif
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for traits::DeferredObligation<'a> {
-    type Lifted = traits::DeferredObligation<'tcx>;
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.predicate).and_then(|predicate| {
-            tcx.lift(&self.cause).map(|cause| {
-                traits::DeferredObligation {
-                    predicate: predicate,
-                    cause: cause
-                }
-            })
-        })
-    }
-}
-
 // For trans only.
 impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
     type Lifted = traits::Vtable<'tcx, ()>;
@@ -589,16 +575,3 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         self.code.visit_with(visitor)
     }
 }
-
-impl<'tcx> TypeFoldable<'tcx> for traits::DeferredObligation<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        traits::DeferredObligation {
-            predicate: self.predicate.fold_with(folder),
-            cause: self.cause.fold_with(folder)
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.predicate.visit_with(visitor) || self.cause.visit_with(visitor)
-    }
-}
index 7b2882bb64f2cb97a13825a6e66ae7eefcf0b877..602f27a64d4d8d195b14c2903e4cfe6b2ac06f78 100644 (file)
@@ -482,7 +482,7 @@ pub fn get_vtable_index_of_object_method<N>(self,
     pub fn closure_trait_ref_and_return_type(self,
         fn_trait_def_id: DefId,
         self_ty: Ty<'tcx>,
-        sig: &ty::PolyFnSig<'tcx>,
+        sig: ty::PolyFnSig<'tcx>,
         tuple_arguments: TupleArgumentsFlag)
         -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)>
     {
index 333a5c74cb45cb309c73e62317493ffed343530c..34977822bc69d8c8600105e7989ce5eed8e7c01f 100644 (file)
@@ -33,6 +33,9 @@ pub enum Adjust<'tcx> {
     /// Go from a safe fn pointer to an unsafe fn pointer.
     UnsafeFnPointer,
 
+    // Go from a non-capturing closure to an fn pointer.
+    ClosureFnPointer,
+
     /// Go from a mut raw pointer to a const raw pointer.
     MutToConstPointer,
 
@@ -120,6 +123,7 @@ pub fn is_identity(&self) -> bool {
 
             Adjust::ReifyFnPointer |
             Adjust::UnsafeFnPointer |
+            Adjust::ClosureFnPointer |
             Adjust::MutToConstPointer |
             Adjust::DerefRef {..} => false,
         }
index 56621c57eb8f7bed86f3b7c10f99b6fbd565acc1..e14295982916f44ad0578777db464581b6a4554d 100644 (file)
@@ -219,7 +219,7 @@ fn tc_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         res = res - TC::OwnsDtor;
                     }
 
-                    if def.has_dtor() {
+                    if def.has_dtor(tcx) {
                         res = res | TC::OwnsDtor;
                     }
 
index 19bb8a63aa277fe3879c6db734641707166b7d25..6961e0da362a5f7835ca0decce0e93c9c603fe9e 100644 (file)
@@ -10,7 +10,7 @@
 
 //! type context book-keeping
 
-use dep_graph::{DepGraph, DepTrackingMap};
+use dep_graph::DepGraph;
 use session::Session;
 use lint;
 use middle;
 use ty::{TyS, TypeVariants, Slice};
 use ty::{AdtKind, AdtDef, ClosureSubsts, Region};
 use hir::FreevarMap;
-use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
+use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
 use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
 use ty::TypeVariants::*;
 use ty::layout::{Layout, TargetDataLayout};
 use ty::inhabitedness::DefIdForest;
 use ty::maps;
-use util::common::MemoizationMap;
 use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
 use util::nodemap::{FxHashMap, FxHashSet};
 use rustc_data_structures::accumulate_vec::AccumulateVec;
 
 use arena::{TypedArena, DroplessArena};
+use rustc_data_structures::indexed_vec::IndexVec;
 use std::borrow::Borrow;
 use std::cell::{Cell, RefCell};
 use std::hash::{Hash, Hasher};
 use std::mem;
 use std::ops::Deref;
-use std::rc::Rc;
 use std::iter;
 use std::cmp::Ordering;
+use syntax::abi;
 use syntax::ast::{self, Name, NodeId};
 use syntax::attr;
 use syntax::symbol::{Symbol, keywords};
@@ -64,7 +64,7 @@ pub struct GlobalArenas<'tcx> {
     layout: TypedArena<Layout>,
 
     // references
-    generics: TypedArena<ty::Generics<'tcx>>,
+    generics: TypedArena<ty::Generics>,
     trait_def: TypedArena<ty::TraitDef>,
     adt_def: TypedArena<ty::AdtDef>,
     mir: TypedArena<RefCell<Mir<'tcx>>>,
@@ -93,7 +93,6 @@ pub struct CtxtInterners<'tcx> {
     type_: RefCell<FxHashSet<Interned<'tcx, TyS<'tcx>>>>,
     type_list: RefCell<FxHashSet<Interned<'tcx, Slice<Ty<'tcx>>>>>,
     substs: RefCell<FxHashSet<Interned<'tcx, Substs<'tcx>>>>,
-    bare_fn: RefCell<FxHashSet<Interned<'tcx, BareFnTy<'tcx>>>>,
     region: RefCell<FxHashSet<Interned<'tcx, Region>>>,
     existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>,
 }
@@ -105,7 +104,6 @@ fn new(arena: &'tcx DroplessArena) -> CtxtInterners<'tcx> {
             type_: RefCell::new(FxHashSet()),
             type_list: RefCell::new(FxHashSet()),
             substs: RefCell::new(FxHashSet()),
-            bare_fn: RefCell::new(FxHashSet()),
             region: RefCell::new(FxHashSet()),
             existential_predicates: RefCell::new(FxHashSet()),
         }
@@ -218,9 +216,9 @@ pub struct TypeckTables<'tcx> {
     pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
 
     /// Records the type of each closure.
-    pub closure_tys: NodeMap<ty::ClosureTy<'tcx>>,
+    pub closure_tys: NodeMap<ty::PolyFnSig<'tcx>>,
 
-    /// Records the type of each closure.
+    /// Records the kind of each closure.
     pub closure_kinds: NodeMap<ty::ClosureKind>,
 
     /// For each fn, records the "liberated" types of its arguments
@@ -242,6 +240,14 @@ pub struct TypeckTables<'tcx> {
 
     /// Lints for the body of this fn generated by typeck.
     pub lints: lint::LintTable,
+
+    /// Set of trait imports actually used in the method resolution.
+    /// This is used for warning unused imports.
+    pub used_trait_imports: DefIdSet,
+
+    /// If any errors occurred while type-checking this body,
+    /// this field will be set to `true`.
+    pub tainted_by_errors: bool,
 }
 
 impl<'tcx> TypeckTables<'tcx> {
@@ -259,6 +265,8 @@ pub fn empty() -> TypeckTables<'tcx> {
             fru_field_types: NodeMap(),
             cast_kinds: NodeMap(),
             lints: lint::LintTable::new(),
+            used_trait_imports: DefIdSet(),
+            tainted_by_errors: false,
         }
     }
 
@@ -389,6 +397,8 @@ pub struct GlobalCtxt<'tcx> {
     global_arenas: &'tcx GlobalArenas<'tcx>,
     global_interners: CtxtInterners<'tcx>,
 
+    pub sess: &'tcx Session,
+
     pub specializes_cache: RefCell<traits::SpecializesCache>,
 
     pub dep_graph: DepGraph,
@@ -396,8 +406,6 @@ pub struct GlobalCtxt<'tcx> {
     /// Common types, pre-interned for your convenience.
     pub types: CommonTypes<'tcx>,
 
-    pub sess: &'tcx Session,
-
     /// Map indicating what traits are in scope for places where this
     /// is relevant; generated by resolve.
     pub trait_map: TraitMap,
@@ -412,44 +420,9 @@ pub struct GlobalCtxt<'tcx> {
     // borrowck. (They are not used during trans, and hence are not
     // serialized or needed for cross-crate fns.)
     free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
-    // FIXME: jroesch make this a refcell
-
-    pub tables: RefCell<DepTrackingMap<maps::TypeckTables<'tcx>>>,
-
-    /// Maps from a trait item to the trait item "descriptor"
-    pub associated_items: RefCell<DepTrackingMap<maps::AssociatedItems<'tcx>>>,
-
-    /// Maps from an impl/trait def-id to a list of the def-ids of its items
-    pub associated_item_def_ids: RefCell<DepTrackingMap<maps::AssociatedItemDefIds<'tcx>>>,
-
-    pub impl_trait_refs: RefCell<DepTrackingMap<maps::ImplTraitRefs<'tcx>>>,
-    pub trait_defs: RefCell<DepTrackingMap<maps::TraitDefs<'tcx>>>,
-    pub adt_defs: RefCell<DepTrackingMap<maps::AdtDefs<'tcx>>>,
-    pub adt_sized_constraint: RefCell<DepTrackingMap<maps::AdtSizedConstraint<'tcx>>>,
-
-    /// Maps from the def-id of an item (trait/struct/enum/fn) to its
-    /// associated generics and predicates.
-    pub generics: RefCell<DepTrackingMap<maps::Generics<'tcx>>>,
-    pub predicates: RefCell<DepTrackingMap<maps::Predicates<'tcx>>>,
-
-    /// Maps from the def-id of a trait to the list of
-    /// super-predicates. This is a subset of the full list of
-    /// predicates. We store these in a separate map because we must
-    /// evaluate them even during type conversion, often before the
-    /// full predicates are available (note that supertraits have
-    /// additional acyclicity requirements).
-    pub super_predicates: RefCell<DepTrackingMap<maps::Predicates<'tcx>>>,
 
     pub hir: hir_map::Map<'tcx>,
-
-    /// Maps from the def-id of a function/method or const/static
-    /// to its MIR. Mutation is done at an item granularity to
-    /// allow MIR optimization passes to function and still
-    /// access cross-crate MIR (e.g. inlining or const eval).
-    ///
-    /// Note that cross-crate MIR appears to be always borrowed
-    /// (in the `RefCell` sense) to prevent accidental mutation.
-    pub mir_map: RefCell<DepTrackingMap<maps::Mir<'tcx>>>,
+    pub maps: maps::Maps<'tcx>,
 
     // Records the free variables refrenced by every closure
     // expression. Do not track deps for this, just recompute it from
@@ -458,18 +431,12 @@ pub struct GlobalCtxt<'tcx> {
 
     pub maybe_unused_trait_imports: NodeSet,
 
-    // Records the type of every item.
-    pub item_types: RefCell<DepTrackingMap<maps::Types<'tcx>>>,
-
     // Internal cache for metadata decoding. No need to track deps on this.
     pub rcache: RefCell<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
 
     // Cache for the type-contents routine. FIXME -- track deps?
     pub tc_cache: RefCell<FxHashMap<Ty<'tcx>, ty::contents::TypeContents>>,
 
-    // FIXME no dep tracking, but we should be able to remove this
-    pub ty_param_defs: RefCell<NodeMap<ty::TypeParameterDef<'tcx>>>,
-
     // FIXME dep tracking -- should be harmless enough
     pub normalized_cache: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
 
@@ -477,18 +444,9 @@ pub struct GlobalCtxt<'tcx> {
 
     pub lang_items: middle::lang_items::LanguageItems,
 
-    /// Maps from def-id of a type or region parameter to its
-    /// (inferred) variance.
-    pub item_variance_map: RefCell<DepTrackingMap<maps::ItemVariances<'tcx>>>,
-
     /// True if the variance has been computed yet; false otherwise.
     pub variance_computed: Cell<bool>,
 
-    /// Maps a DefId of a type to a list of its inherent impls.
-    /// Contains implementations of methods that are inherent to a type.
-    /// Methods in these implementations don't need to be exported.
-    pub inherent_impls: RefCell<DepTrackingMap<maps::InherentImpls<'tcx>>>,
-
     /// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
     /// present in this set can be warned about.
     pub used_unsafe: RefCell<NodeSet>,
@@ -498,10 +456,6 @@ pub struct GlobalCtxt<'tcx> {
     /// about.
     pub used_mut_nodes: RefCell<NodeSet>,
 
-    /// Set of trait imports actually used in the method resolution.
-    /// This is used for warning unused imports.
-    pub used_trait_imports: RefCell<DepTrackingMap<maps::UsedTraitImports<'tcx>>>,
-
     /// The set of external nominal types whose implementations have been read.
     /// This is used for lazy resolution of methods.
     pub populated_external_types: RefCell<DefIdSet>,
@@ -528,23 +482,9 @@ pub struct GlobalCtxt<'tcx> {
     /// (i.e., no type or lifetime parameters).
     pub fulfilled_predicates: RefCell<traits::GlobalFulfilledPredicates<'tcx>>,
 
-    /// Caches the representation hints for struct definitions.
-    repr_hint_cache: RefCell<DepTrackingMap<maps::ReprHints<'tcx>>>,
-
     /// Maps Expr NodeId's to `true` iff `&expr` can have 'static lifetime.
     pub rvalue_promotable_to_static: RefCell<NodeMap<bool>>,
 
-    /// Caches CoerceUnsized kinds for impls on custom types.
-    pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::adjustment::CustomCoerceUnsized>>,
-
-    /// Records the type of each closure. The def ID is the ID of the
-    /// expression defining the closure.
-    pub closure_tys: RefCell<DepTrackingMap<maps::ClosureTypes<'tcx>>>,
-
-    /// Records the type of each closure. The def ID is the ID of the
-    /// expression defining the closure.
-    pub closure_kinds: RefCell<DepTrackingMap<maps::ClosureKinds<'tcx>>>,
-
     /// Maps Fn items to a collection of fragment infos.
     ///
     /// The main goal is to identify data (each of which may be moved
@@ -592,6 +532,15 @@ pub struct GlobalCtxt<'tcx> {
     stability_interner: RefCell<FxHashSet<&'tcx attr::Stability>>,
 
     layout_interner: RefCell<FxHashSet<&'tcx Layout>>,
+
+    /// A vector of every trait accessible in the whole crate
+    /// (i.e. including those from subcrates). This is used only for
+    /// error reporting, and so is lazily initialised and generally
+    /// shouldn't taint the common path (hence the RefCell).
+    pub all_traits: RefCell<Option<Vec<DefId>>>,
+
+    /// HIR Ty -> Ty lowering cache.
+    pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
 }
 
 impl<'tcx> GlobalCtxt<'tcx> {
@@ -646,15 +595,7 @@ pub fn retrace_path(self,
         }
     }
 
-    pub fn type_parameter_def(self,
-                              node_id: NodeId)
-                              -> ty::TypeParameterDef<'tcx>
-    {
-        self.ty_param_defs.borrow().get(&node_id).unwrap().clone()
-    }
-
-    pub fn alloc_generics(self, generics: ty::Generics<'gcx>)
-                          -> &'gcx ty::Generics<'gcx> {
+    pub fn alloc_generics(self, generics: ty::Generics) -> &'gcx ty::Generics {
         self.global_arenas.generics.alloc(generics)
     }
 
@@ -673,12 +614,10 @@ pub fn alloc_trait_def(self, def: ty::TraitDef) -> &'gcx ty::TraitDef {
     pub fn alloc_adt_def(self,
                          did: DefId,
                          kind: AdtKind,
-                         discr_ty: Option<attr::IntType>,
                          variants: Vec<ty::VariantDef>,
                          repr: ReprOptions)
                          -> &'gcx ty::AdtDef {
-        let discr_ty = discr_ty.unwrap_or(attr::UnsignedInt(ast::UintTy::U8));
-        let def = ty::AdtDef::new(self, did, kind, discr_ty, variants, repr);
+        let def = ty::AdtDef::new(self, did, kind, variants, repr);
         self.global_arenas.adt_def.alloc(def)
     }
 
@@ -737,6 +676,8 @@ fn is_global(self) -> bool {
     /// value (types, substs, etc.) can only be used while `ty::tls` has a valid
     /// reference to the context, to allow formatting values that need it.
     pub fn create_and_enter<F, R>(s: &'tcx Session,
+                                  local_providers: ty::maps::Providers<'tcx>,
+                                  extern_providers: ty::maps::Providers<'tcx>,
                                   arenas: &'tcx GlobalArenas<'tcx>,
                                   arena: &'tcx DroplessArena,
                                   resolutions: ty::Resolutions,
@@ -754,7 +695,11 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
         let common_types = CommonTypes::new(&interners);
         let dep_graph = hir.dep_graph.clone();
         let fulfilled_predicates = traits::GlobalFulfilledPredicates::new(dep_graph.clone());
+        let max_cnum = s.cstore.crates().iter().map(|c| c.as_usize()).max().unwrap_or(0);
+        let mut providers = IndexVec::from_elem_n(extern_providers, max_cnum + 1);
+        providers[LOCAL_CRATE] = local_providers;
         tls::enter_global(GlobalCtxt {
+            sess: s,
             specializes_cache: RefCell::new(traits::SpecializesCache::new()),
             global_arenas: arenas,
             global_interners: interners,
@@ -763,46 +708,26 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
             named_region_map: named_region_map,
             region_maps: region_maps,
             free_region_maps: RefCell::new(FxHashMap()),
-            item_variance_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             variance_computed: Cell::new(false),
-            sess: s,
             trait_map: resolutions.trait_map,
-            tables: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            adt_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            adt_sized_constraint: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            generics: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            super_predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             fulfilled_predicates: RefCell::new(fulfilled_predicates),
             hir: hir,
-            mir_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
+            maps: maps::Maps::new(dep_graph, providers),
             freevars: RefCell::new(resolutions.freevars),
             maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports,
-            item_types: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             rcache: RefCell::new(FxHashMap()),
             tc_cache: RefCell::new(FxHashMap()),
-            associated_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            associated_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            ty_param_defs: RefCell::new(NodeMap()),
             normalized_cache: RefCell::new(FxHashMap()),
             inhabitedness_cache: RefCell::new(FxHashMap()),
             lang_items: lang_items,
-            inherent_impls: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             used_unsafe: RefCell::new(NodeSet()),
             used_mut_nodes: RefCell::new(NodeSet()),
-            used_trait_imports: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             populated_external_types: RefCell::new(DefIdSet()),
             populated_external_primitive_impls: RefCell::new(DefIdSet()),
             stability: RefCell::new(stability),
             selection_cache: traits::SelectionCache::new(),
             evaluation_cache: traits::EvaluationCache::new(),
-            repr_hint_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             rvalue_promotable_to_static: RefCell::new(NodeMap()),
-            custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
-            closure_tys: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            closure_kinds: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             fragment_infos: RefCell::new(DefIdMap()),
             crate_name: Symbol::intern(crate_name),
             data_layout: data_layout,
@@ -811,6 +736,8 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
             layout_depth: Cell::new(0),
             derive_macros: RefCell::new(NodeMap()),
             stability_interner: RefCell::new(FxHashSet()),
+            all_traits: RefCell::new(None),
+            ast_ty_to_ty_cache: RefCell::new(NodeMap()),
        }, f)
     }
 }
@@ -933,23 +860,6 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for &'a BareFnTy<'a> {
-    type Lifted = &'tcx BareFnTy<'tcx>;
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
-                             -> Option<&'tcx BareFnTy<'tcx>> {
-        if tcx.interners.arena.in_arena(*self as *const _) {
-            return Some(unsafe { mem::transmute(*self) });
-        }
-        // Also try in the global tcx if we're not that.
-        if !tcx.is_global() {
-            self.lift_to_tcx(tcx.global_tcx())
-        } else {
-            None
-        }
-    }
-}
-
-
 pub mod tls {
     use super::{CtxtInterners, GlobalCtxt, TyCtxt};
 
@@ -1102,7 +1012,6 @@ pub fn print_debug_stats(self) {
             TyDynamic, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
 
         println!("Substs interner: #{}", self.interners.substs.borrow().len());
-        println!("BareFnTy interner: #{}", self.interners.bare_fn.borrow().len());
         println!("Region interner: #{}", self.interners.region.borrow().len());
         println!("Stability interner: #{}", self.stability_interner.borrow().len());
         println!("Layout interner: #{}", self.layout_interner.borrow().len());
@@ -1161,12 +1070,6 @@ fn borrow<'a>(&'a self) -> &'a [Kind<'lcx>] {
     }
 }
 
-impl<'tcx: 'lcx, 'lcx> Borrow<BareFnTy<'lcx>> for Interned<'tcx, BareFnTy<'tcx>> {
-    fn borrow<'a>(&'a self) -> &'a BareFnTy<'lcx> {
-        self.0
-    }
-}
-
 impl<'tcx> Borrow<Region> for Interned<'tcx, Region> {
     fn borrow<'a>(&'a self) -> &'a Region {
         self.0
@@ -1255,9 +1158,6 @@ fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool {
 }
 
 direct_interners!('tcx,
-    bare_fn: mk_bare_fn(|fty: &BareFnTy| {
-        keep_local(&fty.sig)
-    }) -> BareFnTy<'tcx>,
     region: mk_region(|r| {
         match r {
             &ty::ReVar(_) | &ty::ReSkolemized(..) => true,
@@ -1283,12 +1183,11 @@ macro_rules! slice_interners {
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Create an unsafe fn ty based on a safe fn ty.
-    pub fn safe_to_unsafe_fn_ty(self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
-        assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal);
-        self.mk_fn_ptr(self.mk_bare_fn(ty::BareFnTy {
+    pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
+        assert_eq!(sig.unsafety(), hir::Unsafety::Normal);
+        self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig {
             unsafety: hir::Unsafety::Unsafe,
-            abi: bare_fn.abi,
-            sig: bare_fn.sig.clone()
+            ..sig
         }))
     }
 
@@ -1415,11 +1314,11 @@ pub fn mk_bool(self) -> Ty<'tcx> {
 
     pub fn mk_fn_def(self, def_id: DefId,
                      substs: &'tcx Substs<'tcx>,
-                     fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
+                     fty: PolyFnSig<'tcx>) -> Ty<'tcx> {
         self.mk_ty(TyFnDef(def_id, substs, fty))
     }
 
-    pub fn mk_fn_ptr(self, fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
+    pub fn mk_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> {
         self.mk_ty(TyFnPtr(fty))
     }
 
@@ -1513,14 +1412,19 @@ pub fn intern_substs(self, ts: &[Kind<'tcx>]) -> &'tcx Slice<Kind<'tcx>> {
         }
     }
 
-    pub fn mk_fn_sig<I>(self, inputs: I, output: I::Item, variadic: bool)
+    pub fn mk_fn_sig<I>(self,
+                        inputs: I,
+                        output: I::Item,
+                        variadic: bool,
+                        unsafety: hir::Unsafety,
+                        abi: abi::Abi)
         -> <I::Item as InternIteratorElement<Ty<'tcx>, ty::FnSig<'tcx>>>::Output
         where I: Iterator,
               I::Item: InternIteratorElement<Ty<'tcx>, ty::FnSig<'tcx>>
     {
         inputs.chain(iter::once(output)).intern_with(|xs| ty::FnSig {
             inputs_and_output: self.intern_type_list(xs),
-            variadic: variadic
+            variadic, unsafety, abi
         })
     }
 
@@ -1547,15 +1451,6 @@ pub fn mk_substs_trait(self,
     {
         self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from))
     }
-
-    /// Obtain the representation annotation for a struct definition.
-    pub fn lookup_repr_hints(self, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
-        self.repr_hint_cache.memoize(did, || {
-            Rc::new(self.get_attrs(did).iter().flat_map(|meta| {
-                attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter()
-            }).collect())
-        })
-    }
 }
 
 pub trait InternAs<T: ?Sized, R> {
index 3ab3fc899e78c6754305f18f307f6534c3cc5378..44a3aabc0560abe2f6efccc747c3cff9c6a3fd35 100644 (file)
@@ -10,7 +10,7 @@
 
 use hir::def_id::DefId;
 use infer::type_variable;
-use ty::{self, BoundRegion, Region, Ty, TyCtxt};
+use ty::{self, BoundRegion, DefIdTree, Region, Ty, TyCtxt};
 
 use std::fmt;
 use syntax::abi;
@@ -287,8 +287,9 @@ pub fn note_and_explain_type_err(self,
                         db.span_note(span, "a default was defined here...");
                     }
                     None => {
+                        let item_def_id = self.parent(expected.def_id).unwrap();
                         db.note(&format!("a default is defined on `{}`",
-                                         self.item_path_str(expected.def_id)));
+                                         self.item_path_str(item_def_id)));
                     }
                 }
 
@@ -301,8 +302,9 @@ pub fn note_and_explain_type_err(self,
                         db.span_note(span, "a second default was defined here...");
                     }
                     None => {
+                        let item_def_id = self.parent(found.def_id).unwrap();
                         db.note(&format!("a second default is defined on `{}`",
-                                         self.item_path_str(found.def_id)));
+                                         self.item_path_str(item_def_id)));
                     }
                 }
 
index 981cf0897a034f2f68e1d600bdaac3e4448bbe31..3d2cc4c598a22ea66677cc53010e271920c0c3e2 100644 (file)
@@ -76,7 +76,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
             Some(TupleSimplifiedType(tys.len()))
         }
         ty::TyFnDef(.., ref f) | ty::TyFnPtr(ref f) => {
-            Some(FunctionSimplifiedType(f.sig.skip_binder().inputs().len()))
+            Some(FunctionSimplifiedType(f.skip_binder().inputs().len()))
         }
         ty::TyProjection(_) | ty::TyParam(_) => {
             if can_simplify_params {
index 2012917f93a87e91669d74d8b61442ee97763e9f..384f99ceb4e83dff078b5201e7326417a86e4878 100644 (file)
@@ -155,13 +155,13 @@ fn add_sty(&mut self, st: &ty::TypeVariants) {
                 self.add_tys(&ts[..]);
             }
 
-            &ty::TyFnDef(_, substs, ref f) => {
+            &ty::TyFnDef(_, substs, f) => {
                 self.add_substs(substs);
-                self.add_fn_sig(&f.sig);
+                self.add_fn_sig(f);
             }
 
-            &ty::TyFnPtr(ref f) => {
-                self.add_fn_sig(&f.sig);
+            &ty::TyFnPtr(f) => {
+                self.add_fn_sig(f);
             }
         }
     }
@@ -177,7 +177,7 @@ fn add_tys(&mut self, tys: &[Ty]) {
         }
     }
 
-    fn add_fn_sig(&mut self, fn_sig: &ty::PolyFnSig) {
+    fn add_fn_sig(&mut self, fn_sig: ty::PolyFnSig) {
         let mut computation = FlagComputation::new();
 
         computation.add_tys(fn_sig.skip_binder().inputs());
index 10754825a8c1873c9b7100ea262ee5643daf09b7..e29653c9e88a03a7b81042850a40e41dd7886c45 100644 (file)
@@ -159,19 +159,6 @@ fn fold_fn_sig(&mut self,
         sig.super_fold_with(self)
     }
 
-    fn fold_bare_fn_ty(&mut self,
-                       fty: &'tcx ty::BareFnTy<'tcx>)
-                       -> &'tcx ty::BareFnTy<'tcx>
-    {
-        fty.super_fold_with(self)
-    }
-
-    fn fold_closure_ty(&mut self,
-                       fty: &ty::ClosureTy<'tcx>)
-                       -> ty::ClosureTy<'tcx> {
-        fty.super_fold_with(self)
-    }
-
     fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
         r.super_fold_with(self)
     }
index 24ca476e5ff7994a36311f123cec3cace45b164a..77c863a012318ca161a1ebbdf6f46a6a6839a3e0 100644 (file)
@@ -187,7 +187,7 @@ fn uninhabited_from_inner(
                         //      which contains a Foo<((T, T), (T, T))>
                         //      which contains a Foo<(((T, T), (T, T)), ((T, T), (T, T)))>
                         //      etc.
-                        let error = format!("reached recursion limit while checking
+                        let error = format!("reached recursion limit while checking \
                                              inhabitedness of `{}`", self);
                         tcx.sess.fatal(&error);
                     }
index f45f00b4dec96bbf20590469c44687b98858a625..7bf1ba155b53511964c7e95edfc2e755e190a1e3 100644 (file)
@@ -201,7 +201,7 @@ fn push_impl_path<T>(self,
         } else {
             // for local crates, check whether type info is
             // available; typeck might not have completed yet
-            self.impl_trait_refs.borrow().contains_key(&impl_def_id)
+            self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id)
         };
 
         if !use_types {
index f429053d8bb1223a782cddd013c95b8bb766baef..123db6e89476c52c0418ad4c3db34cdd8839da8d 100644 (file)
@@ -1146,7 +1146,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
             }
 
             // SIMD vector types.
-            ty::TyAdt(def, ..) if def.is_simd() => {
+            ty::TyAdt(def, ..) if def.repr.simd => {
                 let element = ty.simd_type(tcx);
                 match *element.layout(infcx)? {
                     Scalar { value, .. } => {
@@ -1181,8 +1181,8 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                     let (mut min, mut max, mut non_zero) = (i64::max_value(),
                                                             i64::min_value(),
                                                             true);
-                    for v in &def.variants {
-                        let x = v.disr_val as i128 as i64;
+                    for discr in def.discriminants(tcx) {
+                        let x = discr.to_u128_unchecked() as i64;
                         if x == 0 { non_zero = false; }
                         if x < min { min = x; }
                         if x > max { max = x; }
@@ -1201,7 +1201,8 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                     });
                 }
 
-                if !def.is_enum() || def.variants.len() == 1 {
+                if !def.is_enum() || (def.variants.len() == 1 &&
+                                      !def.repr.inhibit_enum_layout_opt()) {
                     // Struct, or union, or univariant enum equivalent to a struct.
                     // (Typechecking will reject discriminant-sizing attrs.)
 
@@ -1222,9 +1223,8 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                     let fields = def.variants[0].fields.iter().map(|field| {
                         field.ty(tcx, substs).layout(infcx)
                     }).collect::<Result<Vec<_>, _>>()?;
-                    let packed = tcx.lookup_packed(def.did);
                     let layout = if def.is_union() {
-                        let mut un = Union::new(dl, packed);
+                        let mut un = Union::new(dl, def.repr.packed);
                         un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?;
                         UntaggedUnion { variants: un }
                     } else {
@@ -1240,7 +1240,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                 // non-empty body, explicit discriminants should have
                 // been rejected by a checker before this point.
                 for (i, v) in def.variants.iter().enumerate() {
-                    if i as u128 != v.disr_val {
+                    if v.discr != ty::VariantDiscr::Relative(i) {
                         bug!("non-C-like enum {} with specified discriminants",
                             tcx.item_path_str(def.did));
                     }
@@ -1251,7 +1251,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                     v.fields.iter().map(|field| field.ty(tcx, substs)).collect::<Vec<_>>()
                 }).collect::<Vec<_>>();
 
-                if variants.len() == 2 && !def.repr.c {
+                if variants.len() == 2 && !def.repr.inhibit_enum_layout_opt() {
                     // Nullable pointer optimization
                     for discr in 0..2 {
                         let other_fields = variants[1 - discr].iter().map(|ty| {
@@ -1348,7 +1348,7 @@ pub fn compute_uncached(ty: Ty<'gcx>,
                     return Err(LayoutError::SizeOverflow(ty));
                 }
 
-                let typeck_ity = Integer::from_attr(dl, def.discr_ty);
+                let typeck_ity = Integer::from_attr(dl, def.repr.discr_type());
                 if typeck_ity < min_ity {
                     // It is a bug if Layout decided on a greater discriminant size than typeck for
                     // some reason at this point (based on values discriminant can take on). Mostly
index d7341d148b720636a865cadd0f0399f8f7d189cd..fd1403b15bc892fb4414aec38e9891dae1080d5c 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use dep_graph::{DepNode, DepTrackingMapConfig};
-use hir::def_id::DefId;
+use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig};
+use hir::def_id::{CrateNum, DefId};
+use middle::const_val::ConstVal;
 use mir;
-use ty::{self, Ty};
-use util::nodemap::DefIdSet;
+use ty::{self, Ty, TyCtxt};
 
-use std::cell::RefCell;
-use std::marker::PhantomData;
+use rustc_data_structures::indexed_vec::IndexVec;
+use std::cell::{RefCell, RefMut};
 use std::rc::Rc;
-use syntax::attr;
-
-macro_rules! dep_map_ty {
-    ($ty_name:ident : $node_name:ident ($key:ty) -> $value:ty) => {
-        pub struct $ty_name<'tcx> {
-            data: PhantomData<&'tcx ()>
-        }
-
-        impl<'tcx> DepTrackingMapConfig for $ty_name<'tcx> {
-            type Key = $key;
-            type Value = $value;
-            fn to_dep_node(key: &$key) -> DepNode<DefId> { DepNode::$node_name(*key) }
-        }
-    }
-}
-
-dep_map_ty! { AssociatedItems: AssociatedItems(DefId) -> ty::AssociatedItem }
-dep_map_ty! { Types: ItemSignature(DefId) -> Ty<'tcx> }
-dep_map_ty! { Generics: ItemSignature(DefId) -> &'tcx ty::Generics<'tcx> }
-dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> }
-dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> }
-dep_map_ty! { AssociatedItemDefIds: AssociatedItemDefIds(DefId) -> Rc<Vec<DefId>> }
-dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>> }
-dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef }
-dep_map_ty! { AdtDefs: ItemSignature(DefId) -> &'tcx ty::AdtDef }
-dep_map_ty! { AdtSizedConstraint: SizedConstraint(DefId) -> Ty<'tcx> }
-dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc<Vec<ty::Variance>> }
-dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Vec<DefId> }
-dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc<Vec<attr::ReprAttr>> }
-dep_map_ty! { Mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>> }
-dep_map_ty! { ClosureKinds: ItemSignature(DefId) -> ty::ClosureKind }
-dep_map_ty! { ClosureTypes: ItemSignature(DefId) -> ty::ClosureTy<'tcx> }
-dep_map_ty! { TypeckTables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx> }
-dep_map_ty! { UsedTraitImports: UsedTraitImports(DefId) -> DefIdSet }
+use syntax_pos::{Span, DUMMY_SP};
+
+trait Key {
+    fn map_crate(&self) -> CrateNum;
+    fn default_span(&self, tcx: TyCtxt) -> Span;
+}
+
+impl Key for CrateNum {
+    fn map_crate(&self) -> CrateNum {
+        *self
+    }
+    fn default_span(&self, _: TyCtxt) -> Span {
+        DUMMY_SP
+    }
+}
+
+impl Key for DefId {
+    fn map_crate(&self) -> CrateNum {
+        self.krate
+    }
+    fn default_span(&self, tcx: TyCtxt) -> Span {
+        tcx.def_span(*self)
+    }
+}
+
+impl Key for (DefId, DefId) {
+    fn map_crate(&self) -> CrateNum {
+        self.0.krate
+    }
+    fn default_span(&self, tcx: TyCtxt) -> Span {
+        self.1.default_span(tcx)
+    }
+}
+
+impl Key for (CrateNum, DefId) {
+    fn map_crate(&self) -> CrateNum {
+        self.0
+    }
+    fn default_span(&self, tcx: TyCtxt) -> Span {
+        self.1.default_span(tcx)
+    }
+}
+
+trait Value<'tcx>: Sized {
+    fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
+}
+
+impl<'tcx, T> Value<'tcx> for T {
+    default fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> T {
+        tcx.sess.abort_if_errors();
+        bug!("Value::from_cycle_error called without errors");
+    }
+}
+
+impl<'tcx, T: Default> Value<'tcx> for T {
+    default fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> T {
+        T::default()
+    }
+}
+
+impl<'tcx> Value<'tcx> for Ty<'tcx> {
+    fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
+        tcx.types.err
+    }
+}
+
+pub struct CycleError<'a> {
+    span: Span,
+    cycle: RefMut<'a, [(Span, Query)]>
+}
+
+impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
+    pub fn report_cycle(self, CycleError { span, cycle }: CycleError) {
+        assert!(!cycle.is_empty());
+
+        let mut err = struct_span_err!(self.sess, span, E0391,
+            "unsupported cyclic reference between types/traits detected");
+        err.span_label(span, &format!("cyclic reference"));
+
+        err.span_note(cycle[0].0, &format!("the cycle begins when {}...",
+                                           cycle[0].1.describe(self)));
+
+        for &(span, ref query) in &cycle[1..] {
+            err.span_note(span, &format!("...which then requires {}...",
+                                         query.describe(self)));
+        }
+
+        err.note(&format!("...which then again requires {}, completing the cycle.",
+                          cycle[0].1.describe(self)));
+
+        err.emit();
+    }
+
+    fn cycle_check<F, R>(self, span: Span, query: Query, compute: F)
+                         -> Result<R, CycleError<'a>>
+        where F: FnOnce() -> R
+    {
+        {
+            let mut stack = self.maps.query_stack.borrow_mut();
+            if let Some((i, _)) = stack.iter().enumerate().rev()
+                                       .find(|&(_, &(_, ref q))| *q == query) {
+                return Err(CycleError {
+                    span: span,
+                    cycle: RefMut::map(stack, |stack| &mut stack[i..])
+                });
+            }
+            stack.push((span, query));
+        }
+
+        let result = compute();
+
+        self.maps.query_stack.borrow_mut().pop();
+
+        Ok(result)
+    }
+}
+
+trait QueryDescription: DepTrackingMapConfig {
+    fn describe(tcx: TyCtxt, key: Self::Key) -> String;
+}
+
+impl<M: DepTrackingMapConfig<Key=DefId>> QueryDescription for M {
+    default fn describe(tcx: TyCtxt, def_id: DefId) -> String {
+        format!("processing `{}`", tcx.item_path_str(def_id))
+    }
+}
+
+impl<'tcx> QueryDescription for queries::super_predicates<'tcx> {
+    fn describe(tcx: TyCtxt, def_id: DefId) -> String {
+        format!("computing the supertraits of `{}`",
+                tcx.item_path_str(def_id))
+    }
+}
+
+impl<'tcx> QueryDescription for queries::type_param_predicates<'tcx> {
+    fn describe(tcx: TyCtxt, (_, def_id): (DefId, DefId)) -> String {
+        let id = tcx.hir.as_local_node_id(def_id).unwrap();
+        format!("computing the bounds for type parameter `{}`",
+                tcx.hir.ty_param_name(id))
+    }
+}
+
+impl<'tcx> QueryDescription for queries::coherent_trait<'tcx> {
+    fn describe(tcx: TyCtxt, (_, def_id): (CrateNum, DefId)) -> String {
+        format!("coherence checking all impls of trait `{}`",
+                tcx.item_path_str(def_id))
+    }
+}
+
+impl<'tcx> QueryDescription for queries::coherent_inherent_impls<'tcx> {
+    fn describe(_: TyCtxt, _: CrateNum) -> String {
+        format!("coherence checking all inherent impls")
+    }
+}
+
+macro_rules! define_maps {
+    (<$tcx:tt>
+     $($(#[$attr:meta])*
+       pub $name:ident: $node:ident($K:ty) -> $V:ty),*) => {
+        pub struct Maps<$tcx> {
+            providers: IndexVec<CrateNum, Providers<$tcx>>,
+            query_stack: RefCell<Vec<(Span, Query)>>,
+            $($(#[$attr])* pub $name: RefCell<DepTrackingMap<queries::$name<$tcx>>>),*
+        }
+
+        impl<$tcx> Maps<$tcx> {
+            pub fn new(dep_graph: DepGraph,
+                       providers: IndexVec<CrateNum, Providers<$tcx>>)
+                       -> Self {
+                Maps {
+                    providers,
+                    query_stack: RefCell::new(vec![]),
+                    $($name: RefCell::new(DepTrackingMap::new(dep_graph.clone()))),*
+                }
+            }
+        }
+
+        #[allow(bad_style)]
+        #[derive(Copy, Clone, Debug, PartialEq, Eq)]
+        pub enum Query {
+            $($(#[$attr])* $name($K)),*
+        }
+
+        impl Query {
+            pub fn describe(&self, tcx: TyCtxt) -> String {
+                match *self {
+                    $(Query::$name(key) => queries::$name::describe(tcx, key)),*
+                }
+            }
+        }
+
+        pub mod queries {
+            use std::marker::PhantomData;
+
+            $(#[allow(bad_style)]
+            pub struct $name<$tcx> {
+                data: PhantomData<&$tcx ()>
+            })*
+        }
+
+        $(impl<$tcx> DepTrackingMapConfig for queries::$name<$tcx> {
+            type Key = $K;
+            type Value = $V;
+
+            #[allow(unused)]
+            fn to_dep_node(key: &$K) -> DepNode<DefId> {
+                use dep_graph::DepNode::*;
+
+                $node(*key)
+            }
+        }
+        impl<'a, $tcx, 'lcx> queries::$name<$tcx> {
+            fn try_get_with<F, R>(tcx: TyCtxt<'a, $tcx, 'lcx>,
+                                  mut span: Span,
+                                  key: $K,
+                                  f: F)
+                                  -> Result<R, CycleError<'a>>
+                where F: FnOnce(&$V) -> R
+            {
+                if let Some(result) = tcx.maps.$name.borrow().get(&key) {
+                    return Ok(f(result));
+                }
+
+                // FIXME(eddyb) Get more valid Span's on queries.
+                if span == DUMMY_SP {
+                    span = key.default_span(tcx);
+                }
+
+                let _task = tcx.dep_graph.in_task(Self::to_dep_node(&key));
+
+                let result = tcx.cycle_check(span, Query::$name(key), || {
+                    let provider = tcx.maps.providers[key.map_crate()].$name;
+                    provider(tcx.global_tcx(), key)
+                })?;
+
+                Ok(f(&tcx.maps.$name.borrow_mut().entry(key).or_insert(result)))
+            }
+
+            pub fn try_get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K)
+                           -> Result<$V, CycleError<'a>> {
+                Self::try_get_with(tcx, span, key, Clone::clone)
+            }
+
+            $(#[$attr])*
+            pub fn get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) -> $V {
+                Self::try_get(tcx, span, key).unwrap_or_else(|e| {
+                    tcx.report_cycle(e);
+                    Value::from_cycle_error(tcx.global_tcx())
+                })
+            }
+
+            pub fn force(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) {
+                // FIXME(eddyb) Move away from using `DepTrackingMap`
+                // so we don't have to explicitly ignore a false edge:
+                // we can't observe a value dependency, only side-effects,
+                // through `force`, and once everything has been updated,
+                // perhaps only diagnostics, if those, will remain.
+                let _ignore = tcx.dep_graph.in_ignore();
+                match Self::try_get_with(tcx, span, key, |_| ()) {
+                    Ok(()) => {}
+                    Err(e) => tcx.report_cycle(e)
+                }
+            }
+        })*
+
+        pub struct Providers<$tcx> {
+            $(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $V),*
+        }
+
+        impl<$tcx> Copy for Providers<$tcx> {}
+        impl<$tcx> Clone for Providers<$tcx> {
+            fn clone(&self) -> Self { *self }
+        }
+
+        impl<$tcx> Default for Providers<$tcx> {
+            fn default() -> Self {
+                $(fn $name<'a, $tcx>(_: TyCtxt<'a, $tcx, $tcx>, key: $K) -> $V {
+                    bug!("tcx.maps.{}({:?}) unsupported by its crate",
+                         stringify!($name), key);
+                })*
+                Providers { $($name),* }
+            }
+        }
+    }
+}
+
+// Each of these maps also corresponds to a method on a
+// `Provider` trait for requesting a value of that type,
+// and a method on `Maps` itself for doing that in a
+// a way that memoizes and does dep-graph tracking,
+// wrapping around the actual chain of providers that
+// the driver creates (using several `rustc_*` crates).
+define_maps! { <'tcx>
+    /// Records the type of every item.
+    pub ty: ItemSignature(DefId) -> Ty<'tcx>,
+
+    /// Maps from the def-id of an item (trait/struct/enum/fn) to its
+    /// associated generics and predicates.
+    pub generics: ItemSignature(DefId) -> &'tcx ty::Generics,
+    pub predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>,
+
+    /// Maps from the def-id of a trait to the list of
+    /// super-predicates. This is a subset of the full list of
+    /// predicates. We store these in a separate map because we must
+    /// evaluate them even during type conversion, often before the
+    /// full predicates are available (note that supertraits have
+    /// additional acyclicity requirements).
+    pub super_predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>,
+
+    /// To avoid cycles within the predicates of a single item we compute
+    /// per-type-parameter predicates for resolving `T::AssocTy`.
+    pub type_param_predicates: TypeParamPredicates((DefId, DefId))
+        -> ty::GenericPredicates<'tcx>,
+
+    pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef,
+    pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef,
+    pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>,
+
+    /// Maps from def-id of a type or region parameter to its
+    /// (inferred) variance.
+    pub variances: ItemSignature(DefId) -> Rc<Vec<ty::Variance>>,
+
+    /// Maps from an impl/trait def-id to a list of the def-ids of its items
+    pub associated_item_def_ids: AssociatedItemDefIds(DefId) -> Rc<Vec<DefId>>,
+
+    /// Maps from a trait item to the trait item "descriptor"
+    pub associated_item: AssociatedItems(DefId) -> ty::AssociatedItem,
+
+    pub impl_trait_ref: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>>,
+
+    /// Maps a DefId of a type to a list of its inherent impls.
+    /// Contains implementations of methods that are inherent to a type.
+    /// Methods in these implementations don't need to be exported.
+    pub inherent_impls: InherentImpls(DefId) -> Vec<DefId>,
+
+    /// Maps from the def-id of a function/method or const/static
+    /// to its MIR. Mutation is done at an item granularity to
+    /// allow MIR optimization passes to function and still
+    /// access cross-crate MIR (e.g. inlining or const eval).
+    ///
+    /// Note that cross-crate MIR appears to be always borrowed
+    /// (in the `RefCell` sense) to prevent accidental mutation.
+    pub mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>>,
+
+    /// Maps DefId's that have an associated Mir to the result
+    /// of the MIR qualify_consts pass. The actual meaning of
+    /// the value isn't known except to the pass itself.
+    pub mir_const_qualif: Mir(DefId) -> u8,
+
+    /// Records the type of each closure. The def ID is the ID of the
+    /// expression defining the closure.
+    pub closure_kind: ItemSignature(DefId) -> ty::ClosureKind,
+
+    /// Records the type of each closure. The def ID is the ID of the
+    /// expression defining the closure.
+    pub closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>,
+
+    /// Caches CoerceUnsized kinds for impls on custom types.
+    pub custom_coerce_unsized_kind: ItemSignature(DefId)
+        -> ty::adjustment::CustomCoerceUnsized,
+
+    pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>,
+
+    pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (),
+
+    pub coherent_inherent_impls: coherent_inherent_impls_dep_node(CrateNum) -> (),
+
+    /// Results of evaluating monomorphic constants embedded in
+    /// other items, such as enum variant explicit discriminants.
+    pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal<'tcx>, ()>
+}
+
+fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
+    DepNode::CoherenceCheckTrait(def_id)
+}
+
+fn coherent_inherent_impls_dep_node(_: CrateNum) -> DepNode<DefId> {
+    DepNode::Coherence
+}
index 7937d2ccfe46da45d4c6e5d5524a6599986a7590..8cf8a839afbffaca5e62c42c532be118a1168509 100644 (file)
 use hir::{map as hir_map, FreevarMap, TraitMap};
 use middle;
 use hir::def::{Def, CtorKind, ExportMap};
-use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use middle::const_val::ConstVal;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::region::{CodeExtent, ROOT_CODE_EXTENT};
+use middle::resolve_lifetime::ObjectLifetimeDefault;
 use mir::Mir;
 use traits;
 use ty;
 use ty::subst::{Subst, Substs};
+use ty::util::IntTypeExt;
 use ty::walk::TypeWalker;
 use util::common::MemoizationMap;
-use util::nodemap::{NodeSet, NodeMap, FxHashMap};
+use util::nodemap::{NodeSet, FxHashMap};
 
 use serialize::{self, Encodable, Encoder};
 use std::borrow::Cow;
 use std::cell::{Cell, RefCell, Ref};
+use std::collections::BTreeMap;
 use std::hash::{Hash, Hasher};
 use std::ops::Deref;
 use std::rc::Rc;
@@ -43,6 +47,7 @@
 use syntax::attr;
 use syntax::symbol::{Symbol, InternedString};
 use syntax_pos::{DUMMY_SP, Span};
+use rustc_const_math::ConstInt;
 
 use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
 
@@ -50,8 +55,8 @@
 use hir::itemlikevisit::ItemLikeVisitor;
 
 pub use self::sty::{Binder, DebruijnIndex};
-pub use self::sty::{BareFnTy, FnSig, PolyFnSig};
-pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
+pub use self::sty::{FnSig, PolyFnSig};
+pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
 pub use self::sty::{ClosureSubsts, TypeAndMut};
 pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef};
 pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
@@ -70,6 +75,8 @@
 
 pub use self::trait_def::{TraitDef, TraitFlags};
 
+pub use self::maps::queries;
+
 pub mod adjustment;
 pub mod cast;
 pub mod error;
 mod structural_impls;
 mod sty;
 
-pub type Disr = u128;
-
 // Data types
 
 /// The complete set of all analyses described in this module. This is
 /// produced by the driver and fed to trans and later passes.
 #[derive(Clone)]
-pub struct CrateAnalysis<'tcx> {
+pub struct CrateAnalysis {
     pub export_map: ExportMap,
     pub access_levels: middle::privacy::AccessLevels,
     pub reachable: NodeSet,
     pub name: String,
     pub glob_map: Option<hir::GlobMap>,
-    pub hir_ty_to_ty: NodeMap<Ty<'tcx>>,
 }
 
 #[derive(Clone)]
@@ -585,13 +589,13 @@ pub enum IntVarValue {
     UintType(ast::UintTy),
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable)]
-pub struct TypeParameterDef<'tcx> {
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
+pub struct TypeParameterDef {
     pub name: Name,
     pub def_id: DefId,
     pub index: u32,
-    pub default_def_id: DefId, // for use in error reporing about defaults
-    pub default: Option<Ty<'tcx>>,
+    pub has_default: bool,
+    pub object_lifetime_default: ObjectLifetimeDefault,
 
     /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
     /// on generic parameter `T`, asserts data behind the parameter
@@ -628,16 +632,21 @@ pub fn to_bound_region(&self) -> ty::BoundRegion {
 /// Information about the formal type/lifetime parameters associated
 /// with an item or method. Analogous to hir::Generics.
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
-pub struct Generics<'tcx> {
+pub struct Generics {
     pub parent: Option<DefId>,
     pub parent_regions: u32,
     pub parent_types: u32,
     pub regions: Vec<RegionParameterDef>,
-    pub types: Vec<TypeParameterDef<'tcx>>,
+    pub types: Vec<TypeParameterDef>,
+
+    /// Reverse map to each `TypeParameterDef`'s `index` field, from
+    /// `def_id.index` (`def_id.krate` is the same as the item's).
+    pub type_param_to_index: BTreeMap<DefIndex, u32>,
+
     pub has_self: bool,
 }
 
-impl<'tcx> Generics<'tcx> {
+impl Generics {
     pub fn parent_count(&self) -> usize {
         self.parent_regions as usize + self.parent_types as usize
     }
@@ -651,16 +660,18 @@ pub fn count(&self) -> usize {
     }
 
     pub fn region_param(&self, param: &EarlyBoundRegion) -> &RegionParameterDef {
+        assert_eq!(self.parent_count(), 0);
         &self.regions[param.index as usize - self.has_self as usize]
     }
 
-    pub fn type_param(&self, param: &ParamTy) -> &TypeParameterDef<'tcx> {
+    pub fn type_param(&self, param: &ParamTy) -> &TypeParameterDef {
+        assert_eq!(self.parent_count(), 0);
         &self.types[param.idx as usize - self.has_self as usize - self.regions.len()]
     }
 }
 
 /// Bounds on generics.
-#[derive(Clone)]
+#[derive(Clone, Default)]
 pub struct GenericPredicates<'tcx> {
     pub parent: Option<DefId>,
     pub predicates: Vec<Predicate<'tcx>>,
@@ -1086,24 +1097,6 @@ pub fn is_empty(&self) -> bool {
     }
 }
 
-impl<'tcx> TraitRef<'tcx> {
-    pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> TraitRef<'tcx> {
-        TraitRef { def_id: def_id, substs: substs }
-    }
-
-    pub fn self_ty(&self) -> Ty<'tcx> {
-        self.substs.type_at(0)
-    }
-
-    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()
-    }
-}
-
 /// When type checking, we use the `ParameterEnvironment` to track
 /// details about the type/lifetime parameters that are in scope.
 /// It primarily stores the bounds information.
@@ -1287,10 +1280,10 @@ pub fn for_item(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId)
         const IS_DTORCK           = 1 << 1, // is this a dtorck type?
         const IS_DTORCK_VALID     = 1 << 2,
         const IS_PHANTOM_DATA     = 1 << 3,
-        const IS_SIMD             = 1 << 4,
-        const IS_FUNDAMENTAL      = 1 << 5,
-        const IS_UNION            = 1 << 6,
-        const IS_BOX              = 1 << 7,
+        const IS_FUNDAMENTAL      = 1 << 4,
+        const IS_UNION            = 1 << 5,
+        const IS_BOX              = 1 << 6,
+        const IS_DTOR_VALID       = 1 << 7,
     }
 }
 
@@ -1300,11 +1293,24 @@ pub struct VariantDef {
     /// this is the DefId of the struct's ctor.
     pub did: DefId,
     pub name: Name, // struct's name if this is a struct
-    pub disr_val: Disr,
+    pub discr: VariantDiscr,
     pub fields: Vec<FieldDef>,
     pub ctor_kind: CtorKind,
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
+pub enum VariantDiscr {
+    /// Explicit value for this variant, i.e. `X = 123`.
+    /// The `DefId` corresponds to the embedded constant.
+    Explicit(DefId),
+
+    /// The previous variant's discriminant plus one.
+    /// For efficiency reasons, the distance from the
+    /// last `Explicit` discriminant is being stored,
+    /// or `0` for the first variant, if it has none.
+    Relative(usize),
+}
+
 #[derive(Debug)]
 pub struct FieldDef {
     pub did: DefId,
@@ -1318,12 +1324,6 @@ pub struct FieldDef {
 /// table.
 pub struct AdtDef {
     pub did: DefId,
-    /// Type of the discriminant
-    ///
-    /// Note, that this is the type specified in `repr()` or a default type of some sort, and might
-    /// not match the actual type that layout algorithm decides to use when translating this type
-    /// into LLVM. That being said, layout algorithm may not use a type larger than specified here.
-    pub discr_ty: attr::IntType,
     pub variants: Vec<VariantDef>,
     destructor: Cell<Option<DefId>>,
     flags: Cell<AdtFlags>,
@@ -1366,27 +1366,44 @@ pub struct ReprOptions {
 }
 
 impl ReprOptions {
-    pub fn new<'a, 'gcx, 'tcx>(tcx: &TyCtxt<'a, 'gcx, 'tcx>, did: DefId) -> ReprOptions {
+    pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
         let mut ret = ReprOptions::default();
-        let attrs = tcx.lookup_repr_hints(did);
-        for r in attrs.iter() {
-            match *r {
-                attr::ReprExtern => ret.c = true,
-                attr::ReprPacked => ret.packed = true,
-                attr::ReprSimd => ret.simd = true,
-                attr::ReprInt(i) => ret.int = Some(i),
-                attr::ReprAny => (),
+
+        for attr in tcx.get_attrs(did).iter() {
+            for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) {
+                match r {
+                    attr::ReprExtern => ret.c = true,
+                    attr::ReprPacked => ret.packed = true,
+                    attr::ReprSimd => ret.simd = true,
+                    attr::ReprInt(i) => ret.int = Some(i),
+                }
             }
         }
+
+        // FIXME(eddyb) This is deprecated and should be removed.
+        if tcx.has_attr(did, "simd") {
+            ret.simd = true;
+        }
+
         ret
     }
+
+    pub fn discr_type(&self) -> attr::IntType {
+        self.int.unwrap_or(attr::SignedInt(ast::IntTy::Is))
+    }
+
+    /// Returns true if this `#[repr()]` should inhabit "smart enum
+    /// layout" optimizations, such as representing `Foo<&T>` as a
+    /// single pointer.
+    pub fn inhibit_enum_layout_opt(&self) -> bool {
+        self.c || self.int.is_some()
+    }
 }
 
 impl<'a, 'gcx, 'tcx> AdtDef {
-    fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    fn new(tcx: TyCtxt,
            did: DefId,
            kind: AdtKind,
-           discr_ty: attr::IntType,
            variants: Vec<VariantDef>,
            repr: ReprOptions) -> Self {
         let mut flags = AdtFlags::NO_ADT_FLAGS;
@@ -1394,9 +1411,6 @@ fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         if attr::contains_name(&attrs, "fundamental") {
             flags = flags | AdtFlags::IS_FUNDAMENTAL;
         }
-        if tcx.lookup_simd(did) {
-            flags = flags | AdtFlags::IS_SIMD;
-        }
         if Some(did) == tcx.lang_items.phantom_data() {
             flags = flags | AdtFlags::IS_PHANTOM_DATA;
         }
@@ -1410,7 +1424,6 @@ fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         }
         AdtDef {
             did: did,
-            discr_ty: discr_ty,
             variants: variants,
             flags: Cell::new(flags),
             destructor: Cell::new(None),
@@ -1486,11 +1499,6 @@ pub fn is_fundamental(&self) -> bool {
         self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL)
     }
 
-    #[inline]
-    pub fn is_simd(&self) -> bool {
-        self.flags.get().intersects(AdtFlags::IS_SIMD)
-    }
-
     /// Returns true if this is PhantomData<T>.
     #[inline]
     pub fn is_phantom_data(&self) -> bool {
@@ -1504,8 +1512,8 @@ pub fn is_box(&self) -> bool {
     }
 
     /// Returns whether this type has a destructor.
-    pub fn has_dtor(&self) -> bool {
-        self.destructor.get().is_some()
+    pub fn has_dtor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
+        self.destructor(tcx).is_some()
     }
 
     /// Asserts this is a struct and returns the struct's unique
@@ -1560,12 +1568,57 @@ pub fn variant_of_def(&self, def: Def) -> &VariantDef {
         }
     }
 
-    pub fn destructor(&self) -> Option<DefId> {
-        self.destructor.get()
+    pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
+        if self.flags.get().intersects(AdtFlags::IS_DTOR_VALID) {
+            return self.destructor.get();
+        }
+
+        let dtor = self.destructor_uncached(tcx);
+        self.destructor.set(dtor);
+        self.flags.set(self.flags.get() | AdtFlags::IS_DTOR_VALID);
+
+        dtor
+    }
+
+    fn destructor_uncached(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
+        let drop_trait = if let Some(def_id) = tcx.lang_items.drop_trait() {
+            def_id
+        } else {
+            return None;
+        };
+
+        queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, drop_trait));
+
+        let mut dtor = None;
+        let ty = tcx.item_type(self.did);
+        tcx.lookup_trait_def(drop_trait).for_each_relevant_impl(tcx, ty, |def_id| {
+            if let Some(item) = tcx.associated_items(def_id).next() {
+                dtor = Some(item.def_id);
+            }
+        });
+
+        dtor
     }
 
-    pub fn set_destructor(&self, dtor: DefId) {
-        self.destructor.set(Some(dtor));
+    pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
+                         -> impl Iterator<Item=ConstInt> + 'a {
+        let repr_type = self.repr.discr_type();
+        let initial = repr_type.initial_discriminant(tcx.global_tcx());
+        let mut prev_discr = None::<ConstInt>;
+        self.variants.iter().map(move |v| {
+            let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
+            if let VariantDiscr::Explicit(expr_did) = v.discr {
+                match tcx.maps.monomorphic_const_eval.borrow()[&expr_did] {
+                    Ok(ConstVal::Integral(v)) => {
+                        discr = v;
+                    }
+                    _ => {}
+                }
+            }
+            prev_discr = Some(discr);
+
+            discr
+        })
     }
 
     /// Returns a simpler type such that `Self: Sized` if and only
@@ -1609,7 +1662,7 @@ fn calculate_sized_constraint_inner(&self,
                                         stack: &mut Vec<DefId>)
                                         -> Ty<'tcx>
     {
-        if let Some(ty) = tcx.adt_sized_constraint.borrow().get(&self.did) {
+        if let Some(ty) = tcx.maps.adt_sized_constraint.borrow().get(&self.did) {
             return ty;
         }
 
@@ -1623,7 +1676,7 @@ fn calculate_sized_constraint_inner(&self,
             //
             // Consider the type as Sized in the meanwhile to avoid
             // further errors.
-            tcx.adt_sized_constraint.borrow_mut().insert(self.did, tcx.types.err);
+            tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, tcx.types.err);
             return tcx.types.err;
         }
 
@@ -1647,7 +1700,7 @@ fn calculate_sized_constraint_inner(&self,
             _ => tcx.intern_tup(&tys[..], false)
         };
 
-        let old = tcx.adt_sized_constraint.borrow().get(&self.did).cloned();
+        let old = tcx.maps.adt_sized_constraint.borrow().get(&self.did).cloned();
         match old {
             Some(old_ty) => {
                 debug!("calculate_sized_constraint: {:?} recurred", self);
@@ -1656,7 +1709,7 @@ fn calculate_sized_constraint_inner(&self,
             }
             None => {
                 debug!("calculate_sized_constraint: {:?} => {:?}", self, ty);
-                tcx.adt_sized_constraint.borrow_mut().insert(self.did, ty);
+                tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, ty);
                 ty
             }
         }
@@ -1871,28 +1924,6 @@ pub fn from_mutbl(m: hir::Mutability) -> Self {
     }
 }
 
-/// Helper for looking things up in the various maps that are populated during
-/// typeck::collect (e.g., `tcx.associated_items`, `tcx.types`, etc).  All of
-/// these share the pattern that if the id is local, it should have been loaded
-/// into the map by the `typeck::collect` phase.  If the def-id is external,
-/// then we have to go consult the crate loading code (and cache the result for
-/// the future).
-fn lookup_locally_or_in_crate_store<M, F>(descr: &str,
-                                          def_id: DefId,
-                                          map: &M,
-                                          load_external: F)
-                                          -> M::Value where
-    M: MemoizationMap<Key=DefId>,
-    F: FnOnce() -> M::Value,
-{
-    map.memoize(def_id, || {
-        if def_id.is_local() {
-            bug!("No def'n found for {:?} in tcx.{}", def_id, descr);
-        }
-        load_external()
-    })
-}
-
 impl BorrowKind {
     pub fn from_mutbl(m: hir::Mutability) -> BorrowKind {
         match m {
@@ -1932,25 +1963,7 @@ pub fn body_tables(self, body: hir::BodyId) -> &'gcx TypeckTables<'gcx> {
     }
 
     pub fn item_tables(self, def_id: DefId) -> &'gcx TypeckTables<'gcx> {
-        self.tables.memoize(def_id, || {
-            if def_id.is_local() {
-                // Closures' tables come from their outermost function,
-                // as they are part of the same "inference environment".
-                let outer_def_id = self.closure_base_def_id(def_id);
-                if outer_def_id != def_id {
-                    return self.item_tables(outer_def_id);
-                }
-
-                bug!("No def'n found for {:?} in tcx.tables", def_id);
-            }
-
-            // Cross-crate side-tables only exist alongside serialized HIR.
-            self.sess.cstore.maybe_get_item_body(self.global_tcx(), def_id).map(|_| {
-                self.tables.borrow()[&def_id]
-            }).unwrap_or_else(|| {
-                bug!("tcx.item_tables({:?}): missing from metadata", def_id)
-            })
-        })
+        queries::typeck_tables::get(self, DUMMY_SP, def_id)
     }
 
     pub fn expr_span(self, id: NodeId) -> Span {
@@ -2058,31 +2071,15 @@ pub fn trait_relevant_for_never(self, did: DefId) -> bool {
     }
 
     pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized {
-        self.custom_coerce_unsized_kinds.memoize(did, || {
-            let (kind, src) = if did.krate != LOCAL_CRATE {
-                (self.sess.cstore.custom_coerce_unsized_kind(did), "external")
-            } else {
-                (None, "local")
-            };
-
-            match kind {
-                Some(kind) => kind,
-                None => {
-                    bug!("custom_coerce_unsized_kind: \
-                          {} impl `{}` is missing its kind",
-                          src, self.item_path_str(did));
-                }
-            }
-        })
+        queries::custom_coerce_unsized_kind::get(self, DUMMY_SP, did)
     }
 
     pub fn associated_item(self, def_id: DefId) -> AssociatedItem {
-        self.associated_items.memoize(def_id, || {
-            if !def_id.is_local() {
-                return self.sess.cstore.associated_item(def_id)
-                           .expect("missing AssociatedItem in metadata");
-            }
+        if !def_id.is_local() {
+            return queries::associated_item::get(self, DUMMY_SP, def_id);
+        }
 
+        self.maps.associated_item.memoize(def_id, || {
             // When the user asks for a given associated item, we
             // always go ahead and convert all the associated items in
             // the container. Note that we are also careful only to
@@ -2104,7 +2101,8 @@ pub fn associated_item(self, def_id: DefId) -> AssociatedItem {
                             self.associated_item_from_impl_item_ref(parent_def_id,
                                                                     impl_trait_ref.is_some(),
                                                                     impl_item_ref);
-                        self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item);
+                        self.maps.associated_item.borrow_mut()
+                            .insert(assoc_item.def_id, assoc_item);
                     }
                 }
 
@@ -2112,7 +2110,8 @@ pub fn associated_item(self, def_id: DefId) -> AssociatedItem {
                     for trait_item_ref in trait_item_refs {
                         let assoc_item =
                             self.associated_item_from_trait_item_ref(parent_def_id, trait_item_ref);
-                        self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item);
+                        self.maps.associated_item.borrow_mut()
+                            .insert(assoc_item.def_id, assoc_item);
                     }
                 }
 
@@ -2123,7 +2122,7 @@ pub fn associated_item(self, def_id: DefId) -> AssociatedItem {
 
             // memoize wants us to return something, so return
             // the one we generated for this def-id
-            *self.associated_items.borrow().get(&def_id).unwrap()
+            *self.maps.associated_item.borrow().get(&def_id).unwrap()
         })
     }
 
@@ -2181,11 +2180,11 @@ fn associated_item_from_impl_item_ref(self,
     }
 
     pub fn associated_item_def_ids(self, def_id: DefId) -> Rc<Vec<DefId>> {
-        self.associated_item_def_ids.memoize(def_id, || {
-            if !def_id.is_local() {
-                return Rc::new(self.sess.cstore.associated_item_def_ids(def_id));
-            }
+        if !def_id.is_local() {
+            return queries::associated_item_def_ids::get(self, DUMMY_SP, def_id);
+        }
 
+        self.maps.associated_item_def_ids.memoize(def_id, || {
             let id = self.hir.as_local_node_id(def_id).unwrap();
             let item = self.hir.expect_item(id);
             let vec: Vec<_> = match item.node {
@@ -2217,9 +2216,7 @@ pub fn associated_items(self, def_id: DefId)
     /// Returns the trait-ref corresponding to a given impl, or None if it is
     /// an inherent impl.
     pub fn impl_trait_ref(self, id: DefId) -> Option<TraitRef<'gcx>> {
-        lookup_locally_or_in_crate_store(
-            "impl_trait_refs", id, &self.impl_trait_refs,
-            || self.sess.cstore.impl_trait_ref(self.global_tcx(), id))
+        queries::impl_trait_ref::get(self, DUMMY_SP, id)
     }
 
     // Returns `ty::VariantDef` if `def` refers to a struct,
@@ -2298,58 +2295,37 @@ pub fn item_name(self, id: DefId) -> ast::Name {
     // If the given item is in an external crate, looks up its type and adds it to
     // the type cache. Returns the type parameters and type.
     pub fn item_type(self, did: DefId) -> Ty<'gcx> {
-        lookup_locally_or_in_crate_store(
-            "item_types", did, &self.item_types,
-            || self.sess.cstore.item_type(self.global_tcx(), did))
+        queries::ty::get(self, DUMMY_SP, did)
     }
 
     /// Given the did of a trait, returns its canonical trait ref.
     pub fn lookup_trait_def(self, did: DefId) -> &'gcx TraitDef {
-        lookup_locally_or_in_crate_store(
-            "trait_defs", did, &self.trait_defs,
-            || self.alloc_trait_def(self.sess.cstore.trait_def(self.global_tcx(), did))
-        )
+        queries::trait_def::get(self, DUMMY_SP, did)
     }
 
     /// Given the did of an ADT, return a reference to its definition.
     pub fn lookup_adt_def(self, did: DefId) -> &'gcx AdtDef {
-        lookup_locally_or_in_crate_store(
-            "adt_defs", did, &self.adt_defs,
-            || self.sess.cstore.adt_def(self.global_tcx(), did))
+        queries::adt_def::get(self, DUMMY_SP, did)
     }
 
     /// Given the did of an item, returns its generics.
-    pub fn item_generics(self, did: DefId) -> &'gcx Generics<'gcx> {
-        lookup_locally_or_in_crate_store(
-            "generics", did, &self.generics,
-            || self.alloc_generics(self.sess.cstore.item_generics(self.global_tcx(), did)))
+    pub fn item_generics(self, did: DefId) -> &'gcx Generics {
+        queries::generics::get(self, DUMMY_SP, did)
     }
 
     /// Given the did of an item, returns its full set of predicates.
     pub fn item_predicates(self, did: DefId) -> GenericPredicates<'gcx> {
-        lookup_locally_or_in_crate_store(
-            "predicates", did, &self.predicates,
-            || self.sess.cstore.item_predicates(self.global_tcx(), did))
+        queries::predicates::get(self, DUMMY_SP, did)
     }
 
     /// Given the did of a trait, returns its superpredicates.
     pub fn item_super_predicates(self, did: DefId) -> GenericPredicates<'gcx> {
-        lookup_locally_or_in_crate_store(
-            "super_predicates", did, &self.super_predicates,
-            || self.sess.cstore.item_super_predicates(self.global_tcx(), did))
+        queries::super_predicates::get(self, DUMMY_SP, did)
     }
 
     /// Given the did of an item, returns its MIR, borrowed immutably.
     pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> {
-        lookup_locally_or_in_crate_store("mir_map", did, &self.mir_map, || {
-            let mir = self.sess.cstore.get_item_mir(self.global_tcx(), did);
-            let mir = self.alloc_mir(mir);
-
-            // Perma-borrow MIR from extern crates to prevent mutation.
-            mem::forget(mir.borrow());
-
-            mir
-        }).borrow()
+        queries::mir::get(self, DUMMY_SP, did).borrow()
     }
 
     /// If `type_needs_drop` returns true, then `ty` is definitely
@@ -2400,41 +2376,23 @@ pub fn has_attr(self, did: DefId, attr: &str) -> bool {
         self.get_attrs(did).iter().any(|item| item.check_name(attr))
     }
 
-    /// Determine whether an item is annotated with `#[repr(packed)]`
-    pub fn lookup_packed(self, did: DefId) -> bool {
-        self.lookup_repr_hints(did).contains(&attr::ReprPacked)
-    }
-
-    /// Determine whether an item is annotated with `#[simd]`
-    pub fn lookup_simd(self, did: DefId) -> bool {
-        self.has_attr(did, "simd")
-            || self.lookup_repr_hints(did).contains(&attr::ReprSimd)
-    }
-
     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)))
+        queries::variances::get(self, DUMMY_SP, item_id)
     }
 
     pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool {
-        self.populate_implementations_for_trait_if_necessary(trait_def_id);
-
         let def = self.lookup_trait_def(trait_def_id);
         def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL)
     }
 
-    /// Records a trait-to-implementation mapping.
-    pub fn record_trait_has_default_impl(self, trait_def_id: DefId) {
-        let def = self.lookup_trait_def(trait_def_id);
-        def.flags.set(def.flags.get() | TraitFlags::HAS_DEFAULT_IMPL)
-    }
-
     /// Populates the type context with all the inherent implementations for
     /// the given type if necessary.
     pub fn populate_inherent_implementations_for_type_if_necessary(self,
+                                                                   span: Span,
                                                                    type_id: DefId) {
         if type_id.is_local() {
+            // Make sure coherence of inherent impls ran already.
+            ty::queries::coherent_inherent_impls::force(self, span, LOCAL_CRATE);
             return
         }
 
@@ -2451,7 +2409,7 @@ pub fn populate_inherent_implementations_for_type_if_necessary(self,
 
         let inherent_impls = self.sess.cstore.inherent_implementations_for_type(type_id);
 
-        self.inherent_impls.borrow_mut().insert(type_id, inherent_impls);
+        self.maps.inherent_impls.borrow_mut().insert(type_id, inherent_impls);
         self.populated_external_types.borrow_mut().insert(type_id);
     }
 
@@ -2467,16 +2425,12 @@ pub fn populate_implementations_for_trait_if_necessary(self, trait_id: DefId) {
         let _ignore = self.dep_graph.in_ignore();
 
         let def = self.lookup_trait_def(trait_id);
-        if def.flags.get().intersects(TraitFlags::IMPLS_VALID) {
+        if def.flags.get().intersects(TraitFlags::HAS_REMOTE_IMPLS) {
             return;
         }
 
         debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def);
 
-        if self.sess.cstore.is_defaulted_trait(trait_id) {
-            self.record_trait_has_default_impl(trait_id);
-        }
-
         for impl_def_id in self.sess.cstore.implementations_of_trait(Some(trait_id)) {
             let trait_ref = self.impl_trait_ref(impl_def_id).unwrap();
 
@@ -2485,37 +2439,15 @@ pub fn populate_implementations_for_trait_if_necessary(self, trait_id: DefId) {
             def.record_remote_impl(self, impl_def_id, trait_ref, parent);
         }
 
-        def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID);
+        def.flags.set(def.flags.get() | TraitFlags::HAS_REMOTE_IMPLS);
     }
 
     pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind {
-        // If this is a local def-id, it should be inserted into the
-        // tables by typeck; else, it will be retreived from
-        // the external crate metadata.
-        if let Some(&kind) = self.closure_kinds.borrow().get(&def_id) {
-            return kind;
-        }
-
-        let kind = self.sess.cstore.closure_kind(def_id);
-        self.closure_kinds.borrow_mut().insert(def_id, kind);
-        kind
+        queries::closure_kind::get(self, DUMMY_SP, def_id)
     }
 
-    pub fn closure_type(self,
-                        def_id: DefId,
-                        substs: ClosureSubsts<'tcx>)
-                        -> ty::ClosureTy<'tcx>
-    {
-        // If this is a local def-id, it should be inserted into the
-        // tables by typeck; else, it will be retreived from
-        // the external crate metadata.
-        if let Some(ty) = self.closure_tys.borrow().get(&def_id) {
-            return ty.subst(self, substs.substs);
-        }
-
-        let ty = self.sess.cstore.closure_ty(self.global_tcx(), def_id);
-        self.closure_tys.borrow_mut().insert(def_id, ty.clone());
-        ty.subst(self, substs.substs)
+    pub fn closure_type(self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
+        queries::closure_type::get(self, DUMMY_SP, def_id)
     }
 
     /// Given the def_id of an impl, return the def_id of the trait it implements.
@@ -2527,15 +2459,17 @@ pub fn trait_id_of_impl(self, def_id: DefId) -> Option<DefId> {
     /// If the given def ID describes a method belonging to an impl, return the
     /// ID of the impl that the method belongs to. Otherwise, return `None`.
     pub fn impl_of_method(self, def_id: DefId) -> Option<DefId> {
-        if def_id.krate != LOCAL_CRATE {
-            return self.sess.cstore.associated_item(def_id).and_then(|item| {
-                match item.container {
-                    TraitContainer(_) => None,
-                    ImplContainer(def_id) => Some(def_id),
-                }
-            });
-        }
-        match self.associated_items.borrow().get(&def_id).cloned() {
+        let item = if def_id.krate != LOCAL_CRATE {
+            if let Some(Def::Method(_)) = self.sess.cstore.describe_def(def_id) {
+                Some(self.associated_item(def_id))
+            } else {
+                None
+            }
+        } else {
+            self.maps.associated_item.borrow().get(&def_id).cloned()
+        };
+
+        match item {
             Some(trait_item) => {
                 match trait_item.container {
                     TraitContainer(_) => None,
@@ -2553,7 +2487,7 @@ pub fn trait_of_item(self, def_id: DefId) -> Option<DefId> {
         if def_id.krate != LOCAL_CRATE {
             return self.sess.cstore.trait_of_item(def_id);
         }
-        match self.associated_items.borrow().get(&def_id) {
+        match self.maps.associated_item.borrow().get(&def_id) {
             Some(associated_item) => {
                 match associated_item.container {
                     TraitContainer(def_id) => Some(def_id),
index 2e3009b4ed6dba72b0c814a700ae28dd40cb2475..cef24d44d6875300ded45c8bb997678f1e7eb521 100644 (file)
@@ -157,24 +157,6 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
     Ok(tcx.mk_substs(params)?)
 }
 
-impl<'tcx> Relate<'tcx> for &'tcx ty::BareFnTy<'tcx> {
-    fn relate<'a, 'gcx, R>(relation: &mut R,
-                           a: &&'tcx ty::BareFnTy<'tcx>,
-                           b: &&'tcx ty::BareFnTy<'tcx>)
-                           -> RelateResult<'tcx, &'tcx ty::BareFnTy<'tcx>>
-        where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
-    {
-        let unsafety = relation.relate(&a.unsafety, &b.unsafety)?;
-        let abi = relation.relate(&a.abi, &b.abi)?;
-        let sig = relation.relate(&a.sig, &b.sig)?;
-        Ok(relation.tcx().mk_bare_fn(ty::BareFnTy {
-            unsafety: unsafety,
-            abi: abi,
-            sig: sig
-        }))
-    }
-}
-
 impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
     fn relate<'a, 'gcx, R>(relation: &mut R,
                            a: &ty::FnSig<'tcx>,
@@ -186,6 +168,8 @@ fn relate<'a, 'gcx, R>(relation: &mut R,
             return Err(TypeError::VariadicMismatch(
                 expected_found(relation, &a.variadic, &b.variadic)));
         }
+        let unsafety = relation.relate(&a.unsafety, &b.unsafety)?;
+        let abi = relation.relate(&a.abi, &b.abi)?;
 
         if a.inputs().len() != b.inputs().len() {
             return Err(TypeError::ArgCount);
@@ -204,7 +188,9 @@ fn relate<'a, 'gcx, R>(relation: &mut R,
             }).collect::<Result<AccumulateVec<[_; 8]>, _>>()?;
         Ok(ty::FnSig {
             inputs_and_output: relation.tcx().intern_type_list(&inputs_and_output),
-            variadic: a.variadic
+            variadic: a.variadic,
+            unsafety: unsafety,
+            abi: abi
         })
     }
 }
index aa74e7cc0d0430c809f0195b34fcf98a4bdc2170..48f6fcd11b8acf18b1e221e751e68f90d5113fa7 100644 (file)
@@ -235,20 +235,9 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lif
         tcx.lift(&self.inputs_and_output).map(|x| {
             ty::FnSig {
                 inputs_and_output: x,
-                variadic: self.variadic
-            }
-        })
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::ClosureTy<'a> {
-    type Lifted = ty::ClosureTy<'tcx>;
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.sig).map(|sig| {
-            ty::ClosureTy {
-                sig: sig,
+                variadic: self.variadic,
                 unsafety: self.unsafety,
-                abi: self.abi
+                abi: self.abi,
             }
         })
     }
@@ -353,7 +342,7 @@ fn super_visit_with<F: TypeVisitor<'tcx>>(&self, _: &mut F) -> bool {
     }
 }
 
-CopyImpls! { (), hir::Unsafety, abi::Abi, ty::RegionParameterDef }
+CopyImpls! { (), hir::Unsafety, abi::Abi }
 
 impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> (T, U) {
@@ -531,43 +520,6 @@ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::BareFnTy<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        let fty = ty::BareFnTy {
-            sig: self.sig.fold_with(folder),
-            abi: self.abi,
-            unsafety: self.unsafety
-        };
-        folder.tcx().mk_bare_fn(fty)
-    }
-
-    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_bare_fn_ty(self)
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.sig.visit_with(visitor)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ClosureTy<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-       ty::ClosureTy {
-            sig: self.sig.fold_with(folder),
-            unsafety: self.unsafety,
-            abi: self.abi,
-        }
-    }
-
-    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_closure_ty(self)
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.sig.visit_with(visitor)
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         ty::TypeAndMut { ty: self.ty.fold_with(folder), mutbl: self.mutbl }
@@ -588,6 +540,8 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
         ty::FnSig {
             inputs_and_output: folder.tcx().intern_type_list(&inputs_and_output),
             variadic: self.variadic,
+            unsafety: self.unsafety,
+            abi: self.abi,
         }
     }
 
@@ -716,40 +670,6 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::TypeParameterDef {
-            name: self.name,
-            def_id: self.def_id,
-            index: self.index,
-            default: self.default.fold_with(folder),
-            default_def_id: self.default_def_id,
-            pure_wrt_drop: self.pure_wrt_drop,
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.default.visit_with(visitor)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::Generics {
-            parent: self.parent,
-            parent_regions: self.parent_regions,
-            parent_types: self.parent_types,
-            regions: self.regions.fold_with(folder),
-            types: self.types.fold_with(folder),
-            has_self: self.has_self,
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.regions.visit_with(visitor) || self.types.visit_with(visitor)
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         ty::GenericPredicates {
index 862bc15c0526001775f1088c92cb540be4ed225a..e686d62019145bc13d7aaadb1d955a4116d0a86b 100644 (file)
@@ -128,12 +128,12 @@ pub enum TypeVariants<'tcx> {
 
     /// The anonymous type of a function declaration/definition. Each
     /// function has a unique type.
-    TyFnDef(DefId, &'tcx Substs<'tcx>, &'tcx BareFnTy<'tcx>),
+    TyFnDef(DefId, &'tcx Substs<'tcx>, PolyFnSig<'tcx>),
 
     /// A pointer to a function.  Written as `fn() -> i32`.
     /// FIXME: This is currently also used to represent the callee of a method;
     /// see ty::MethodCallee etc.
-    TyFnPtr(&'tcx BareFnTy<'tcx>),
+    TyFnPtr(PolyFnSig<'tcx>),
 
     /// A trait, defined with `trait`.
     TyDynamic(Binder<&'tcx Slice<ExistentialPredicate<'tcx>>>, &'tcx ty::Region),
@@ -389,6 +389,24 @@ pub struct TraitRef<'tcx> {
     pub substs: &'tcx Substs<'tcx>,
 }
 
+impl<'tcx> TraitRef<'tcx> {
+    pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> TraitRef<'tcx> {
+        TraitRef { def_id: def_id, substs: substs }
+    }
+
+    pub fn self_ty(&self) -> Ty<'tcx> {
+        self.substs.type_at(0)
+    }
+
+    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()
+    }
+}
+
 pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>;
 
 impl<'tcx> PolyTraitRef<'tcx> {
@@ -531,38 +549,22 @@ pub struct ProjectionTy<'tcx> {
     /// The name `N` of the associated type.
     pub item_name: Name,
 }
-
-#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
-pub struct BareFnTy<'tcx> {
-    pub unsafety: hir::Unsafety,
-    pub abi: abi::Abi,
-    /// Signature (inputs and output) of this function type.
-    pub sig: PolyFnSig<'tcx>,
-}
-
-impl<'tcx> serialize::UseSpecializedDecodable for &'tcx BareFnTy<'tcx> {}
-
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
-pub struct ClosureTy<'tcx> {
-    pub unsafety: hir::Unsafety,
-    pub abi: abi::Abi,
-    pub sig: PolyFnSig<'tcx>,
-}
-
 /// Signature of a function type, which I have arbitrarily
 /// decided to use to refer to the input/output types.
 ///
 /// - `inputs` is the list of arguments and their modes.
 /// - `output` is the return type.
 /// - `variadic` indicates whether this is a variadic function. (only true for foreign fns)
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct FnSig<'tcx> {
     pub inputs_and_output: &'tcx Slice<Ty<'tcx>>,
-    pub variadic: bool
+    pub variadic: bool,
+    pub unsafety: hir::Unsafety,
+    pub abi: abi::Abi,
 }
 
 impl<'tcx> FnSig<'tcx> {
-    pub fn inputs(&self) -> &[Ty<'tcx>] {
+    pub fn inputs(&self) -> &'tcx [Ty<'tcx>] {
         &self.inputs_and_output[..self.inputs_and_output.len() - 1]
     }
 
@@ -574,7 +576,7 @@ pub fn output(&self) -> Ty<'tcx> {
 pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>;
 
 impl<'tcx> PolyFnSig<'tcx> {
-    pub fn inputs(&self) -> Binder<&[Ty<'tcx>]> {
+    pub fn inputs(&self) -> Binder<&'tcx [Ty<'tcx>]> {
         Binder(self.skip_binder().inputs())
     }
     pub fn input(&self, index: usize) -> ty::Binder<Ty<'tcx>> {
@@ -586,6 +588,12 @@ pub fn output(&self) -> ty::Binder<Ty<'tcx>> {
     pub fn variadic(&self) -> bool {
         self.skip_binder().variadic
     }
+    pub fn unsafety(&self) -> hir::Unsafety {
+        self.skip_binder().unsafety
+    }
+    pub fn abi(&self) -> abi::Abi {
+        self.skip_binder().abi
+    }
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
@@ -1087,7 +1095,7 @@ pub fn is_structural(&self) -> bool {
     #[inline]
     pub fn is_simd(&self) -> bool {
         match self.sty {
-            TyAdt(def, _) => def.is_simd(),
+            TyAdt(def, _) => def.repr.simd,
             _ => false
         }
     }
@@ -1280,23 +1288,15 @@ pub fn builtin_index(&self) -> Option<Ty<'tcx>> {
         }
     }
 
-    pub fn fn_sig(&self) -> &'tcx PolyFnSig<'tcx> {
+    pub fn fn_sig(&self) -> PolyFnSig<'tcx> {
         match self.sty {
-            TyFnDef(.., ref f) | TyFnPtr(ref f) => &f.sig,
+            TyFnDef(.., f) | TyFnPtr(f) => f,
             _ => bug!("Ty::fn_sig() called on non-fn type: {:?}", self)
         }
     }
 
-    /// Returns the ABI of the given function.
-    pub fn fn_abi(&self) -> abi::Abi {
-        match self.sty {
-            TyFnDef(.., ref f) | TyFnPtr(ref f) => f.abi,
-            _ => bug!("Ty::fn_abi() called on non-fn type"),
-        }
-    }
-
     // Type accessors for substructures of types
-    pub fn fn_args(&self) -> ty::Binder<&[Ty<'tcx>]> {
+    pub fn fn_args(&self) -> ty::Binder<&'tcx [Ty<'tcx>]> {
         self.fn_sig().inputs()
     }
 
index c0a529b936b0fbde258a5aa22aadc5e93c06e92a..0a2cc1c30f40fc61452b3aa8bd3fedd3386269c9 100644 (file)
@@ -184,7 +184,7 @@ pub fn for_item<FR, FT>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                             mut mk_type: FT)
                             -> &'tcx Substs<'tcx>
     where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
-          FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> {
+          FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
         let defs = tcx.item_generics(def_id);
         let mut substs = Vec::with_capacity(defs.count());
         Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type);
@@ -198,7 +198,7 @@ pub fn extend_to<FR, FT>(&self,
                              mut mk_type: FT)
                              -> &'tcx Substs<'tcx>
     where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
-          FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx>
+          FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx>
     {
         let defs = tcx.item_generics(def_id);
         let mut result = Vec::with_capacity(defs.count());
@@ -209,11 +209,11 @@ pub fn extend_to<FR, FT>(&self,
 
     fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
                          tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                         defs: &ty::Generics<'tcx>,
+                         defs: &ty::Generics,
                          mk_region: &mut FR,
                          mk_type: &mut FT)
     where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
-          FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> {
+          FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
 
         if let Some(def_id) = defs.parent {
             let parent_defs = tcx.item_generics(def_id);
@@ -223,11 +223,11 @@ fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
     }
 
     fn fill_single<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
-                           defs: &ty::Generics<'tcx>,
+                           defs: &ty::Generics,
                            mk_region: &mut FR,
                            mk_type: &mut FT)
     where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
-          FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> {
+          FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
         // Handle Self first, before all regions.
         let mut types = defs.types.iter();
         if defs.parent.is_none() && defs.has_self {
@@ -301,7 +301,7 @@ pub fn rebase_onto(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
         tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned())
     }
 
-    pub fn truncate_to(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, generics: &ty::Generics<'tcx>)
+    pub fn truncate_to(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, generics: &ty::Generics)
                        -> &'tcx Substs<'tcx> {
         tcx.mk_substs(self.iter().take(generics.count()).cloned())
     }
index 1dc494ca277b309e3ef0bb81f2f19688a9da2609..097b596c5ebb6b6c9e08219168643855605b265a 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use dep_graph::DepNode;
-use hir::def_id::DefId;
+use hir::def_id::{DefId, LOCAL_CRATE};
 use traits::{self, specialization_graph};
 use ty;
 use ty::fast_reject;
@@ -18,6 +18,9 @@
 use hir;
 use util::nodemap::FxHashMap;
 
+use syntax::ast;
+use syntax_pos::DUMMY_SP;
+
 /// A trait's definition with type information.
 pub struct TraitDef {
     pub def_id: DefId,
@@ -60,6 +63,11 @@ pub struct TraitDef {
     /// Various flags
     pub flags: Cell<TraitFlags>,
 
+    /// The number of impls we've added from the local crate.
+    /// When this number matches up the list in the HIR map,
+    /// we're done, and the specialization graph is correct.
+    local_impl_count: Cell<usize>,
+
     /// The ICH of this trait's DefPath, cached here so it doesn't have to be
     /// recomputed all the time.
     pub def_path_hash: u64,
@@ -78,6 +86,7 @@ pub fn new(def_id: DefId,
             nonblanket_impls: RefCell::new(FxHashMap()),
             blanket_impls: RefCell::new(vec![]),
             flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS),
+            local_impl_count: Cell::new(0),
             specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()),
             def_path_hash: def_path_hash,
         }
@@ -155,6 +164,13 @@ pub fn record_local_impl(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
         assert!(impl_def_id.is_local());
         let was_new = self.record_impl(tcx, impl_def_id, impl_trait_ref);
         assert!(was_new);
+
+        self.local_impl_count.set(self.local_impl_count.get() + 1);
+    }
+
+    /// Records a trait-to-implementation mapping.
+    pub fn record_has_default_impl(&self) {
+        self.flags.set(self.flags.get() | TraitFlags::HAS_DEFAULT_IMPL);
     }
 
     /// Records a trait-to-implementation mapping for a non-local impl.
@@ -194,10 +210,51 @@ pub fn ancestors(&'a self, of_impl: DefId) -> specialization_graph::Ancestors<'a
         specialization_graph::ancestors(self, of_impl)
     }
 
+    /// Whether the impl set and specialization graphs are complete.
+    pub fn is_complete(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
+        tcx.populate_implementations_for_trait_if_necessary(self.def_id);
+        ty::queries::coherent_trait::try_get(tcx, DUMMY_SP, (LOCAL_CRATE, self.def_id)).is_ok()
+    }
+
+    /// If any local impls haven't been added yet, returns
+    /// Some(list of local impls for this trait).
+    fn missing_local_impls(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
+                           -> Option<&'gcx [ast::NodeId]> {
+        if self.flags.get().intersects(TraitFlags::HAS_LOCAL_IMPLS) {
+            return None;
+        }
+
+        if self.is_complete(tcx) {
+            self.flags.set(self.flags.get() | TraitFlags::HAS_LOCAL_IMPLS);
+            return None;
+        }
+
+        let impls = tcx.hir.trait_impls(self.def_id);
+        assert!(self.local_impl_count.get() <= impls.len());
+        if self.local_impl_count.get() == impls.len() {
+            self.flags.set(self.flags.get() | TraitFlags::HAS_LOCAL_IMPLS);
+            return None;
+        }
+
+        Some(impls)
+    }
+
     pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, mut f: F) {
         self.read_trait_impls(tcx);
         tcx.populate_implementations_for_trait_if_necessary(self.def_id);
 
+        let local_impls = self.missing_local_impls(tcx);
+        if let Some(impls) = local_impls {
+            for &id in impls {
+                f(tcx.hir.local_def_id(id));
+            }
+        }
+        let mut f = |def_id: DefId| {
+            if !(local_impls.is_some() && def_id.is_local()) {
+                f(def_id);
+            }
+        };
+
         for &impl_def_id in self.blanket_impls.borrow().iter() {
             f(impl_def_id);
         }
@@ -217,9 +274,20 @@ pub fn for_each_relevant_impl<F: FnMut(DefId)>(&self,
                                                    mut f: F)
     {
         self.read_trait_impls(tcx);
-
         tcx.populate_implementations_for_trait_if_necessary(self.def_id);
 
+        let local_impls = self.missing_local_impls(tcx);
+        if let Some(impls) = local_impls {
+            for &id in impls {
+                f(tcx.hir.local_def_id(id));
+            }
+        }
+        let mut f = |def_id: DefId| {
+            if !(local_impls.is_some() && def_id.is_local()) {
+                f(def_id);
+            }
+        };
+
         for &impl_def_id in self.blanket_impls.borrow().iter() {
             f(impl_def_id);
         }
@@ -258,6 +326,7 @@ pub fn for_each_relevant_impl<F: FnMut(DefId)>(&self,
         const HAS_DEFAULT_IMPL      = 1 << 0,
         const IS_OBJECT_SAFE        = 1 << 1,
         const OBJECT_SAFETY_VALID   = 1 << 2,
-        const IMPLS_VALID           = 1 << 3,
+        const HAS_REMOTE_IMPLS      = 1 << 3,
+        const HAS_LOCAL_IMPLS       = 1 << 4,
     }
 }
index 16492de6c3d27fefb456f787c89a8a876628877e..49c25d25c604fb8c893dbecc6d1b5e50e4fe92b0 100644 (file)
 use hir::map as hir_map;
 use traits::{self, Reveal};
 use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
-use ty::{Disr, ParameterEnvironment};
+use ty::{ParameterEnvironment};
 use ty::fold::TypeVisitor;
 use ty::layout::{Layout, LayoutError};
 use ty::TypeVariants::*;
 use util::nodemap::FxHashMap;
 use middle::lang_items;
 
+use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
 use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult};
 
 use std::cell::RefCell;
 
 use hir;
 
-pub trait IntTypeExt {
-    fn to_ty<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
-    fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
+type Disr = ConstInt;
+
+ pub trait IntTypeExt {
+    fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
+    fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
+                           -> Option<Disr>;
+    fn assert_ty_matches(&self, val: Disr);
+    fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
+ }
+
+
+macro_rules! typed_literal {
+    ($tcx:expr, $ty:expr, $lit:expr) => {
+        match $ty {
+            SignedInt(ast::IntTy::I8)    => ConstInt::I8($lit),
+            SignedInt(ast::IntTy::I16)   => ConstInt::I16($lit),
+            SignedInt(ast::IntTy::I32)   => ConstInt::I32($lit),
+            SignedInt(ast::IntTy::I64)   => ConstInt::I64($lit),
+            SignedInt(ast::IntTy::I128)   => ConstInt::I128($lit),
+            SignedInt(ast::IntTy::Is) => match $tcx.sess.target.int_type {
+                ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16($lit)),
+                ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32($lit)),
+                ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64($lit)),
+                _ => bug!(),
+            },
+            UnsignedInt(ast::UintTy::U8)  => ConstInt::U8($lit),
+            UnsignedInt(ast::UintTy::U16) => ConstInt::U16($lit),
+            UnsignedInt(ast::UintTy::U32) => ConstInt::U32($lit),
+            UnsignedInt(ast::UintTy::U64) => ConstInt::U64($lit),
+            UnsignedInt(ast::UintTy::U128) => ConstInt::U128($lit),
+            UnsignedInt(ast::UintTy::Us) => match $tcx.sess.target.uint_type {
+                ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16($lit)),
+                ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32($lit)),
+                ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64($lit)),
+                _ => bug!(),
+            },
+        }
+    }
 }
 
 impl IntTypeExt for attr::IntType {
-    fn to_ty<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
-        match self {
-            SignedInt(i) => tcx.mk_mach_int(i),
-            UnsignedInt(i) => tcx.mk_mach_uint(i),
+    fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
+        match *self {
+            SignedInt(ast::IntTy::I8)      => tcx.types.i8,
+            SignedInt(ast::IntTy::I16)     => tcx.types.i16,
+            SignedInt(ast::IntTy::I32)     => tcx.types.i32,
+            SignedInt(ast::IntTy::I64)     => tcx.types.i64,
+            SignedInt(ast::IntTy::I128)     => tcx.types.i128,
+            SignedInt(ast::IntTy::Is)   => tcx.types.isize,
+            UnsignedInt(ast::UintTy::U8)    => tcx.types.u8,
+            UnsignedInt(ast::UintTy::U16)   => tcx.types.u16,
+            UnsignedInt(ast::UintTy::U32)   => tcx.types.u32,
+            UnsignedInt(ast::UintTy::U64)   => tcx.types.u64,
+            UnsignedInt(ast::UintTy::U128)   => tcx.types.u128,
+            UnsignedInt(ast::UintTy::Us) => tcx.types.usize,
         }
     }
 
-    fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
-        0
+    fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
+        typed_literal!(tcx, *self, 0)
+    }
+
+    fn assert_ty_matches(&self, val: Disr) {
+        match (*self, val) {
+            (SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => {},
+            (SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {},
+            (SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {},
+            (SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {},
+            (SignedInt(ast::IntTy::I128), ConstInt::I128(_)) => {},
+            (SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => {},
+            (UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {},
+            (UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {},
+            (UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {},
+            (UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {},
+            (UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) => {},
+            (UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => {},
+            _ => bug!("disr type mismatch: {:?} vs {:?}", self, val),
+        }
+    }
+
+    fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
+                           -> Option<Disr> {
+        if let Some(val) = val {
+            self.assert_ty_matches(val);
+            (val + typed_literal!(tcx, *self, 1)).ok()
+        } else {
+            Some(self.initial_discriminant(tcx))
+        }
     }
 }
 
@@ -81,7 +155,7 @@ pub fn can_type_implement_copy<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                        self_type: Ty<'tcx>, span: Span)
                                        -> Result<(), CopyImplementationError> {
         // FIXME: (@jroesch) float this code up
-        tcx.infer_ctxt(self.clone(), Reveal::NotSpecializable).enter(|infcx| {
+        tcx.infer_ctxt(self.clone(), Reveal::UserFacing).enter(|infcx| {
             let (adt, substs) = match self_type.sty {
                 ty::TyAdt(adt, substs) => (adt, substs),
                 _ => return Err(CopyImplementationError::NotAnAdt)
@@ -103,7 +177,7 @@ pub fn can_type_implement_copy<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 }
             }
 
-            if adt.has_dtor() {
+            if adt.has_dtor(tcx) {
                 return Err(CopyImplementationError::HasDestructor);
             }
 
@@ -164,21 +238,6 @@ pub fn named_element_ty(self,
         }
     }
 
-    /// Returns the IntType representation.
-    /// This used to ensure `int_ty` doesn't contain `usize` and `isize`
-    /// by converting them to their actual types. That doesn't happen anymore.
-    pub fn enum_repr_type(self, opt_hint: Option<&attr::ReprAttr>) -> attr::IntType {
-        match opt_hint {
-            // Feed in the given type
-            Some(&attr::ReprInt(int_t)) => int_t,
-            // ... but provide sensible default if none provided
-            //
-            // NB. Historically `fn enum_variants` generate i64 here, while
-            // rustc_typeck::check would generate isize.
-            _ => SignedInt(ast::IntTy::Is),
-        }
-    }
-
     /// Returns the deeply last field of nested structures, or the same type,
     /// if not a structure at all. Corresponds to the only possible unsized
     /// field, and its type can be used to determine unsizing strategy.
@@ -300,7 +359,7 @@ pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 {
     /// (This allows programs to make cyclic structures without
     /// resorting to unasfe means; see RFCs 769 and 1238).
     pub fn is_adt_dtorck(self, adt: &ty::AdtDef) -> bool {
-        let dtor_method = match adt.destructor() {
+        let dtor_method = match adt.destructor(self) {
             Some(dtor) => dtor,
             None => return false
         };
@@ -388,10 +447,10 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
             TyFnDef(def_id, ..) => self.def_id(def_id),
             TyAdt(d, _) => self.def_id(d.did),
             TyFnPtr(f) => {
-                self.hash(f.unsafety);
-                self.hash(f.abi);
-                self.hash(f.sig.variadic());
-                self.hash(f.sig.skip_binder().inputs().len());
+                self.hash(f.unsafety());
+                self.hash(f.abi());
+                self.hash(f.variadic());
+                self.hash(f.inputs().skip_binder().len());
             }
             TyDynamic(ref data, ..) => {
                 if let Some(p) = data.principal() {
@@ -471,7 +530,7 @@ fn impls_bound(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
             }
         }
         let result =
-            tcx.infer_ctxt(param_env.clone(), Reveal::ExactMatch)
+            tcx.infer_ctxt(param_env.clone(), Reveal::UserFacing)
             .enter(|infcx| {
                 traits::type_known_to_meet_bound(&infcx, self, def_id, span)
             });
index 01f31e5024c0dfeaf258100b77b17e136193a493..d7954953aba856902fb1829b0d8d30db6f60d71e 100644 (file)
@@ -115,17 +115,17 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
         ty::TyTuple(ts, _) => {
             stack.extend(ts.iter().cloned().rev());
         }
-        ty::TyFnDef(_, substs, ref ft) => {
+        ty::TyFnDef(_, substs, ft) => {
             stack.extend(substs.types().rev());
-            push_sig_subtypes(stack, &ft.sig);
+            push_sig_subtypes(stack, ft);
         }
-        ty::TyFnPtr(ref ft) => {
-            push_sig_subtypes(stack, &ft.sig);
+        ty::TyFnPtr(ft) => {
+            push_sig_subtypes(stack, ft);
         }
     }
 }
 
-fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: &ty::PolyFnSig<'tcx>) {
+fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: ty::PolyFnSig<'tcx>) {
     stack.push(sig.skip_binder().output());
     stack.extend(sig.skip_binder().inputs().iter().cloned().rev());
 }
index a45c43235ebf857ff203cf6ef128360cbf10154c..6323f1dc0d4c4a8da2f00a60797851a88b2edbe8 100644 (file)
@@ -137,11 +137,14 @@ pub fn parameterized(f: &mut fmt::Formatter,
         }
 
         if !verbose {
-            if generics.types.last().map_or(false, |def| def.default.is_some()) {
+            if generics.types.last().map_or(false, |def| def.has_default) {
                 if let Some(substs) = tcx.lift(&substs) {
                     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) {
+                        if !def.has_default {
+                            break;
+                        }
+                        if tcx.item_type(def.def_id).subst(tcx, substs) != actual {
                             break;
                         }
                         num_supplied_defaults += 1;
@@ -326,7 +329,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::TypeParameterDef<'tcx> {
+impl fmt::Debug for ty::TypeParameterDef {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "TypeParameterDef({}, {:?}, {})",
                self.name,
@@ -492,15 +495,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::ClosureTy<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "ClosureTy({},{:?},{})",
-               self.unsafety,
-               self.sig,
-               self.abi)
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "ClosureUpvar({:?},{:?})",
@@ -582,6 +576,14 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 impl<'tcx> fmt::Display for ty::FnSig<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        if self.unsafety == hir::Unsafety::Unsafe {
+            write!(f, "unsafe ")?;
+        }
+
+        if self.abi != Abi::Rust {
+            write!(f, "extern {} ", self.abi)?;
+        }
+
         write!(f, "fn")?;
         fn_sig(f, self.inputs(), self.variadic, self.output())
     }
@@ -738,42 +740,17 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 write!(f, ")")
             }
             TyFnDef(def_id, substs, ref bare_fn) => {
-                if bare_fn.unsafety == hir::Unsafety::Unsafe {
-                    write!(f, "unsafe ")?;
-                }
-
-                if bare_fn.abi != Abi::Rust {
-                    write!(f, "extern {} ", bare_fn.abi)?;
-                }
-
-                write!(f, "{} {{", bare_fn.sig.0)?;
+                write!(f, "{} {{", bare_fn.0)?;
                 parameterized(f, substs, def_id, &[])?;
                 write!(f, "}}")
             }
             TyFnPtr(ref bare_fn) => {
-                if bare_fn.unsafety == hir::Unsafety::Unsafe {
-                    write!(f, "unsafe ")?;
-                }
-
-                if bare_fn.abi != Abi::Rust {
-                    write!(f, "extern {} ", bare_fn.abi)?;
-                }
-
-                write!(f, "{}", bare_fn.sig.0)
+                write!(f, "{}", bare_fn.0)
             }
             TyInfer(infer_ty) => write!(f, "{}", infer_ty),
             TyError => write!(f, "[type error]"),
             TyParam(ref param_ty) => write!(f, "{}", param_ty),
-            TyAdt(def, substs) => {
-                ty::tls::with(|tcx| {
-                    if def.did.is_local() &&
-                          !tcx.item_types.borrow().contains_key(&def.did) {
-                        write!(f, "{}<..>", tcx.item_path_str(def.did))
-                    } else {
-                        parameterized(f, substs, def.did, &[])
-                    }
-                })
-            }
+            TyAdt(def, substs) => parameterized(f, substs, def.did, &[]),
             TyDynamic(data, r) => {
                 write!(f, "{}", data)?;
                 let r = r.to_string();
index 1d5d1e3ab2fc78a22f0ba2a9ac9dc0cbe1a994f8..0c179469448fef7a917db711b8a5f4c01c49e944 100644 (file)
@@ -200,6 +200,7 @@ fn $module() {
     ("armv7s-apple-ios", armv7s_apple_ios),
 
     ("x86_64-sun-solaris", x86_64_sun_solaris),
+    ("sparcv9-sun-solaris", sparcv9_sun_solaris),
 
     ("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu),
     ("i686-pc-windows-gnu", i686_pc_windows_gnu),
diff --git a/src/librustc_back/target/sparcv9_sun_solaris.rs b/src/librustc_back/target/sparcv9_sun_solaris.rs
new file mode 100644 (file)
index 0000000..c88e5a4
--- /dev/null
@@ -0,0 +1,35 @@
+// 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::solaris_base::opts();
+    base.pre_link_args.push("-m64".to_string());
+    // llvm calls this "v9"
+    base.cpu = "v9".to_string();
+    base.max_atomic_width = Some(64);
+
+    Ok(Target {
+        llvm_target: "sparcv9-sun-solaris".to_string(),
+        target_endian: "big".to_string(),
+        target_pointer_width: "64".to_string(),
+        data_layout: "E-m:e-i64:64-n32:64-S128".to_string(),
+        // Use "sparc64" instead of "sparcv9" here, since the former is already
+        // used widely in the source base.  If we ever needed ABI
+        // differentiation from the sparc64, we could, but that would probably
+        // just be confusing.
+        arch: "sparc64".to_string(),
+        target_os: "solaris".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "sun".to_string(),
+        options: base,
+    })
+}
index e3dec97472a481af97aa6b6e87b4ffe1495e16d2..3ce31882b86c4583ec1c4f5a7d5a5f05dad26aa8 100644 (file)
@@ -783,7 +783,7 @@ fn check_if_assigned_path_is_moved(&self,
             }
             LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => {
                 match lp_base.to_type().sty {
-                    ty::TyAdt(def, _) if def.has_dtor() => {
+                    ty::TyAdt(def, _) if def.has_dtor(self.tcx()) => {
                         // In the case where the owner implements drop, then
                         // the path must be initialized to prevent a case of
                         // partial reinitialization
index c33ced52e2bd6aee181faebf9e37f6acd99fa0a9..0577ba7f45a938883d3767c8b697acd94913dca3 100644 (file)
@@ -177,7 +177,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => {
             match b.ty.sty {
                 ty::TyAdt(def, _) => {
-                    if def.has_dtor() {
+                    if def.has_dtor(bccx.tcx) {
                         Some(cmt.clone())
                     } else {
                         check_and_get_illegal_move_origin(bccx, b)
index 47f8d978704f4710145305f1c40d9b74b4ea8b8b..3678c2e55c1fdb17d0d175796e282f167f98f861 100644 (file)
@@ -150,7 +150,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         Categorization::Downcast(ref b, _) |
         Categorization::Interior(ref b, mc::InteriorField(_)) => {
             match b.ty.sty {
-                ty::TyAdt(def, _) if def.has_dtor() => {
+                ty::TyAdt(def, _) if def.has_dtor(bccx.tcx) => {
                     let mut err = struct_span_err!(bccx, move_from.span, E0509,
                                                    "cannot move out of type `{}`, \
                                                    which implements the `Drop` trait",
index 940dd5433a0d9ee3846f762c9a8da678293be009..44e3b38ea3857dd04d18599e15734ade67c7822e 100644 (file)
@@ -164,8 +164,9 @@ fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         {
             if let mir::Operand::Constant(ref func) = *oper
             {
-                if let ty::TyFnDef(def_id, _, &ty::BareFnTy { abi, .. }) = func.ty.sty
+                if let ty::TyFnDef(def_id, _, sig) = func.ty.sty
                 {
+                    let abi = sig.abi();
                     let name = tcx.item_name(def_id);
                     if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
                         if name == "rustc_peek" {
index 5899c9f31d14dc4c4d00c73a2183a37db193b566..13f898219bc12dfba9c9d456cb34c7d15a5b51e5 100644 (file)
@@ -20,7 +20,7 @@
 use rustc::ty::util::IntTypeExt;
 use rustc::mir::*;
 use rustc::mir::transform::{Pass, MirPass, MirSource};
-use rustc::middle::const_val::{ConstVal, ConstInt};
+use rustc::middle::const_val::ConstVal;
 use rustc::middle::lang_items;
 use rustc::util::nodemap::FxHashMap;
 use rustc_data_structures::indexed_set::IdxSetBuf;
@@ -639,10 +639,7 @@ fn open_drop_for_adt<'a>(&mut self, c: &DropCtxt<'a, 'tcx>,
                 let mut values = Vec::with_capacity(adt.variants.len());
                 let mut blocks = Vec::with_capacity(adt.variants.len());
                 let mut otherwise = None;
-                for (variant_index, variant) in adt.variants.iter().enumerate() {
-                    let discr = ConstInt::new_inttype(variant.disr_val, adt.discr_ty,
-                                                      self.tcx.sess.target.uint_type,
-                                                      self.tcx.sess.target.int_type).unwrap();
+                for (variant_index, discr) in adt.discriminants(self.tcx).enumerate() {
                     let subpath = super::move_path_children_matching(
                         self.move_data(), c.path, |proj| match proj {
                             &Projection {
@@ -680,7 +677,7 @@ fn open_drop_for_adt<'a>(&mut self, c: &DropCtxt<'a, 'tcx>,
                 // Additionally, we do not want to switch on the
                 // discriminant after it is free-ed, because that
                 // way lies only trouble.
-                let discr_ty = adt.discr_ty.to_ty(self.tcx);
+                let discr_ty = adt.repr.discr_type().to_ty(self.tcx);
                 let discr = Lvalue::Local(self.patch.new_temp(discr_ty));
                 let switch_block = self.patch.new_block(BasicBlockData {
                     statements: vec![
@@ -901,7 +898,7 @@ fn must_complete_drop<'a>(&self, c: &DropCtxt<'a, 'tcx>) -> bool {
 
         match ty.sty {
             ty::TyAdt(def, _) => {
-                if def.has_dtor() && !def.is_box() {
+                if def.has_dtor(self.tcx) && !def.is_box() {
                     self.tcx.sess.span_warn(
                         c.source_info.span,
                         &format!("dataflow bug??? moving out of type with dtor {:?}",
index 35ace6628cfed4d7f244443a4feda936e20555c3..8d866676dbd1875dc3838da2e0491e4db397ae00 100644 (file)
@@ -289,7 +289,7 @@ fn move_path_for_projection(&mut self,
             // error: can't move out of borrowed content
             ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove),
             // error: can't move out of struct with destructor
-            ty::TyAdt(adt, _) if adt.has_dtor() && !adt.is_box() =>
+            ty::TyAdt(adt, _) if adt.has_dtor(self.tcx) && !adt.is_box() =>
                 return Err(MovePathError::IllegalMove),
             // move out of union - always move the entire union
             ty::TyAdt(adt, _) if adt.is_union() =>
index d9283e7037f50f2dc851af5ec9cb53737709f837..1c9ee335699ae13439d689cbb1af77e826b72b69 100644 (file)
@@ -248,7 +248,7 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
                    lv, ty);
             true
         }
-        ty::TyAdt(def, _) if (def.has_dtor() && !def.is_box()) || def.is_union() => {
+        ty::TyAdt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => {
             debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => true",
                    lv, ty);
             true
index 78c4027aa4319297a1ab45100580d6e863b70c57..53a7e87292818d773a7af3dfcd859d0b8467adcd 100644 (file)
@@ -196,24 +196,46 @@ fn lower_byte_str_pattern<'p>(&mut self, pat: &'p Pattern<'tcx>) -> Vec<&'p Patt
             }
         }).clone()
     }
+
+    fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
+        if self.tcx.sess.features.borrow().never_type {
+            ty.is_uninhabited_from(self.module, self.tcx)
+        } else {
+            false
+        }
+    }
+
+    fn is_variant_uninhabited(&self,
+                              variant: &'tcx ty::VariantDef,
+                              substs: &'tcx ty::subst::Substs<'tcx>) -> bool
+    {
+        if self.tcx.sess.features.borrow().never_type {
+            let forest = variant.uninhabited_from(
+                &mut FxHashMap::default(), self.tcx, substs, AdtKind::Enum
+            );
+            forest.contains(self.tcx, self.module)
+        } else {
+            false
+        }
+    }
 }
 
 #[derive(Clone, Debug, PartialEq)]
-pub enum Constructor {
+pub enum Constructor<'tcx> {
     /// The constructor of all patterns that don't vary by constructor,
     /// e.g. struct patterns and fixed-length arrays.
     Single,
     /// Enum variants.
     Variant(DefId),
     /// Literal values.
-    ConstantValue(ConstVal),
+    ConstantValue(ConstVal<'tcx>),
     /// Ranges of literal values (`2...5` and `2..5`).
-    ConstantRange(ConstVal, ConstVal, RangeEnd),
+    ConstantRange(ConstVal<'tcx>, ConstVal<'tcx>, RangeEnd),
     /// Array patterns of length n.
     Slice(usize),
 }
 
-impl<'tcx> Constructor {
+impl<'tcx> Constructor<'tcx> {
     fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> usize {
         match self {
             &Variant(vid) => adt.variant_index_with_id(vid),
@@ -267,7 +289,7 @@ pub fn single_pattern(&self) -> &Pattern<'tcx> {
     fn push_wild_constructor<'a>(
         mut self,
         cx: &MatchCheckCtxt<'a, 'tcx>,
-        ctor: &Constructor,
+        ctor: &Constructor<'tcx>,
         ty: Ty<'tcx>)
         -> Self
     {
@@ -299,7 +321,7 @@ fn push_wild_constructor<'a>(
     fn apply_constructor<'a>(
         mut self,
         cx: &MatchCheckCtxt<'a,'tcx>,
-        ctor: &Constructor,
+        ctor: &Constructor<'tcx>,
         ty: Ty<'tcx>)
         -> Self
     {
@@ -377,50 +399,35 @@ fn apply_constructor<'a>(
 /// We make sure to omit constructors that are statically impossible. eg for
 /// Option<!> we do not include Some(_) in the returned list of constructors.
 fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
-                                  pcx: PatternContext<'tcx>) -> Vec<Constructor>
+                                  pcx: PatternContext<'tcx>)
+                                  -> Vec<Constructor<'tcx>>
 {
-    let check_inhabited = cx.tcx.sess.features.borrow().never_type;
     debug!("all_constructors({:?})", pcx.ty);
     match pcx.ty.sty {
         ty::TyBool =>
             [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
         ty::TySlice(ref sub_ty) => {
-            if sub_ty.is_uninhabited_from(cx.module, cx.tcx)
-                && check_inhabited
-            {
+            if cx.is_uninhabited(sub_ty) {
                 vec![Slice(0)]
             } else {
                 (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect()
             }
         }
         ty::TyArray(ref sub_ty, length) => {
-            if length == 0 || !(sub_ty.is_uninhabited_from(cx.module, cx.tcx)
-                                && check_inhabited)
-            {
-                vec![Slice(length)]
-            } else {
+            if length > 0 && cx.is_uninhabited(sub_ty) {
                 vec![]
+            } else {
+                vec![Slice(length)]
             }
         }
         ty::TyAdt(def, substs) if def.is_enum() && def.variants.len() != 1 => {
-            def.variants.iter().filter_map(|v| {
-                let mut visited = FxHashMap::default();
-                let forest = v.uninhabited_from(&mut visited,
-                                                cx.tcx, substs,
-                                                AdtKind::Enum);
-                if forest.contains(cx.tcx, cx.module)
-                    && check_inhabited
-                {
-                    None
-                } else {
-                    Some(Variant(v.did))
-                }
-            }).collect()
+            def.variants.iter()
+                .filter(|v| !cx.is_variant_uninhabited(v, substs))
+                .map(|v| Variant(v.did))
+                .collect()
         }
         _ => {
-            if pcx.ty.is_uninhabited_from(cx.module, cx.tcx)
-                    && check_inhabited
-            {
+            if cx.is_uninhabited(pcx.ty) {
                 vec![]
             } else {
                 vec![Single]
@@ -564,7 +571,6 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
 
     assert!(rows.iter().all(|r| r.len() == v.len()));
 
-
     let pcx = PatternContext {
         ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error())
             .unwrap_or(v[0].ty),
@@ -590,7 +596,6 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
         let missing_ctors: Vec<Constructor> = all_ctors.iter().filter(|c| {
             !used_ctors.contains(*c)
         }).cloned().collect();
-        debug!("missing_ctors = {:?}", missing_ctors);
 
         // `missing_ctors` is the set of constructors from the same type as the
         // first column of `matrix` that are matched only by wildcard patterns
@@ -599,8 +604,23 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
         // Therefore, if there is some pattern that is unmatched by `matrix`,
         // it will still be unmatched if the first constructor is replaced by
         // any of the constructors in `missing_ctors`
-
-        if missing_ctors.is_empty() {
+        //
+        // However, if our scrutinee is *privately* an empty enum, we
+        // must treat it as though it had an "unknown" constructor (in
+        // that case, all other patterns obviously can't be variants)
+        // to avoid exposing its emptyness. See the `match_privately_empty`
+        // test for details.
+        //
+        // FIXME: currently the only way I know of something can
+        // be a privately-empty enum is when the never_type
+        // feature flag is not present, so this is only
+        // needed for that case.
+
+        let is_privately_empty =
+            all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
+        debug!("missing_ctors={:?} is_privately_empty={:?}", missing_ctors,
+               is_privately_empty);
+        if missing_ctors.is_empty() && !is_privately_empty {
             all_ctors.into_iter().map(|c| {
                 is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
             }).find(|result| result.is_useful()).unwrap_or(NotUseful)
@@ -645,10 +665,11 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
     cx: &mut MatchCheckCtxt<'a, 'tcx>,
     &Matrix(ref m): &Matrix<'p, 'tcx>,
     v: &[&'p Pattern<'tcx>],
-    ctor: Constructor,
+    ctor: Constructor<'tcx>,
     lty: Ty<'tcx>,
     witness: WitnessPreference) -> Usefulness<'tcx>
 {
+    debug!("is_useful_specialized({:?}, {:?}, {:?})", v, ctor, lty);
     let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty);
     let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| {
         Pattern {
@@ -682,10 +703,10 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
 /// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
 ///
 /// Returns None in case of a catch-all, which can't be specialized.
-fn pat_constructors(_cx: &mut MatchCheckCtxt,
-                    pat: &Pattern,
-                    pcx: PatternContext)
-                    -> Option<Vec<Constructor>>
+fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
+                          pat: &Pattern<'tcx>,
+                          pcx: PatternContext)
+                          -> Option<Vec<Constructor<'tcx>>>
 {
     match *pat.kind {
         PatternKind::Binding { .. } | PatternKind::Wild =>
@@ -754,7 +775,19 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
         ty::TyRef(_, ref ty_and_mut) => vec![ty_and_mut.ty],
         ty::TyAdt(adt, substs) => {
             adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
-                field.ty(cx.tcx, substs)
+                let is_visible = adt.is_enum()
+                    || field.vis.is_accessible_from(cx.module, cx.tcx);
+                if is_visible {
+                    field.ty(cx.tcx, substs)
+                } else {
+                    // Treat all non-visible fields as nil. They
+                    // can't appear in any other pattern from
+                    // this match (because they are private),
+                    // so their type does not matter - but
+                    // we don't want to know they are
+                    // uninhabited.
+                    cx.tcx.mk_nil()
+                }
             }).collect()
         }
         _ => vec![],
index 6f33b4fad769f20d9e7d06b053a0a014fafbb5c3..e2b9f174ff0c200a6e174347d0e85cf5c7239fff 100644 (file)
@@ -124,7 +124,7 @@ fn report_inlining_errors(&self, patcx: PatternContext, pat_span: Span) {
                               "statics cannot be referenced in patterns");
                 }
                 PatternError::ConstEval(err) => {
-                    report_const_eval_err(self.tcx, &err, pat_span, "pattern").emit();
+                    report_const_eval_err(self.tcx, &err, pat_span, "pattern");
                 }
             }
         }
@@ -177,6 +177,31 @@ fn check_match(
             // Fourth, check for unreachable arms.
             check_arms(cx, &inlined_arms, source);
 
+            // Then, if the match has no arms, check whether the scrutinee
+            // is uninhabited.
+            let pat_ty = self.tables.node_id_to_type(scrut.id);
+            let module = self.tcx.hir.local_def_id(self.tcx.hir.get_module_parent(scrut.id));
+            if inlined_arms.is_empty() {
+                let scrutinee_is_uninhabited = if self.tcx.sess.features.borrow().never_type {
+                    pat_ty.is_uninhabited_from(module, self.tcx)
+                } else {
+                    self.conservative_is_uninhabited(pat_ty)
+                };
+                if !scrutinee_is_uninhabited {
+                    // We know the type is inhabited, so this must be wrong
+                    let mut err = create_e0004(self.tcx.sess, scrut.span,
+                                               format!("non-exhaustive patterns: type {} \
+                                                        is non-empty",
+                                                       pat_ty));
+                    span_help!(&mut err, scrut.span,
+                               "Please ensure that all possible cases are being handled; \
+                                possibly adding wildcards or more match arms.");
+                    err.emit();
+                }
+                // If the type *is* uninhabited, it's vacuously exhaustive
+                return;
+            }
+
             let matrix: Matrix = inlined_arms
                 .iter()
                 .filter(|&&(_, guard)| guard.is_none())
@@ -188,6 +213,15 @@ fn check_match(
         })
     }
 
+    fn conservative_is_uninhabited(&self, scrutinee_ty: Ty<'tcx>) -> bool {
+        // "rustc-1.0-style" uncontentious uninhabitableness check
+        match scrutinee_ty.sty {
+            ty::TyNever => true,
+            ty::TyAdt(def, _) => def.variants.is_empty(),
+            _ => false
+        }
+    }
+
     fn check_irrefutable(&self, pat: &Pat, is_fn_arg: bool) {
         let origin = if is_fn_arg {
             "function argument"
@@ -482,7 +516,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
 ///
 /// FIXME: this should be done by borrowck.
 fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
-    cx.tcx.infer_ctxt((cx.tables, cx.param_env.clone()), Reveal::NotSpecializable).enter(|infcx| {
+    cx.tcx.infer_ctxt((cx.tables, cx.param_env.clone()), Reveal::UserFacing).enter(|infcx| {
         let mut checker = MutationChecker {
             cx: cx,
         };
index 8c8b2b5da36dc65d7e13a787e7bf349c09f44000..9937cbbf8e10c3929293c99e1cf1bdb7d3d3d4b9 100644 (file)
@@ -576,22 +576,6 @@ enum Enum {
 https://doc.rust-lang.org/reference.html#ffi-attributes
 "##,
 
-
-E0306: r##"
-In an array type `[T; N]`, `N` is the number of elements in the array. This
-must be an unsigned integer. Erroneous code example:
-
-```compile_fail,E0306
-const X: [i32; true] = [0]; // error: expected `usize` for array length,
-                            //        found boolean
-```
-
-Working example:
-
-```
-const X: [i32; 1] = [0];
-```
-"##,
 }
 
 
index af4f63a05613eef94f20438b98343163cf7d0c35..c5d577ce571d40aceb664dd8d190a19f4efb709d 100644 (file)
@@ -11,7 +11,6 @@
 use rustc::middle::const_val::ConstVal::*;
 use rustc::middle::const_val::ConstVal;
 use self::ErrKind::*;
-use self::EvalHint::*;
 
 use rustc::hir::map as hir_map;
 use rustc::hir::map::blocks::FnLikeNode;
@@ -20,7 +19,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::util::IntTypeExt;
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Substs, Subst};
 use rustc::traits::Reveal;
 use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::DefIdMap;
@@ -28,8 +27,7 @@
 use graphviz::IntoCow;
 use syntax::ast;
 use rustc::hir::{self, Expr};
-use syntax::attr::IntType;
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 
 use std::borrow::Cow;
 use std::cmp::Ordering;
 use rustc_const_math::*;
 use rustc_errors::DiagnosticBuilder;
 
+macro_rules! signal {
+    ($e:expr, $exn:expr) => {
+        return Err(ConstEvalErr { span: $e.span, kind: $exn })
+    }
+}
+
 macro_rules! math {
     ($e:expr, $op:expr) => {
         match $op {
             Ok(val) => val,
-            Err(e) => signal!($e, Math(e)),
+            Err(e) => signal!($e, ErrKind::from(e)),
         }
     }
 }
 
 fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   variant_def: DefId)
-                                  -> Option<(&'tcx Expr, Option<&'a ty::TypeckTables<'tcx>>)> {
+                                  -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> {
     if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) {
         let enum_node_id = tcx.hir.get_parent(variant_node_id);
         if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) {
@@ -58,7 +62,7 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         return variant.node.disr_expr.map(|e| {
                             let def_id = tcx.hir.body_owner_def_id(e);
                             (&tcx.hir.body(e).value,
-                             tcx.tables.borrow().get(&def_id).cloned())
+                             tcx.item_tables(def_id))
                         });
                     }
                 }
@@ -75,55 +79,41 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 /// This generally happens in late/trans const evaluation.
 pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         def_id: DefId,
-                                        substs: Option<&'tcx Substs<'tcx>>)
+                                        substs: &'tcx Substs<'tcx>)
                                         -> Option<(&'tcx Expr,
-                                                   Option<&'a ty::TypeckTables<'tcx>>,
-                                                   Option<ty::Ty<'tcx>>)> {
+                                                   &'a ty::TypeckTables<'tcx>)> {
     if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
         match tcx.hir.find(node_id) {
             None => None,
             Some(hir_map::NodeItem(&hir::Item {
-                node: hir::ItemConst(ref ty, body), ..
+                node: hir::ItemConst(_, body), ..
             })) |
             Some(hir_map::NodeImplItem(&hir::ImplItem {
-                node: hir::ImplItemKind::Const(ref ty, body), ..
+                node: hir::ImplItemKind::Const(_, body), ..
             })) => {
                 Some((&tcx.hir.body(body).value,
-                      tcx.tables.borrow().get(&def_id).cloned(),
-                      tcx.ast_ty_to_prim_ty(ty)))
+                      tcx.item_tables(def_id)))
             }
             Some(hir_map::NodeTraitItem(ti)) => match ti.node {
-                hir::TraitItemKind::Const(ref ty, default) => {
-                    if let Some(substs) = substs {
-                        // If we have a trait item and the substitutions for it,
-                        // `resolve_trait_associated_const` will select an impl
-                        // or the default.
-                        let trait_id = tcx.hir.get_parent(node_id);
-                        let trait_id = tcx.hir.local_def_id(trait_id);
-                        let default_value = default.map(|body| {
-                            (&tcx.hir.body(body).value,
-                             tcx.tables.borrow().get(&def_id).cloned(),
-                             tcx.ast_ty_to_prim_ty(ty))
-                        });
-                        resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
-                    } else {
-                        // Technically, without knowing anything about the
-                        // expression that generates the obligation, we could
-                        // still return the default if there is one. However,
-                        // it's safer to return `None` than to return some value
-                        // that may differ from what you would get from
-                        // correctly selecting an impl.
-                        None
-                    }
+                hir::TraitItemKind::Const(_, default) => {
+                    // If we have a trait item and the substitutions for it,
+                    // `resolve_trait_associated_const` will select an impl
+                    // or the default.
+                    let trait_id = tcx.hir.get_parent(node_id);
+                    let trait_id = tcx.hir.local_def_id(trait_id);
+                    let default_value = default.map(|body| {
+                        (&tcx.hir.body(body).value,
+                            tcx.item_tables(def_id))
+                    });
+                    resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
                 }
                 _ => None
             },
             Some(_) => None
         }
     } else {
-        let expr_tables_ty = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
-            (&body.value, Some(tcx.item_tables(def_id)),
-             Some(tcx.sess.cstore.item_type(tcx, def_id)))
+        let expr_and_tables = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
+            (&body.value, tcx.item_tables(def_id))
         });
         match tcx.sess.cstore.describe_def(def_id) {
             Some(Def::AssociatedConst(_)) => {
@@ -133,30 +123,26 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 // trait-associated const if the caller gives us the
                 // substitutions for the reference to it.
                 if let Some(trait_id) = trait_id {
-                    if let Some(substs) = substs {
-                        resolve_trait_associated_const(tcx, def_id, expr_tables_ty,
-                                                       trait_id, substs)
-                    } else {
-                        None
-                    }
+                    resolve_trait_associated_const(tcx, def_id, expr_and_tables,
+                                                   trait_id, substs)
                 } else {
-                    expr_tables_ty
+                    expr_and_tables
                 }
             },
-            Some(Def::Const(..)) => expr_tables_ty,
+            Some(Def::Const(..)) => expr_and_tables,
             _ => None
         }
     }
 }
 
 fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                                   -> Option<(&'tcx hir::Body, Option<&'a ty::TypeckTables<'tcx>>)>
+                                   -> Option<(&'tcx hir::Body, &'a ty::TypeckTables<'tcx>)>
 {
     if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
         FnLikeNode::from_node(tcx.hir.get(node_id)).and_then(|fn_like| {
             if fn_like.constness() == hir::Constness::Const {
                 Some((tcx.hir.body(fn_like.body()),
-                      tcx.tables.borrow().get(&def_id).cloned()))
+                      tcx.item_tables(def_id)))
             } else {
                 None
             }
@@ -164,7 +150,7 @@ fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
     } else {
         if tcx.sess.cstore.is_const_fn(def_id) {
             tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
-                (body, Some(tcx.item_tables(def_id)))
+                (body, tcx.item_tables(def_id))
             })
         } else {
             None
@@ -172,7 +158,7 @@ fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
     }
 }
 
-pub fn report_const_eval_err<'a, 'tcx>(
+fn build_const_eval_err<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     err: &ConstEvalErr,
     primary_span: Span,
@@ -189,6 +175,18 @@ pub fn report_const_eval_err<'a, 'tcx>(
     diag
 }
 
+pub fn report_const_eval_err<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    err: &ConstEvalErr,
+    primary_span: Span,
+    primary_kind: &str)
+{
+    if let TypeckError = err.kind {
+        return;
+    }
+    build_const_eval_err(tcx, err, primary_span, primary_kind).emit();
+}
+
 pub fn fatal_const_eval_err<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     err: &ConstEvalErr,
@@ -196,7 +194,7 @@ pub fn fatal_const_eval_err<'a, 'tcx>(
     primary_kind: &str)
     -> !
 {
-    report_const_eval_err(tcx, err, primary_span, primary_kind).emit();
+    report_const_eval_err(tcx, err, primary_span, primary_kind);
     tcx.sess.abort_if_errors();
     unreachable!()
 }
@@ -222,69 +220,58 @@ pub fn note_const_eval_err<'a, 'tcx>(
 
 pub struct ConstContext<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    tables: Option<&'a ty::TypeckTables<'tcx>>,
-    fn_args: Option<DefIdMap<ConstVal>>
+    tables: &'a ty::TypeckTables<'tcx>,
+    substs: &'tcx Substs<'tcx>,
+    fn_args: Option<DefIdMap<ConstVal<'tcx>>>
 }
 
 impl<'a, 'tcx> ConstContext<'a, 'tcx> {
     pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body: hir::BodyId) -> Self {
         let def_id = tcx.hir.body_owner_def_id(body);
-        ConstContext {
-            tcx: tcx,
-            tables: tcx.tables.borrow().get(&def_id).cloned(),
-            fn_args: None
-        }
+        ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
+        ConstContext::with_tables(tcx, tcx.item_tables(def_id))
     }
 
     pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self {
         ConstContext {
             tcx: tcx,
-            tables: Some(tables),
+            tables: tables,
+            substs: tcx.intern_substs(&[]),
             fn_args: None
         }
     }
 
     /// Evaluate a constant expression in a context where the expression isn't
-    /// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
-    /// but a few places need to evaluate constants during type-checking, like
-    /// computing the length of an array. (See also the FIXME above EvalHint.)
-    pub fn eval(&self, e: &Expr, ty_hint: EvalHint<'tcx>) -> EvalResult {
-        eval_const_expr_partial(self, e, ty_hint)
+    /// guaranteed to be evaluatable.
+    pub fn eval(&self, e: &Expr) -> EvalResult<'tcx> {
+        if self.tables.tainted_by_errors {
+            signal!(e, TypeckError);
+        }
+        eval_const_expr_partial(self, e)
     }
 }
 
 #[derive(Clone, Debug)]
-pub struct ConstEvalErr {
+pub struct ConstEvalErr<'tcx> {
     pub span: Span,
-    pub kind: ErrKind,
+    pub kind: ErrKind<'tcx>,
 }
 
 #[derive(Clone, Debug)]
-pub enum ErrKind {
+pub enum ErrKind<'tcx> {
     CannotCast,
-    CannotCastTo(&'static str),
-    InvalidOpForInts(hir::BinOp_),
-    InvalidOpForBools(hir::BinOp_),
-    InvalidOpForFloats(hir::BinOp_),
-    InvalidOpForIntUint(hir::BinOp_),
-    InvalidOpForUintInt(hir::BinOp_),
-    NegateOn(ConstVal),
-    NotOn(ConstVal),
-    CallOn(ConstVal),
-
     MissingStructField,
+    NegateOn(ConstVal<'tcx>),
+    NotOn(ConstVal<'tcx>),
+    CallOn(ConstVal<'tcx>),
+
     NonConstPath,
     UnimplementedConstVal(&'static str),
-    UnresolvedPath,
     ExpectedConstTuple,
     ExpectedConstStruct,
-    TupleIndexOutOfBounds,
     IndexedNonVec,
-    IndexNegative,
-    IndexNotInt,
+    IndexNotUsize,
     IndexOutOfBounds { len: u64, index: u64 },
-    RepeatCountNotNatural,
-    RepeatCountNotInt,
 
     MiscBinaryOp,
     MiscCatchAll,
@@ -292,18 +279,17 @@ pub enum ErrKind {
     IndexOpFeatureGated,
     Math(ConstMathErr),
 
-    IntermediateUnsignedNegative,
-    /// Expected, Got
-    TypeMismatch(String, ConstInt),
+    ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>),
 
-    BadType(ConstVal),
-    ErroneousReferencedConstant(Box<ConstEvalErr>),
-    CharCast(ConstInt),
+    TypeckError
 }
 
-impl From<ConstMathErr> for ErrKind {
-    fn from(err: ConstMathErr) -> ErrKind {
-        Math(err)
+impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
+    fn from(err: ConstMathErr) -> ErrKind<'tcx> {
+        match err {
+            ConstMathErr::UnsignedNegation => TypeckError,
+            _ => Math(err)
+        }
     }
 }
 
@@ -321,7 +307,7 @@ pub fn into_oneline(self) -> Cow<'a, str> {
     }
 }
 
-impl ConstEvalErr {
+impl<'tcx> ConstEvalErr<'tcx> {
     pub fn description(&self) -> ConstEvalErrDescription {
         use self::ErrKind::*;
         use self::ConstEvalErrDescription::*;
@@ -335,12 +321,6 @@ macro_rules! simple {
 
         match self.kind {
             CannotCast => simple!("can't cast this type"),
-            CannotCastTo(s) => simple!("can't cast this type to {}", s),
-            InvalidOpForInts(_) =>  simple!("can't do this op on integrals"),
-            InvalidOpForBools(_) =>  simple!("can't do this op on bools"),
-            InvalidOpForFloats(_) => simple!("can't do this op on floats"),
-            InvalidOpForIntUint(..) => simple!("can't do this op on an isize and usize"),
-            InvalidOpForUintInt(..) => simple!("can't do this op on a usize and isize"),
             NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
             NotOn(ref const_val) => simple!("not on {}", const_val.description()),
             CallOn(ref const_val) => simple!("call on {}", const_val.description()),
@@ -349,111 +329,42 @@ macro_rules! simple {
             NonConstPath        => simple!("non-constant path in constant expression"),
             UnimplementedConstVal(what) =>
                 simple!("unimplemented constant expression: {}", what),
-            UnresolvedPath => simple!("unresolved path in constant expression"),
             ExpectedConstTuple => simple!("expected constant tuple"),
             ExpectedConstStruct => simple!("expected constant struct"),
-            TupleIndexOutOfBounds => simple!("tuple index out of bounds"),
             IndexedNonVec => simple!("indexing is only supported for arrays"),
-            IndexNegative => simple!("indices must be non-negative integers"),
-            IndexNotInt => simple!("indices must be integers"),
+            IndexNotUsize => simple!("indices must be of type `usize`"),
             IndexOutOfBounds { len, index } => {
                 simple!("index out of bounds: the len is {} but the index is {}",
                         len, index)
             }
-            RepeatCountNotNatural => simple!("repeat count must be a natural number"),
-            RepeatCountNotInt => simple!("repeat count must be integers"),
 
             MiscBinaryOp => simple!("bad operands for binary"),
             MiscCatchAll => simple!("unsupported constant expr"),
             IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
             Math(ref err) => Simple(err.description().into_cow()),
 
-            IntermediateUnsignedNegative => simple!(
-                "during the computation of an unsigned a negative \
-                 number was encountered. This is most likely a bug in\
-                 the constant evaluator"),
-
-            TypeMismatch(ref expected, ref got) => {
-                simple!("expected {}, found {}", expected, got.description())
-            },
-            BadType(ref i) => simple!("value of wrong type: {:?}", i),
             ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
-            CharCast(ref got) => {
-                simple!("only `u8` can be cast as `char`, not `{}`", got.description())
-            },
-        }
-    }
-}
-
-pub type EvalResult = Result<ConstVal, ConstEvalErr>;
-pub type CastResult = Result<ConstVal, ErrKind>;
-
-// FIXME: Long-term, this enum should go away: trying to evaluate
-// an expression which hasn't been type-checked is a recipe for
-// disaster.  That said, it's not clear how to fix ast_ty_to_ty
-// to avoid the ordering issue.
-
-/// Hint to determine how to evaluate constant expressions which
-/// might not be type-checked.
-#[derive(Copy, Clone, Debug)]
-pub enum EvalHint<'tcx> {
-    /// We have a type-checked expression.
-    ExprTypeChecked,
-    /// We have an expression which hasn't been type-checked, but we have
-    /// an idea of what the type will be because of the context. For example,
-    /// the length of an array is always `usize`. (This is referred to as
-    /// a hint because it isn't guaranteed to be consistent with what
-    /// type-checking would compute.)
-    UncheckedExprHint(Ty<'tcx>),
-    /// We have an expression which has not yet been type-checked, and
-    /// and we have no clue what the type will be.
-    UncheckedExprNoHint,
-}
 
-impl<'tcx> EvalHint<'tcx> {
-    fn erase_hint(&self) -> EvalHint<'tcx> {
-        match *self {
-            ExprTypeChecked => ExprTypeChecked,
-            UncheckedExprHint(_) | UncheckedExprNoHint => UncheckedExprNoHint,
-        }
-    }
-    fn checked_or(&self, ty: Ty<'tcx>) -> EvalHint<'tcx> {
-        match *self {
-            ExprTypeChecked => ExprTypeChecked,
-            _ => UncheckedExprHint(ty),
+            TypeckError => simple!("type-checking failed"),
         }
     }
 }
 
-macro_rules! signal {
-    ($e:expr, $exn:expr) => {
-        return Err(ConstEvalErr { span: $e.span, kind: $exn })
-    }
-}
+pub type EvalResult<'tcx> = Result<ConstVal<'tcx>, ConstEvalErr<'tcx>>;
+pub type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
 
 fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
-                                     e: &Expr,
-                                     ty_hint: EvalHint<'tcx>) -> EvalResult {
+                                     e: &Expr) -> EvalResult<'tcx> {
     let tcx = cx.tcx;
-    // Try to compute the type of the expression based on the EvalHint.
-    // (See also the definition of EvalHint, and the FIXME above EvalHint.)
-    let ety = match ty_hint {
-        ExprTypeChecked => {
-            // After type-checking, expr_ty is guaranteed to succeed.
-            cx.tables.map(|tables| tables.expr_ty(e))
-        }
-        UncheckedExprHint(ty) => {
-            // Use the type hint; it's not guaranteed to be right, but it's
-            // usually good enough.
-            Some(ty)
-        }
-        UncheckedExprNoHint => {
-            // This expression might not be type-checked, and we have no hint.
-            // Try to query the context for a type anyway; we might get lucky
-            // (for example, if the expression was imported from another crate).
-            cx.tables.and_then(|tables| tables.expr_ty_opt(e))
-        }
+    let ety = cx.tables.expr_ty(e);
+
+    // Avoid applying substitutions if they're empty, that'd ICE.
+    let ety = if cx.substs.is_empty() {
+        ety
+    } else {
+        ety.subst(tcx, cx.substs)
     };
+
     let result = match e.node {
       hir::ExprUnary(hir::UnNeg, ref inner) => {
         // unary neg literals already got their sign during creation
@@ -465,28 +376,28 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
             const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
             const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
             const I128_OVERFLOW: u128 = i128::min_value() as u128;
-            match (&lit.node, ety.map(|t| &t.sty)) {
-                (&LitKind::Int(I8_OVERFLOW, _), Some(&ty::TyInt(IntTy::I8))) |
+            match (&lit.node, &ety.sty) {
+                (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
                 (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
                     return Ok(Integral(I8(i8::min_value())))
                 },
-                (&LitKind::Int(I16_OVERFLOW, _), Some(&ty::TyInt(IntTy::I16))) |
+                (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
                 (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
                     return Ok(Integral(I16(i16::min_value())))
                 },
-                (&LitKind::Int(I32_OVERFLOW, _), Some(&ty::TyInt(IntTy::I32))) |
+                (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
                 (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
                     return Ok(Integral(I32(i32::min_value())))
                 },
-                (&LitKind::Int(I64_OVERFLOW, _), Some(&ty::TyInt(IntTy::I64))) |
+                (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
                 (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
                     return Ok(Integral(I64(i64::min_value())))
                 },
-                (&LitKind::Int(I128_OVERFLOW, _), Some(&ty::TyInt(IntTy::I128))) |
+                (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
                 (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
                     return Ok(Integral(I128(i128::min_value())))
                 },
-                (&LitKind::Int(n, _), Some(&ty::TyInt(IntTy::Is))) |
+                (&LitKind::Int(n, _), &ty::TyInt(IntTy::Is)) |
                 (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
                     match tcx.sess.target.int_type {
                         IntTy::I16 => if n == I16_OVERFLOW {
@@ -498,20 +409,20 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                         IntTy::I64 => if n == I64_OVERFLOW {
                             return Ok(Integral(Isize(Is64(i64::min_value()))));
                         },
-                        _ => bug!(),
+                        _ => span_bug!(e.span, "typeck error")
                     }
                 },
                 _ => {},
             }
         }
-        match cx.eval(inner, ty_hint)? {
+        match cx.eval(inner)? {
           Float(f) => Float(-f),
           Integral(i) => Integral(math!(e, -i)),
           const_val => signal!(e, NegateOn(const_val)),
         }
       }
       hir::ExprUnary(hir::UnNot, ref inner) => {
-        match cx.eval(inner, ty_hint)? {
+        match cx.eval(inner)? {
           Integral(i) => Integral(math!(e, !i)),
           Bool(b) => Bool(!b),
           const_val => signal!(e, NotOn(const_val)),
@@ -519,16 +430,11 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
       }
       hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
       hir::ExprBinary(op, ref a, ref b) => {
-        let b_ty = match op.node {
-            hir::BiShl | hir::BiShr => ty_hint.erase_hint(),
-            _ => ty_hint
-        };
         // technically, if we don't have type hints, but integral eval
         // gives us a type through a type-suffix, cast or const def type
         // we need to re-eval the other value of the BinOp if it was
         // not inferred
-        match (cx.eval(a, ty_hint)?,
-               cx.eval(b, b_ty)?) {
+        match (cx.eval(a)?, cx.eval(b)?) {
           (Float(a), Float(b)) => {
             use std::cmp::Ordering::*;
             match op.node {
@@ -543,7 +449,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
               hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
               hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
               hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
-              _ => signal!(e, InvalidOpForFloats(op.node)),
+              _ => span_bug!(e.span, "typeck error"),
             }
           }
           (Integral(a), Integral(b)) => {
@@ -565,7 +471,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
               hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
               hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
               hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
-              _ => signal!(e, InvalidOpForInts(op.node)),
+              _ => span_bug!(e.span, "typeck error"),
             }
           }
           (Bool(a), Bool(b)) => {
@@ -581,90 +487,57 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
               hir::BiLe => a <= b,
               hir::BiGe => a >= b,
               hir::BiGt => a > b,
-              _ => signal!(e, InvalidOpForBools(op.node)),
+              _ => span_bug!(e.span, "typeck error"),
              })
           }
 
           _ => signal!(e, MiscBinaryOp),
         }
       }
-      hir::ExprCast(ref base, ref target_ty) => {
-        let ety = tcx.ast_ty_to_prim_ty(&target_ty).or(ety)
-                .unwrap_or_else(|| {
-                    tcx.sess.span_fatal(target_ty.span,
-                                        "target type not found for const cast")
-                });
-
-        let base_hint = if let ExprTypeChecked = ty_hint {
-            ExprTypeChecked
-        } else {
-            match cx.tables.and_then(|tables| tables.expr_ty_opt(&base)) {
-                Some(t) => UncheckedExprHint(t),
-                None => ty_hint
-            }
-        };
-
-        let val = match cx.eval(base, base_hint) {
-            Ok(val) => val,
-            Err(ConstEvalErr { kind: ErroneousReferencedConstant(
-                box ConstEvalErr { kind: TypeMismatch(_, val), .. }), .. }) |
-            Err(ConstEvalErr { kind: TypeMismatch(_, val), .. }) => {
-                // Something like `5i8 as usize` doesn't need a type hint for the base
-                // instead take the type hint from the inner value
-                let hint = match val.int_type() {
-                    Some(IntType::UnsignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_uint(ty)),
-                    Some(IntType::SignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_int(ty)),
-                    // we had a type hint, so we can't have an unknown type
-                    None => bug!(),
-                };
-                cx.eval(base, hint)?
-            },
-            Err(e) => return Err(e),
-        };
-        match cast_const(tcx, val, ety) {
+      hir::ExprCast(ref base, _) => {
+        match cast_const(tcx, cx.eval(base)?, ety) {
             Ok(val) => val,
             Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
         }
       }
       hir::ExprPath(ref qpath) => {
-          let def = cx.tables.map(|tables| tables.qpath_def(qpath, e.id)).unwrap_or_else(|| {
-            // There are no tables so we can only handle already-resolved HIR.
-            match *qpath {
-                hir::QPath::Resolved(_, ref path) => path.def,
-                hir::QPath::TypeRelative(..) => Def::Err
-            }
-          });
-          match def {
+        let substs = cx.tables.node_id_item_substs(e.id)
+            .unwrap_or_else(|| tcx.intern_substs(&[]));
+
+        // Avoid applying substitutions if they're empty, that'd ICE.
+        let substs = if cx.substs.is_empty() {
+            substs
+        } else {
+            substs.subst(tcx, cx.substs)
+        };
+
+          match cx.tables.qpath_def(qpath, e.id) {
               Def::Const(def_id) |
               Def::AssociatedConst(def_id) => {
-                  let substs = if let ExprTypeChecked = ty_hint {
-                      Some(cx.tables.and_then(|tables| tables.node_id_item_substs(e.id))
-                        .unwrap_or_else(|| tcx.intern_substs(&[])))
-                  } else {
-                      None
-                  };
-                  if let Some((expr, tables, ty)) = lookup_const_by_id(tcx, def_id, substs) {
-                      let item_hint = match ty {
-                          Some(ty) => ty_hint.checked_or(ty),
-                          None => ty_hint,
-                      };
-                      let cx = ConstContext { tcx: tcx, tables: tables, fn_args: None };
-                      match cx.eval(expr, item_hint) {
+                  if let Some((expr, tables)) = lookup_const_by_id(tcx, def_id, substs) {
+                      let cx = ConstContext::with_tables(tcx, tables);
+                      match cx.eval(expr) {
                           Ok(val) => val,
+                          Err(ConstEvalErr { kind: TypeckError, .. }) => {
+                              signal!(e, TypeckError);
+                          }
                           Err(err) => {
                               debug!("bad reference: {:?}, {:?}", err.description(), err.span);
                               signal!(e, ErroneousReferencedConstant(box err))
                           },
                       }
                   } else {
-                      signal!(e, NonConstPath);
+                      signal!(e, TypeckError);
                   }
               },
               Def::VariantCtor(variant_def, ..) => {
                   if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) {
-                      let cx = ConstContext { tcx: tcx, tables: tables, fn_args: None };
-                      match cx.eval(expr, ty_hint) {
+                      let cx = ConstContext::with_tables(tcx, tables);
+                      match cx.eval(expr) {
                           Ok(val) => val,
+                          Err(ConstEvalErr { kind: TypeckError, .. }) => {
+                              signal!(e, TypeckError);
+                          }
                           Err(err) => {
                               debug!("bad reference: {:?}, {:?}", err.description(), err.span);
                               signal!(e, ErroneousReferencedConstant(box err))
@@ -685,16 +558,14 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
                       signal!(e, NonConstPath);
                   }
               },
-              Def::Method(id) | Def::Fn(id) => Function(id),
-              Def::Err => signal!(e, UnresolvedPath),
+              Def::Method(id) | Def::Fn(id) => Function(id, substs),
+              Def::Err => span_bug!(e.span, "typeck error"),
               _ => signal!(e, NonConstPath),
           }
       }
       hir::ExprCall(ref callee, ref args) => {
-          let sub_ty_hint = ty_hint.erase_hint();
-          let callee_val = cx.eval(callee, sub_ty_hint)?;
-          let did = match callee_val {
-              Function(did) => did,
+          let (did, substs) = match cx.eval(callee)? {
+              Function(did, substs) => (did, substs),
               Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
               callee => signal!(e, CallOn(callee)),
           };
@@ -711,8 +582,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
 
           let mut call_args = DefIdMap();
           for (arg, arg_expr) in arg_defs.into_iter().zip(args.iter()) {
-              let arg_hint = ty_hint.erase_hint();
-              let arg_val = cx.eval(arg_expr, arg_hint)?;
+              let arg_val = cx.eval(arg_expr)?;
               debug!("const call arg: {:?}", arg);
               if let Some(def_id) = arg {
                 assert!(call_args.insert(def_id, arg_val).is_none());
@@ -722,9 +592,10 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           let callee_cx = ConstContext {
             tcx: tcx,
             tables: tables,
+            substs: substs,
             fn_args: Some(call_args)
           };
-          callee_cx.eval(&body.value, ty_hint)?
+          callee_cx.eval(&body.value)?
       },
       hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
           Ok(val) => val,
@@ -732,32 +603,27 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
       },
       hir::ExprBlock(ref block) => {
         match block.expr {
-            Some(ref expr) => cx.eval(expr, ty_hint)?,
-            None => signal!(e, UnimplementedConstVal("empty block")),
+            Some(ref expr) => cx.eval(expr)?,
+            None => Tuple(vec![]),
         }
       }
-      hir::ExprType(ref e, _) => cx.eval(e, ty_hint)?,
+      hir::ExprType(ref e, _) => cx.eval(e)?,
       hir::ExprTup(ref fields) => {
-        let field_hint = ty_hint.erase_hint();
-        Tuple(fields.iter().map(|e| cx.eval(e, field_hint)).collect::<Result<_, _>>()?)
+        Tuple(fields.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
       }
       hir::ExprStruct(_, ref fields, _) => {
-        let field_hint = ty_hint.erase_hint();
         Struct(fields.iter().map(|f| {
-            cx.eval(&f.expr, field_hint).map(|v| (f.name.node, v))
+            cx.eval(&f.expr).map(|v| (f.name.node, v))
         }).collect::<Result<_, _>>()?)
       }
       hir::ExprIndex(ref arr, ref idx) => {
         if !tcx.sess.features.borrow().const_indexing {
             signal!(e, IndexOpFeatureGated);
         }
-        let arr_hint = ty_hint.erase_hint();
-        let arr = cx.eval(arr, arr_hint)?;
-        let idx_hint = ty_hint.checked_or(tcx.types.usize);
-        let idx = match cx.eval(idx, idx_hint)? {
+        let arr = cx.eval(arr)?;
+        let idx = match cx.eval(idx)? {
             Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
-            Integral(_) => bug!(),
-            _ => signal!(idx, IndexNotInt),
+            _ => signal!(idx, IndexNotUsize),
         };
         assert_eq!(idx as usize as u64, idx);
         match arr {
@@ -787,45 +653,25 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
         }
       }
       hir::ExprArray(ref v) => {
-        let elem_hint = ty_hint.erase_hint();
-        Array(v.iter().map(|e| cx.eval(e, elem_hint)).collect::<Result<_, _>>()?)
+        Array(v.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
       }
-      hir::ExprRepeat(ref elem, count) => {
-          let elem_hint = ty_hint.erase_hint();
-          let len_hint = ty_hint.checked_or(tcx.types.usize);
-          let n = if let Some(ty) = ety {
-            // For cross-crate constants, we have the type already,
-            // but not the body for `count`, so use the type.
-            match ty.sty {
-                ty::TyArray(_, n) => n as u64,
-                _ => bug!()
-            }
-          } else {
-            let n = &tcx.hir.body(count).value;
-            match ConstContext::new(tcx, count).eval(n, len_hint)? {
-                Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
-                Integral(_) => signal!(e, RepeatCountNotNatural),
-                _ => signal!(e, RepeatCountNotInt),
-            }
+      hir::ExprRepeat(ref elem, _) => {
+          let n = match ety.sty {
+            ty::TyArray(_, n) => n as u64,
+            _ => span_bug!(e.span, "typeck error")
           };
-          Repeat(Box::new(cx.eval(elem, elem_hint)?), n)
+          Repeat(Box::new(cx.eval(elem)?), n)
       },
       hir::ExprTupField(ref base, index) => {
-        let base_hint = ty_hint.erase_hint();
-        let c = cx.eval(base, base_hint)?;
+        let c = cx.eval(base)?;
         if let Tuple(ref fields) = c {
-            if let Some(elem) = fields.get(index.node) {
-                elem.clone()
-            } else {
-                signal!(e, TupleIndexOutOfBounds);
-            }
+            fields[index.node].clone()
         } else {
             signal!(base, ExpectedConstTuple);
         }
       }
       hir::ExprField(ref base, field_name) => {
-        let base_hint = ty_hint.erase_hint();
-        let c = cx.eval(base, base_hint)?;
+        let c = cx.eval(base)?;
         if let Struct(ref fields) = c {
             if let Some(f) = fields.get(&field_name.node) {
                 f.clone()
@@ -840,90 +686,23 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
       _ => signal!(e, MiscCatchAll)
     };
 
-    match (ety.map(|t| &t.sty), result) {
-        (Some(ref ty_hint), Integral(i)) => match infer(i, tcx, ty_hint) {
-            Ok(inferred) => Ok(Integral(inferred)),
-            Err(err) => signal!(e, err),
-        },
-        (_, result) => Ok(result),
-    }
-}
-
-fn infer<'a, 'tcx>(i: ConstInt,
-                   tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                   ty_hint: &ty::TypeVariants<'tcx>)
-                   -> Result<ConstInt, ErrKind> {
-    use syntax::ast::*;
-
-    match (ty_hint, i) {
-        (&ty::TyInt(IntTy::I8), result @ I8(_)) => Ok(result),
-        (&ty::TyInt(IntTy::I16), result @ I16(_)) => Ok(result),
-        (&ty::TyInt(IntTy::I32), result @ I32(_)) => Ok(result),
-        (&ty::TyInt(IntTy::I64), result @ I64(_)) => Ok(result),
-        (&ty::TyInt(IntTy::I128), result @ I128(_)) => Ok(result),
-        (&ty::TyInt(IntTy::Is), result @ Isize(_)) => Ok(result),
-
-        (&ty::TyUint(UintTy::U8), result @ U8(_)) => Ok(result),
-        (&ty::TyUint(UintTy::U16), result @ U16(_)) => Ok(result),
-        (&ty::TyUint(UintTy::U32), result @ U32(_)) => Ok(result),
-        (&ty::TyUint(UintTy::U64), result @ U64(_)) => Ok(result),
-        (&ty::TyUint(UintTy::U128), result @ U128(_)) => Ok(result),
-        (&ty::TyUint(UintTy::Us), result @ Usize(_)) => Ok(result),
-
-        (&ty::TyInt(IntTy::I8), Infer(i)) => Ok(I8(i as i128 as i8)),
-        (&ty::TyInt(IntTy::I16), Infer(i)) => Ok(I16(i as i128 as i16)),
-        (&ty::TyInt(IntTy::I32), Infer(i)) => Ok(I32(i as i128 as i32)),
-        (&ty::TyInt(IntTy::I64), Infer(i)) => Ok(I64(i as i128 as i64)),
-        (&ty::TyInt(IntTy::I128), Infer(i)) => Ok(I128(i as i128)),
-        (&ty::TyInt(IntTy::Is), Infer(i)) => {
-            Ok(Isize(ConstIsize::new_truncating(i as i128, tcx.sess.target.int_type)))
-        },
-
-        (&ty::TyInt(IntTy::I8), InferSigned(i)) => Ok(I8(i as i8)),
-        (&ty::TyInt(IntTy::I16), InferSigned(i)) => Ok(I16(i as i16)),
-        (&ty::TyInt(IntTy::I32), InferSigned(i)) => Ok(I32(i as i32)),
-        (&ty::TyInt(IntTy::I64), InferSigned(i)) => Ok(I64(i as i64)),
-        (&ty::TyInt(IntTy::I128), InferSigned(i)) => Ok(I128(i)),
-        (&ty::TyInt(IntTy::Is), InferSigned(i)) => {
-            Ok(Isize(ConstIsize::new_truncating(i, tcx.sess.target.int_type)))
-        },
-
-        (&ty::TyUint(UintTy::U8), Infer(i)) => Ok(U8(i as u8)),
-        (&ty::TyUint(UintTy::U16), Infer(i)) => Ok(U16(i as u16)),
-        (&ty::TyUint(UintTy::U32), Infer(i)) => Ok(U32(i as u32)),
-        (&ty::TyUint(UintTy::U64), Infer(i)) => Ok(U64(i as u64)),
-        (&ty::TyUint(UintTy::U128), Infer(i)) => Ok(U128(i)),
-        (&ty::TyUint(UintTy::Us), Infer(i)) => {
-            Ok(Usize(ConstUsize::new_truncating(i, tcx.sess.target.uint_type)))
-        },
-        (&ty::TyUint(_), InferSigned(_)) => Err(IntermediateUnsignedNegative),
-
-        (&ty::TyInt(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
-        (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
-
-        (&ty::TyAdt(adt, _), i) if adt.is_enum() => {
-            let hints = tcx.lookup_repr_hints(adt.did);
-            let int_ty = tcx.enum_repr_type(hints.iter().next());
-            infer(i, tcx, &int_ty.to_ty(tcx).sty)
-        },
-        (_, i) => Err(BadType(ConstVal::Integral(i))),
-    }
+    Ok(result)
 }
 
 fn resolve_trait_associated_const<'a, 'tcx: 'a>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     trait_item_id: DefId,
-    default_value: Option<(&'tcx Expr, Option<&'a ty::TypeckTables<'tcx>>, Option<ty::Ty<'tcx>>)>,
+    default_value: Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>,
     trait_id: DefId,
     rcvr_substs: &'tcx Substs<'tcx>
-) -> Option<(&'tcx Expr, Option<&'a ty::TypeckTables<'tcx>>, Option<ty::Ty<'tcx>>)>
+) -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>
 {
     let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
     debug!("resolve_trait_associated_const: trait_ref={:?}",
            trait_ref);
 
     tcx.populate_implementations_for_trait_if_necessary(trait_id);
-    tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
+    tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
         let mut selcx = traits::SelectionContext::new(&infcx);
         let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
                                                  trait_ref.to_poly_trait_predicate());
@@ -951,7 +730,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(
                 let ac = tcx.associated_items(impl_data.impl_def_id)
                     .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
                 match ac {
-                    Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
+                    Some(ic) => lookup_const_by_id(tcx, ic.def_id, Substs::empty()),
                     None => default_value,
                 }
             }
@@ -962,7 +741,10 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(
     })
 }
 
-fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::Ty) -> CastResult {
+fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            val: ConstInt,
+                            ty: Ty<'tcx>)
+                            -> CastResult<'tcx> {
     let v = val.to_u128_unchecked();
     match ty.sty {
         ty::TyBool if v == 0 => Ok(Bool(false)),
@@ -983,42 +765,31 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::
         ty::TyUint(ast::UintTy::Us) => {
             Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type))))
         },
-        ty::TyFloat(ast::FloatTy::F64) => match val.erase_type() {
-            Infer(u) => Ok(Float(F64(u as f64))),
-            InferSigned(i) => Ok(Float(F64(i as f64))),
-            _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"),
-        },
-        ty::TyFloat(ast::FloatTy::F32) => match val.erase_type() {
-            Infer(u) => Ok(Float(F32(u as f32))),
-            InferSigned(i) => Ok(Float(F32(i as f32))),
-            _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"),
-        },
+        ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(val.to_f64()))),
+        ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(val.to_f32()))),
         ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
-        ty::TyChar => match infer(val, tcx, &ty::TyUint(ast::UintTy::U8)) {
-            Ok(U8(u)) => Ok(Char(u as char)),
-            // can only occur before typeck, typeck blocks `T as char` for `T` != `u8`
-            _ => Err(CharCast(val)),
+        ty::TyChar => match val {
+            U8(u) => Ok(Char(u as char)),
+            _ => bug!(),
         },
-        _ => Err(CannotCast),
+        _ => bug!(),
     }
 }
 
 fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                               val: ConstFloat,
-                              ty: ty::Ty) -> CastResult {
+                              ty: Ty<'tcx>) -> CastResult<'tcx> {
     match ty.sty {
         ty::TyInt(_) | ty::TyUint(_) => {
             let i = match val {
-                F32(f) if f >= 0.0 => Infer(f as u128),
-                FInfer { f64: f, .. } |
-                F64(f) if f >= 0.0 => Infer(f as u128),
+                F32(f) if f >= 0.0 => U128(f as u128),
+                F64(f) if f >= 0.0 => U128(f as u128),
 
-                F32(f) => InferSigned(f as i128),
-                FInfer { f64: f, .. } |
-                F64(f) => InferSigned(f as i128)
+                F32(f) => I128(f as i128),
+                F64(f) => I128(f as i128)
             };
 
-            if let (InferSigned(_), &ty::TyUint(_)) = (i, &ty.sty) {
+            if let (I128(_), &ty::TyUint(_)) = (i, &ty.sty) {
                 return Err(CannotCast);
             }
 
@@ -1026,23 +797,26 @@ fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
         ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(match val {
             F32(f) => f as f64,
-            FInfer { f64: f, .. } | F64(f) => f
+            F64(f) => f
         }))),
         ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(match val {
             F64(f) => f as f32,
-            FInfer { f32: f, .. } | F32(f) => f
+            F32(f) => f
         }))),
         _ => Err(CannotCast),
     }
 }
 
-fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult {
+fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        val: ConstVal<'tcx>,
+                        ty: Ty<'tcx>)
+                        -> CastResult<'tcx> {
     match val {
         Integral(i) => cast_const_int(tcx, i, ty),
-        Bool(b) => cast_const_int(tcx, Infer(b as u128), ty),
+        Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
         Float(f) => cast_const_float(tcx, f, ty),
-        Char(c) => cast_const_int(tcx, Infer(c as u128), ty),
-        Function(_) => Err(UnimplementedConstVal("casting fn pointers")),
+        Char(c) => cast_const_int(tcx, U32(c as u32), ty),
+        Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
         ByteStr(b) => match ty.sty {
             ty::TyRawPtr(_) => {
                 Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
@@ -1070,67 +844,56 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty)
 
 fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          ty_hint: Option<Ty<'tcx>>)
-                          -> Result<ConstVal, ErrKind> {
+                          mut ty: Ty<'tcx>)
+                          -> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
     use syntax::ast::*;
     use syntax::ast::LitIntType::*;
+
+    if let ty::TyAdt(adt, _) = ty.sty {
+        if adt.is_enum() {
+            ty = adt.repr.discr_type().to_ty(tcx)
+        }
+    }
+
     match *lit {
         LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
         LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
         LitKind::Byte(n) => Ok(Integral(U8(n))),
-        LitKind::Int(n, Signed(ity)) => {
-            infer(InferSigned(n as i128), tcx, &ty::TyInt(ity)).map(Integral)
-        },
-
-        // FIXME: this should become u128.
-        LitKind::Int(n, Unsuffixed) => {
-            match ty_hint.map(|t| &t.sty) {
-                Some(&ty::TyInt(ity)) => {
-                    infer(InferSigned(n as i128), tcx, &ty::TyInt(ity)).map(Integral)
-                },
-                Some(&ty::TyUint(uty)) => {
-                    infer(Infer(n as u128), tcx, &ty::TyUint(uty)).map(Integral)
-                },
-                None => Ok(Integral(Infer(n as u128))),
-                Some(&ty::TyAdt(adt, _)) => {
-                    let hints = tcx.lookup_repr_hints(adt.did);
-                    let int_ty = tcx.enum_repr_type(hints.iter().next());
-                    infer(Infer(n as u128), tcx, &int_ty.to_ty(tcx).sty).map(Integral)
-                },
-                Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit),
+        LitKind::Int(n, hint) => {
+            match (&ty.sty, hint) {
+                (&ty::TyInt(ity), _) |
+                (_, Signed(ity)) => {
+                    Ok(Integral(ConstInt::new_signed_truncating(n as i128,
+                        ity, tcx.sess.target.int_type)))
+                }
+                (&ty::TyUint(uty), _) |
+                (_, Unsigned(uty)) => {
+                    Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
+                        uty, tcx.sess.target.uint_type)))
+                }
+                _ => bug!()
             }
-        },
-        LitKind::Int(n, Unsigned(ity)) => {
-            infer(Infer(n as u128), tcx, &ty::TyUint(ity)).map(Integral)
-        },
-
+        }
         LitKind::Float(n, fty) => {
-            parse_float(&n.as_str(), Some(fty)).map(Float)
+            parse_float(&n.as_str(), fty).map(Float)
         }
         LitKind::FloatUnsuffixed(n) => {
-            let fty_hint = match ty_hint.map(|t| &t.sty) {
-                Some(&ty::TyFloat(fty)) => Some(fty),
-                _ => None
+            let fty = match ty.sty {
+                ty::TyFloat(fty) => fty,
+                _ => bug!()
             };
-            parse_float(&n.as_str(), fty_hint).map(Float)
+            parse_float(&n.as_str(), fty).map(Float)
         }
         LitKind::Bool(b) => Ok(Bool(b)),
         LitKind::Char(c) => Ok(Char(c)),
     }
 }
 
-fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>)
-               -> Result<ConstFloat, ErrKind> {
-    let val = match fty_hint {
-        Some(ast::FloatTy::F32) => num.parse::<f32>().map(F32),
-        Some(ast::FloatTy::F64) => num.parse::<f64>().map(F64),
-        None => {
-            num.parse::<f32>().and_then(|f32| {
-                num.parse::<f64>().map(|f64| {
-                    FInfer { f32: f32, f64: f64 }
-                })
-            })
-        }
+fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
+                     -> Result<ConstFloat, ErrKind<'tcx>> {
+    let val = match fty {
+        ast::FloatTy::F32 => num.parse::<f32>().map(F32),
+        ast::FloatTy::F64 => num.parse::<f64>().map(F64)
     };
     val.map_err(|_| {
         // FIXME(#31407) this is only necessary because float parsing is buggy
@@ -1170,17 +933,17 @@ pub fn compare_lit_exprs(&self,
                              a: &Expr,
                              b: &Expr) -> Result<Ordering, ErrorReported> {
         let tcx = self.tcx;
-        let a = match self.eval(a, ExprTypeChecked) {
+        let a = match self.eval(a) {
             Ok(a) => a,
             Err(e) => {
-                report_const_eval_err(tcx, &e, a.span, "expression").emit();
+                report_const_eval_err(tcx, &e, a.span, "expression");
                 return Err(ErrorReported);
             }
         };
-        let b = match self.eval(b, ExprTypeChecked) {
+        let b = match self.eval(b) {
             Ok(b) => b,
             Err(e) => {
-                report_const_eval_err(tcx, &e, b.span, "expression").emit();
+                report_const_eval_err(tcx, &e, b.span, "expression");
                 return Err(ErrorReported);
             }
         };
@@ -1195,26 +958,17 @@ pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              reason: &str)
                              -> Result<usize, ErrorReported>
 {
-    let hint = UncheckedExprHint(tcx.types.usize);
     let count_expr = &tcx.hir.body(count).value;
-    match ConstContext::new(tcx, count).eval(count_expr, hint) {
+    match ConstContext::new(tcx, count).eval(count_expr) {
         Ok(Integral(Usize(count))) => {
             let val = count.as_u64(tcx.sess.target.uint_type);
             assert_eq!(val as usize as u64, val);
             Ok(val as usize)
         },
-        Ok(const_val) => {
-            struct_span_err!(tcx.sess, count_expr.span, E0306,
-                             "expected `usize` for {}, found {}",
-                             reason,
-                             const_val.description())
-                .span_label(count_expr.span, &format!("expected `usize`"))
-                .emit();
-
-            Err(ErrorReported)
-        }
+        Ok(_) |
+        Err(ConstEvalErr { kind: TypeckError, .. }) => Err(ErrorReported),
         Err(err) => {
-            let mut diag = report_const_eval_err(
+            let mut diag = build_const_eval_err(
                 tcx, &err, count_expr.span, reason);
 
             if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
index 198e49daabc63f74422d86778f4dd143ee4f39f9..4434a901f9412512f29ed52bcf674f7a15d0b106 100644 (file)
@@ -21,6 +21,7 @@
 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![deny(warnings)]
 
 #![feature(rustc_private)]
 #![feature(staged_api)]
index 609fb3e39d62cc8406987ca1ebd8e6fffb3d0e03..72a47c0028162a39d6e9d894cdbdf1380c52bf4f 100644 (file)
@@ -27,9 +27,9 @@
 use syntax_pos::Span;
 
 #[derive(Clone, Debug)]
-pub enum PatternError {
+pub enum PatternError<'tcx> {
     StaticInPattern(Span),
-    ConstEval(eval::ConstEvalErr),
+    ConstEval(eval::ConstEvalErr<'tcx>),
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -84,12 +84,12 @@ pub enum PatternKind<'tcx> {
     },
 
     Constant {
-        value: ConstVal,
+        value: ConstVal<'tcx>,
     },
 
     Range {
-        lo: ConstVal,
-        hi: ConstVal,
+        lo: ConstVal<'tcx>,
+        hi: ConstVal<'tcx>,
         end: RangeEnd,
     },
 
@@ -118,7 +118,7 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
         ConstVal::Char(c) => write!(f, "{:?}", c),
         ConstVal::Struct(_) |
         ConstVal::Tuple(_) |
-        ConstVal::Function(_) |
+        ConstVal::Function(..) |
         ConstVal::Array(..) |
         ConstVal::Repeat(..) => bug!("{:?} not printable in a pattern", value)
     }
@@ -265,7 +265,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
     pub tables: &'a ty::TypeckTables<'gcx>,
-    pub errors: Vec<PatternError>,
+    pub errors: Vec<PatternError<'tcx>>,
 }
 
 impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
@@ -582,11 +582,11 @@ fn lower_path(&mut self,
                 let tcx = self.tcx.global_tcx();
                 let substs = self.tables.node_id_item_substs(id)
                     .unwrap_or_else(|| tcx.intern_substs(&[]));
-                match eval::lookup_const_by_id(tcx, def_id, Some(substs)) {
-                    Some((const_expr, const_tables, _const_ty)) => {
+                match eval::lookup_const_by_id(tcx, def_id, substs) {
+                    Some((const_expr, const_tables)) => {
                         // Enter the inlined constant's tables temporarily.
                         let old_tables = self.tables;
-                        self.tables = const_tables.expect("missing tables after typeck");
+                        self.tables = const_tables;
                         let pat = self.lower_const_expr(const_expr, pat_id, span);
                         self.tables = old_tables;
                         return pat;
@@ -609,7 +609,7 @@ fn lower_path(&mut self,
 
     fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
         let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables);
-        match const_cx.eval(expr, eval::EvalHint::ExprTypeChecked) {
+        match const_cx.eval(expr) {
             Ok(value) => {
                 PatternKind::Constant { value: value }
             }
@@ -796,7 +796,7 @@ fn super_fold_with<F: PatternFolder<$lt_tcx>>(&self, _: &mut F) -> Self {
 }
 
 CloneImpls!{ <'tcx>
-    Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal, Region,
+    Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal<'tcx>, Region,
     Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
     &'tcx Substs<'tcx>, &'tcx Kind<'tcx>
 }
index 4610c183e1b1f3f52f3809738bc1e366df36b7ed..f557edffbda462053b3a8bfcfb737d407a291bd7 100644 (file)
 #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
 pub enum ConstFloat {
     F32(f32),
-    F64(f64),
-
-    // When the type isn't known, we have to operate on both possibilities.
-    FInfer {
-        f32: f32,
-        f64: f64
-    }
+    F64(f64)
 }
 pub use self::ConstFloat::*;
 
@@ -31,7 +25,6 @@ impl ConstFloat {
     /// Description of the type, not the value
     pub fn description(&self) -> &'static str {
         match *self {
-            FInfer {..} => "float",
             F32(_) => "f32",
             F64(_) => "f64",
         }
@@ -41,17 +34,13 @@ pub fn is_nan(&self) -> bool {
         match *self {
             F32(f) => f.is_nan(),
             F64(f) => f.is_nan(),
-            FInfer { f32, f64 } => f32.is_nan() || f64.is_nan()
         }
     }
 
     /// Compares the values if they are of the same type
     pub fn try_cmp(self, rhs: Self) -> Result<Ordering, ConstMathErr> {
         match (self, rhs) {
-            (F64(a), F64(b)) |
-            (F64(a), FInfer { f64: b, .. }) |
-            (FInfer { f64: a, .. }, F64(b)) |
-            (FInfer { f64: a, .. }, FInfer { f64: b, .. })  => {
+            (F64(a), F64(b))  => {
                 // This is pretty bad but it is the existing behavior.
                 Ok(if a == b {
                     Ordering::Equal
@@ -62,9 +51,7 @@ pub fn try_cmp(self, rhs: Self) -> Result<Ordering, ConstMathErr> {
                 })
             }
 
-            (F32(a), F32(b)) |
-            (F32(a), FInfer { f32: b, .. }) |
-            (FInfer { f32: a, .. }, F32(b)) => {
+            (F32(a), F32(b)) => {
                 Ok(if a == b {
                     Ordering::Equal
                 } else if a < b {
@@ -86,10 +73,7 @@ pub fn try_cmp(self, rhs: Self) -> Result<Ordering, ConstMathErr> {
 impl PartialEq for ConstFloat {
     fn eq(&self, other: &Self) -> bool {
         match (*self, *other) {
-            (F64(a), F64(b)) |
-            (F64(a), FInfer { f64: b, .. }) |
-            (FInfer { f64: a, .. }, F64(b)) |
-            (FInfer { f64: a, .. }, FInfer { f64: b, .. }) => {
+            (F64(a), F64(b)) => {
                 unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)}
             }
             (F32(a), F32(b)) => {
@@ -105,7 +89,7 @@ impl Eq for ConstFloat {}
 impl hash::Hash for ConstFloat {
     fn hash<H: hash::Hasher>(&self, state: &mut H) {
         match *self {
-            F64(a) | FInfer { f64: a, .. } => {
+            F64(a) => {
                 unsafe { transmute::<_,u64>(a) }.hash(state)
             }
             F32(a) => {
@@ -118,7 +102,6 @@ fn hash<H: hash::Hasher>(&self, state: &mut H) {
 impl ::std::fmt::Display for ConstFloat {
     fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
         match *self {
-            FInfer { f64, .. } => write!(fmt, "{}", f64),
             F32(f) => write!(fmt, "{}f32", f),
             F64(f) => write!(fmt, "{}f64", f),
         }
@@ -131,20 +114,8 @@ impl ::std::ops::$op for ConstFloat {
             type Output = Result<Self, ConstMathErr>;
             fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
                 match (self, rhs) {
-                    (F32(a), F32(b)) |
-                    (F32(a), FInfer { f32: b, .. }) |
-                    (FInfer { f32: a, .. }, F32(b)) => Ok(F32(a.$func(b))),
-
-                    (F64(a), F64(b)) |
-                    (FInfer { f64: a, .. }, F64(b)) |
-                    (F64(a), FInfer { f64: b, .. }) => Ok(F64(a.$func(b))),
-
-                    (FInfer { f32: a32, f64: a64 },
-                     FInfer { f32: b32, f64: b64 }) => Ok(FInfer {
-                        f32: a32.$func(b32),
-                        f64: a64.$func(b64)
-                    }),
-
+                    (F32(a), F32(b)) => Ok(F32(a.$func(b))),
+                    (F64(a), F64(b)) => Ok(F64(a.$func(b))),
                     _ => Err(UnequalTypes(Op::$op)),
                 }
             }
@@ -164,10 +135,6 @@ fn neg(self) -> Self {
         match self {
             F32(f) => F32(-f),
             F64(f) => F64(-f),
-            FInfer { f32, f64 } => FInfer {
-                f32: -f32,
-                f64: -f64
-            }
         }
     }
 }
index bc3809db1c63a619086b78b41daceb2d84a80ead..d97276da9bf34b9315d7a410f403fe34a558a076 100644 (file)
@@ -30,8 +30,6 @@ pub enum ConstInt {
     U64(u64),
     U128(u128),
     Usize(ConstUsize),
-    Infer(u128),
-    InferSigned(i128),
 }
 pub use self::ConstInt::*;
 
@@ -77,14 +75,6 @@ mod ibounds {
 }
 
 impl ConstInt {
-    pub fn new_inttype(val: u128, ty: IntType, usize_ty: UintTy, isize_ty: IntTy)
-    -> Option<ConstInt> {
-        match ty {
-            IntType::SignedInt(i) => ConstInt::new_signed(val as i128, i, isize_ty),
-            IntType::UnsignedInt(i) => ConstInt::new_unsigned(val, i, usize_ty),
-        }
-    }
-
     /// Creates a new unsigned ConstInt with matching type while also checking that overflow does
     /// not happen.
     pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option<ConstInt> {
@@ -100,7 +90,7 @@ pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option<ConstInt>
         }
     }
 
-    /// Creates a new unsigned ConstInt with matching type while also checking that overflow does
+    /// Creates a new signed ConstInt with matching type while also checking that overflow does
     /// not happen.
     pub fn new_signed(val: i128, ty: IntTy, isize_ty: IntTy) -> Option<ConstInt> {
         match ty {
@@ -115,103 +105,33 @@ pub fn new_signed(val: i128, ty: IntTy, isize_ty: IntTy) -> Option<ConstInt> {
         }
     }
 
-    /// If either value is `Infer` or `InferSigned`, try to turn the value into the type of
-    /// the other value. If both values have no type, don't do anything
-    pub fn infer(self, other: Self) -> Result<(Self, Self), ConstMathErr> {
-        let inferred = match (self, other) {
-            (InferSigned(_), InferSigned(_))
-            | (Infer(_), Infer(_)) => self, // no inference possible
-            // kindof wrong, you could have had values > I64MAX during computation of a
-            (Infer(a @ 0...ubounds::I64MAX), InferSigned(_)) => InferSigned(a as i128),
-            (Infer(_), InferSigned(_)) => return Err(ConstMathErr::NotInRange),
-            (_, InferSigned(_))
-            | (_, Infer(_)) => return other.infer(self).map(|(b, a)| (a, b)),
-
-            (Infer(a @ 0...ubounds::I8MAX), I8(_)) => I8(a as i64 as i8),
-            (Infer(a @ 0...ubounds::I16MAX), I16(_)) => I16(a as i64 as i16),
-            (Infer(a @ 0...ubounds::I32MAX), I32(_)) => I32(a as i64 as i32),
-            (Infer(a @ 0...ubounds::I64MAX), I64(_)) => I64(a as i64),
-            (Infer(a @ 0...ubounds::I128MAX), I128(_)) => I128(a as i128),
-            (Infer(a @ 0...ubounds::I16MAX), Isize(Is16(_))) => Isize(Is16(a as i64 as i16)),
-            (Infer(a @ 0...ubounds::I32MAX), Isize(Is32(_))) => Isize(Is32(a as i64 as i32)),
-            (Infer(a @ 0...ubounds::I64MAX), Isize(Is64(_))) => Isize(Is64(a as i64)),
-            (Infer(a @ 0...ubounds::U8MAX), U8(_)) => U8(a as u8),
-            (Infer(a @ 0...ubounds::U16MAX), U16(_)) => U16(a as u16),
-            (Infer(a @ 0...ubounds::U32MAX), U32(_)) => U32(a as u32),
-            (Infer(a @ 0...ubounds::U64MAX), U64(_)) => U64(a as u64),
-            (Infer(a @ 0...ubounds::U128MAX), U128(_)) => U128(a as u128),
-            (Infer(a @ 0...ubounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)),
-            (Infer(a @ 0...ubounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
-            (Infer(a @ 0...ubounds::U64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)),
-
-            (Infer(_), _) => return Err(ConstMathErr::NotInRange),
-
-            (InferSigned(a @ ibounds::I8MIN...ibounds::I8MAX), I8(_)) => I8(a as i8),
-            (InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), I16(_)) => I16(a as i16),
-            (InferSigned(a @ ibounds::I32MIN...ibounds::I32MAX), I32(_)) => I32(a as i32),
-            (InferSigned(a @ ibounds::I64MIN...ibounds::I64MAX), I64(_)) => I64(a as i64),
-            (InferSigned(a @ ibounds::I128MIN...ibounds::I128MAX), I128(_)) => I128(a as i128),
-            (InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), Isize(Is16(_))) => {
-                Isize(Is16(a as i16))
-            },
-            (InferSigned(a @ ibounds::I32MIN...ibounds::I32MAX), Isize(Is32(_))) => {
-                Isize(Is32(a as i32))
-            },
-            (InferSigned(a @ ibounds::I64MIN...ibounds::I64MAX), Isize(Is64(_))) => {
-                Isize(Is64(a as i64))
-            },
-            (InferSigned(a @ 0...ibounds::U8MAX), U8(_)) => U8(a as u8),
-            (InferSigned(a @ 0...ibounds::U16MAX), U16(_)) => U16(a as u16),
-            (InferSigned(a @ 0...ibounds::U32MAX), U32(_)) => U32(a as u32),
-            (InferSigned(a @ 0...ibounds::U64MAX), U64(_)) => U64(a as u64),
-            (InferSigned(a @ 0...ibounds::I128MAX), U128(_)) => U128(a as u128),
-            (InferSigned(a @ 0...ibounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)),
-            (InferSigned(a @ 0...ibounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
-            (InferSigned(a @ 0...ibounds::U64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)),
-            (InferSigned(_), _) => return Err(ConstMathErr::NotInRange),
-            _ => self, // already known types
-        };
-        Ok((inferred, other))
+    /// Creates a new unsigned ConstInt with matching type.
+    pub fn new_unsigned_truncating(val: u128, ty: UintTy, usize_ty: UintTy) -> ConstInt {
+        match ty {
+            UintTy::U8 => U8(val as u8),
+            UintTy::U16 => U16(val as u16),
+            UintTy::U32 => U32(val as u32),
+            UintTy::U64 => U64(val as u64),
+            UintTy::Us => Usize(ConstUsize::new_truncating(val, usize_ty)),
+            UintTy::U128 => U128(val)
+        }
     }
 
-    /// Turn this value into an `Infer` or an `InferSigned`
-    pub fn erase_type(self) -> Self {
-        match self {
-            Infer(i) => Infer(i),
-            InferSigned(i) if i < 0 => InferSigned(i),
-            I8(i) if i < 0 => InferSigned(i as i128),
-            I16(i) if i < 0 => InferSigned(i as i128),
-            I32(i) if i < 0 => InferSigned(i as i128),
-            I64(i) if i < 0 => InferSigned(i as i128),
-            I128(i) if i < 0 => InferSigned(i as i128),
-            Isize(Is16(i)) if i < 0 => InferSigned(i as i128),
-            Isize(Is32(i)) if i < 0 => InferSigned(i as i128),
-            Isize(Is64(i)) if i < 0 => InferSigned(i as i128),
-            InferSigned(i) => Infer(i as u128),
-            I8(i) => Infer(i as u128),
-            I16(i) => Infer(i as u128),
-            I32(i) => Infer(i as u128),
-            I64(i) => Infer(i as u128),
-            I128(i) => Infer(i as u128),
-            Isize(Is16(i)) => Infer(i as u128),
-            Isize(Is32(i)) => Infer(i as u128),
-            Isize(Is64(i)) => Infer(i as u128),
-            U8(i) => Infer(i as u128),
-            U16(i) => Infer(i as u128),
-            U32(i) => Infer(i as u128),
-            U64(i) => Infer(i as u128),
-            U128(i) => Infer(i as u128),
-            Usize(Us16(i)) => Infer(i as u128),
-            Usize(Us32(i)) => Infer(i as u128),
-            Usize(Us64(i)) => Infer(i as u128),
+    /// Creates a new signed ConstInt with matching type.
+    pub fn new_signed_truncating(val: i128, ty: IntTy, isize_ty: IntTy) -> ConstInt {
+        match ty {
+            IntTy::I8 => I8(val as i8),
+            IntTy::I16 => I16(val as i16),
+            IntTy::I32 => I32(val as i32),
+            IntTy::I64 => I64(val as i64),
+            IntTy::Is => Isize(ConstIsize::new_truncating(val, isize_ty)),
+            IntTy::I128 => I128(val)
         }
     }
 
     /// Description of the type, not the value
     pub fn description(&self) -> &'static str {
         match *self {
-            Infer(_) => "not yet inferred integral",
-            InferSigned(_) => "not yet inferred signed integral",
             I8(_) => "i8",
             I16(_) => "i16",
             I32(_) => "i32",
@@ -230,10 +150,23 @@ pub fn description(&self) -> &'static str {
     /// Erases the type and returns a u128.
     /// This is not the same as `-5i8 as u128` but as `-5i8 as i128 as u128`
     pub fn to_u128_unchecked(self) -> u128 {
-        match self.erase_type() {
-            ConstInt::Infer(i) => i,
-            ConstInt::InferSigned(i) => i as u128,
-            _ => unreachable!(),
+        match self {
+            I8(i) => i as i128 as u128,
+            I16(i) => i as i128 as u128,
+            I32(i) => i as i128 as u128,
+            I64(i) => i as i128 as u128,
+            I128(i) => i as i128 as u128,
+            Isize(Is16(i)) => i as i128 as u128,
+            Isize(Is32(i)) => i as i128 as u128,
+            Isize(Is64(i)) => i as i128 as u128,
+            U8(i) => i as u128,
+            U16(i) => i as u128,
+            U32(i) => i as u128,
+            U64(i) => i as u128,
+            U128(i) => i as u128,
+            Usize(Us16(i)) => i as u128,
+            Usize(Us32(i)) => i as u128,
+            Usize(Us64(i)) => i as u128,
         }
     }
 
@@ -258,8 +191,6 @@ pub fn to_u64(&self) -> Option<u64> {
     /// Converts the value to a `u128` if it's in the range 0...std::u128::MAX
     pub fn to_u128(&self) -> Option<u128> {
         match *self {
-            Infer(v) => Some(v),
-            InferSigned(v) if v >= 0 => Some(v as u128),
             I8(v) if v >= 0 => Some(v as u128),
             I16(v) if v >= 0 => Some(v as u128),
             I32(v) if v >= 0 => Some(v as u128),
@@ -280,6 +211,48 @@ pub fn to_u128(&self) -> Option<u128> {
         }
     }
 
+    pub fn to_f32(self) -> f32 {
+        match self {
+            I8(i) => i as f32,
+            I16(i) => i as f32,
+            I32(i) => i as f32,
+            I64(i) => i as f32,
+            I128(i) => i as f32,
+            Isize(Is16(i)) => i as f32,
+            Isize(Is32(i)) => i as f32,
+            Isize(Is64(i)) => i as f32,
+            U8(i) => i as f32,
+            U16(i) => i as f32,
+            U32(i) => i as f32,
+            U64(i) => i as f32,
+            U128(i) => i as f32,
+            Usize(Us16(i)) => i as f32,
+            Usize(Us32(i)) => i as f32,
+            Usize(Us64(i)) => i as f32,
+        }
+    }
+
+    pub fn to_f64(self) -> f64 {
+        match self {
+            I8(i) => i as f64,
+            I16(i) => i as f64,
+            I32(i) => i as f64,
+            I64(i) => i as f64,
+            I128(i) => i as f64,
+            Isize(Is16(i)) => i as f64,
+            Isize(Is32(i)) => i as f64,
+            Isize(Is64(i)) => i as f64,
+            U8(i) => i as f64,
+            U16(i) => i as f64,
+            U32(i) => i as f64,
+            U64(i) => i as f64,
+            U128(i) => i as f64,
+            Usize(Us16(i)) => i as f64,
+            Usize(Us32(i)) => i as f64,
+            Usize(Us64(i)) => i as f64,
+        }
+    }
+
     pub fn is_negative(&self) -> bool {
         match *self {
             I8(v) => v < 0,
@@ -290,14 +263,13 @@ pub fn is_negative(&self) -> bool {
             Isize(Is16(v)) => v < 0,
             Isize(Is32(v)) => v < 0,
             Isize(Is64(v)) => v < 0,
-            InferSigned(v) => v < 0,
             _ => false,
         }
     }
 
     /// Compares the values if they are of the same type
     pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> {
-        match self.infer(rhs)? {
+        match (self, rhs) {
             (I8(a), I8(b)) => Ok(a.cmp(&b)),
             (I16(a), I16(b)) => Ok(a.cmp(&b)),
             (I32(a), I32(b)) => Ok(a.cmp(&b)),
@@ -314,8 +286,6 @@ pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> {
             (Usize(Us16(a)), Usize(Us16(b))) => Ok(a.cmp(&b)),
             (Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)),
             (Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)),
-            (Infer(a), Infer(b)) => Ok(a.cmp(&b)),
-            (InferSigned(a), InferSigned(b)) => Ok(a.cmp(&b)),
             _ => Err(CmpBetweenUnequalTypes),
         }
     }
@@ -342,25 +312,23 @@ macro_rules! add1 {
             ConstInt::Usize(ConstUsize::Us16(i)) => ConstInt::Usize(ConstUsize::Us16(add1!(i))),
             ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))),
             ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))),
-            ConstInt::Infer(_) | ConstInt::InferSigned(_) => panic!("no type info for const int"),
         }
     }
 
-    pub fn int_type(self) -> Option<IntType> {
+    pub fn int_type(self) -> IntType {
         match self {
-            ConstInt::I8(_) => Some(IntType::SignedInt(IntTy::I8)),
-            ConstInt::I16(_) => Some(IntType::SignedInt(IntTy::I16)),
-            ConstInt::I32(_) => Some(IntType::SignedInt(IntTy::I32)),
-            ConstInt::I64(_) => Some(IntType::SignedInt(IntTy::I64)),
-            ConstInt::I128(_) => Some(IntType::SignedInt(IntTy::I128)),
-            ConstInt::Isize(_) => Some(IntType::SignedInt(IntTy::Is)),
-            ConstInt::U8(_) => Some(IntType::UnsignedInt(UintTy::U8)),
-            ConstInt::U16(_) => Some(IntType::UnsignedInt(UintTy::U16)),
-            ConstInt::U32(_) => Some(IntType::UnsignedInt(UintTy::U32)),
-            ConstInt::U64(_) => Some(IntType::UnsignedInt(UintTy::U64)),
-            ConstInt::U128(_) => Some(IntType::UnsignedInt(UintTy::U128)),
-            ConstInt::Usize(_) => Some(IntType::UnsignedInt(UintTy::Us)),
-            _ => None,
+            ConstInt::I8(_) => IntType::SignedInt(IntTy::I8),
+            ConstInt::I16(_) => IntType::SignedInt(IntTy::I16),
+            ConstInt::I32(_) => IntType::SignedInt(IntTy::I32),
+            ConstInt::I64(_) => IntType::SignedInt(IntTy::I64),
+            ConstInt::I128(_) => IntType::SignedInt(IntTy::I128),
+            ConstInt::Isize(_) => IntType::SignedInt(IntTy::Is),
+            ConstInt::U8(_) => IntType::UnsignedInt(UintTy::U8),
+            ConstInt::U16(_) => IntType::UnsignedInt(UintTy::U16),
+            ConstInt::U32(_) => IntType::UnsignedInt(UintTy::U32),
+            ConstInt::U64(_) => IntType::UnsignedInt(UintTy::U64),
+            ConstInt::U128(_) => IntType::UnsignedInt(UintTy::U128),
+            ConstInt::Usize(_) => IntType::UnsignedInt(UintTy::Us),
         }
     }
 }
@@ -380,8 +348,6 @@ fn cmp(&self, other: &Self) -> Ordering {
 impl ::std::fmt::Display for ConstInt {
     fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
         match *self {
-            Infer(i) => write!(fmt, "{}", i),
-            InferSigned(i) => write!(fmt, "{}", i),
             I8(i) => write!(fmt, "{}i8", i),
             I16(i) => write!(fmt, "{}i16", i),
             I32(i) => write!(fmt, "{}i32", i),
@@ -417,7 +383,7 @@ macro_rules! impl_binop {
         impl ::std::ops::$op for ConstInt {
             type Output = Result<Self, ConstMathErr>;
             fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
-                match self.infer(rhs)? {
+                match (self, rhs) {
                     (I8(a), I8(b)) => a.$checked_func(b).map(I8),
                     (I16(a), I16(b)) => a.$checked_func(b).map(I16),
                     (I32(a), I32(b)) => a.$checked_func(b).map(I32),
@@ -434,8 +400,6 @@ fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
                     (Usize(Us16(a)), Usize(Us16(b))) => a.$checked_func(b).map(Us16).map(Usize),
                     (Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize),
                     (Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize),
-                    (Infer(a), Infer(b)) => a.$checked_func(b).map(Infer),
-                    (InferSigned(a), InferSigned(b)) => a.$checked_func(b).map(InferSigned),
                     _ => return Err(UnequalTypes(Op::$op)),
                 }.ok_or(Overflow(Op::$op))
             }
@@ -448,7 +412,7 @@ macro_rules! derive_binop {
         impl ::std::ops::$op for ConstInt {
             type Output = Result<Self, ConstMathErr>;
             fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
-                match self.infer(rhs)? {
+                match (self, rhs) {
                     (I8(a), I8(b)) => Ok(I8(a.$func(b))),
                     (I16(a), I16(b)) => Ok(I16(a.$func(b))),
                     (I32(a), I32(b)) => Ok(I32(a.$func(b))),
@@ -465,8 +429,6 @@ fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
                     (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a.$func(b)))),
                     (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))),
                     (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))),
-                    (Infer(a), Infer(b)) => Ok(Infer(a.$func(b))),
-                    (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a.$func(b))),
                     _ => Err(UnequalTypes(Op::$op)),
                 }
             }
@@ -498,7 +460,6 @@ fn check_division(
         (Isize(_), Isize(Is16(0))) => Err(zerr),
         (Isize(_), Isize(Is32(0))) => Err(zerr),
         (Isize(_), Isize(Is64(0))) => Err(zerr),
-        (InferSigned(_), InferSigned(0)) => Err(zerr),
 
         (U8(_), U8(0)) => Err(zerr),
         (U16(_), U16(0)) => Err(zerr),
@@ -508,7 +469,6 @@ fn check_division(
         (Usize(_), Usize(Us16(0))) => Err(zerr),
         (Usize(_), Usize(Us32(0))) => Err(zerr),
         (Usize(_), Usize(Us64(0))) => Err(zerr),
-        (Infer(_), Infer(0)) => Err(zerr),
 
         (I8(::std::i8::MIN), I8(-1)) => Err(Overflow(op)),
         (I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)),
@@ -518,7 +478,6 @@ fn check_division(
         (Isize(Is16(::std::i16::MIN)), Isize(Is16(-1))) => Err(Overflow(op)),
         (Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)),
         (Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)),
-        (InferSigned(I128_MIN), InferSigned(-1)) => Err(Overflow(op)),
 
         _ => Ok(()),
     }
@@ -527,7 +486,7 @@ fn check_division(
 impl ::std::ops::Div for ConstInt {
     type Output = Result<Self, ConstMathErr>;
     fn div(self, rhs: Self) -> Result<Self, ConstMathErr> {
-        let (lhs, rhs) = self.infer(rhs)?;
+        let (lhs, rhs) = (self, rhs);
         check_division(lhs, rhs, Op::Div, DivisionByZero)?;
         match (lhs, rhs) {
             (I8(a), I8(b)) => Ok(I8(a/b)),
@@ -538,7 +497,6 @@ fn div(self, rhs: Self) -> Result<Self, ConstMathErr> {
             (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a/b))),
             (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))),
             (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))),
-            (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a/b)),
 
             (U8(a), U8(b)) => Ok(U8(a/b)),
             (U16(a), U16(b)) => Ok(U16(a/b)),
@@ -548,7 +506,6 @@ fn div(self, rhs: Self) -> Result<Self, ConstMathErr> {
             (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a/b))),
             (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))),
             (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))),
-            (Infer(a), Infer(b)) => Ok(Infer(a/b)),
 
             _ => Err(UnequalTypes(Op::Div)),
         }
@@ -558,7 +515,7 @@ fn div(self, rhs: Self) -> Result<Self, ConstMathErr> {
 impl ::std::ops::Rem for ConstInt {
     type Output = Result<Self, ConstMathErr>;
     fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> {
-        let (lhs, rhs) = self.infer(rhs)?;
+        let (lhs, rhs) = (self, rhs);
         // should INT_MIN%-1 be zero or an error?
         check_division(lhs, rhs, Op::Rem, RemainderByZero)?;
         match (lhs, rhs) {
@@ -570,7 +527,6 @@ fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> {
             (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a%b))),
             (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))),
             (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))),
-            (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a%b)),
 
             (U8(a), U8(b)) => Ok(U8(a%b)),
             (U16(a), U16(b)) => Ok(U16(a%b)),
@@ -580,7 +536,6 @@ fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> {
             (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a%b))),
             (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))),
             (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))),
-            (Infer(a), Infer(b)) => Ok(Infer(a%b)),
 
             _ => Err(UnequalTypes(Op::Rem)),
         }
@@ -608,8 +563,6 @@ fn shl(self, rhs: Self) -> Result<Self, ConstMathErr> {
             Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shl(b), Op::Shl)))),
             Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
             Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
-            Infer(a) => Ok(Infer(overflowing!(a.overflowing_shl(b), Op::Shl))),
-            InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shl(b), Op::Shl))),
         }
     }
 }
@@ -635,8 +588,6 @@ fn shr(self, rhs: Self) -> Result<Self, ConstMathErr> {
             Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shr(b), Op::Shr)))),
             Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
             Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
-            Infer(a) => Ok(Infer(overflowing!(a.overflowing_shr(b), Op::Shr))),
-            InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shr(b), Op::Shr))),
         }
     }
 }
@@ -656,9 +607,6 @@ fn neg(self) -> Result<Self, ConstMathErr> {
             a@U8(0) | a@U16(0) | a@U32(0) | a@U64(0) | a@U128(0) |
             a@Usize(Us16(0)) | a@Usize(Us32(0)) | a@Usize(Us64(0)) => Ok(a),
             U8(_) | U16(_) | U32(_) | U64(_) | U128(_) | Usize(_) => Err(UnsignedNegation),
-            Infer(a @ 0...ubounds::I128MAX) => Ok(InferSigned(-(a as i128))),
-            Infer(_) => Err(Overflow(Op::Neg)),
-            InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_neg(), Op::Neg))),
         }
     }
 }
@@ -683,8 +631,6 @@ fn not(self) -> Result<Self, ConstMathErr> {
             Usize(Us16(a)) => Ok(Usize(Us16(!a))),
             Usize(Us32(a)) => Ok(Usize(Us32(!a))),
             Usize(Us64(a)) => Ok(Usize(Us64(!a))),
-            Infer(a) => Ok(Infer(!a)),
-            InferSigned(a) => Ok(InferSigned(!a)),
         }
     }
 }
index 13764ce5bbbfd2027f50cda905102dd6abf4b351..b7833a5440321221eb934a00ef08fd675550cfcc 100644 (file)
@@ -21,7 +21,7 @@
 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
-
+#![deny(warnings)]
 
 #![feature(rustc_private)]
 #![feature(staged_api)]
index de789d5686fcfb81024bb8ebf8e66bfd4f66686d..9619ba8472404bb70e0a1fffca1e620841dbe528 100644 (file)
 use rustc::middle::privacy::AccessLevels;
 use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas};
 use rustc::util::common::time;
-use rustc::util::nodemap::{NodeSet, NodeMap};
+use rustc::util::nodemap::NodeSet;
 use rustc::util::fs::rename_or_copy_remove;
 use rustc_borrowck as borrowck;
 use rustc_incremental::{self, IncrementalHashesMap};
 use rustc_incremental::ich::Fingerprint;
 use rustc_resolve::{MakeGlobMap, Resolver};
 use rustc_metadata::creader::CrateLoader;
-use rustc_metadata::cstore::CStore;
+use rustc_metadata::cstore::{self, CStore};
 use rustc_trans::back::{link, write};
 use rustc_trans as trans;
 use rustc_typeck as typeck;
@@ -343,7 +343,7 @@ pub struct CompileState<'a, 'tcx: 'a> {
     pub hir_crate: Option<&'a hir::Crate>,
     pub hir_map: Option<&'a hir_map::Map<'tcx>>,
     pub resolutions: Option<&'a Resolutions>,
-    pub analysis: Option<&'a ty::CrateAnalysis<'tcx>>,
+    pub analysis: Option<&'a ty::CrateAnalysis>,
     pub tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
     pub trans: Option<&'a trans::CrateTranslation>,
 }
@@ -417,7 +417,7 @@ fn state_after_hir_lowering(input: &'a Input,
                                 arenas: &'tcx GlobalArenas<'tcx>,
                                 cstore: &'a CStore,
                                 hir_map: &'a hir_map::Map<'tcx>,
-                                analysis: &'a ty::CrateAnalysis<'static>,
+                                analysis: &'a ty::CrateAnalysis,
                                 resolutions: &'a Resolutions,
                                 krate: &'a ast::Crate,
                                 hir_crate: &'a hir::Crate,
@@ -444,7 +444,7 @@ fn state_after_analysis(input: &'a Input,
                             out_file: &'a Option<PathBuf>,
                             krate: Option<&'a ast::Crate>,
                             hir_crate: &'a hir::Crate,
-                            analysis: &'a ty::CrateAnalysis<'tcx>,
+                            analysis: &'a ty::CrateAnalysis,
                             tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             crate_name: &'a str)
                             -> Self {
@@ -534,7 +534,7 @@ fn count_nodes(krate: &ast::Crate) -> usize {
 pub struct ExpansionResult {
     pub expanded_crate: ast::Crate,
     pub defs: hir_map::Definitions,
-    pub analysis: ty::CrateAnalysis<'static>,
+    pub analysis: ty::CrateAnalysis,
     pub resolutions: Resolutions,
     pub hir_forest: hir_map::Forest,
 }
@@ -688,6 +688,14 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
 
         let krate = ecx.monotonic_expander().expand_crate(krate);
 
+        let mut missing_fragment_specifiers: Vec<_> =
+            ecx.parse_sess.missing_fragment_specifiers.borrow().iter().cloned().collect();
+        missing_fragment_specifiers.sort();
+        for span in missing_fragment_specifiers {
+            let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER;
+            let msg = "missing fragment specifier".to_string();
+            sess.add_lint(lint, ast::CRATE_NODE_ID, span, msg);
+        }
         if ecx.parse_sess.span_diagnostic.err_count() - ecx.resolve_err_count > err_count {
             ecx.parse_sess.span_diagnostic.abort_if_errors();
         }
@@ -797,7 +805,6 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
             reachable: NodeSet(),
             name: crate_name.to_string(),
             glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None },
-            hir_ty_to_ty: NodeMap(),
         },
         resolutions: Resolutions {
             freevars: resolver.freevars,
@@ -813,7 +820,7 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
 /// structures carrying the results of the analysis.
 pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
                                                hir_map: hir_map::Map<'tcx>,
-                                               mut analysis: ty::CrateAnalysis<'tcx>,
+                                               mut analysis: ty::CrateAnalysis,
                                                resolutions: Resolutions,
                                                arena: &'tcx DroplessArena,
                                                arenas: &'tcx GlobalArenas<'tcx>,
@@ -821,7 +828,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
                                                f: F)
                                                -> Result<R, usize>
     where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>,
-                            ty::CrateAnalysis<'tcx>,
+                            ty::CrateAnalysis,
                             IncrementalHashesMap,
                             CompileResult) -> R
 {
@@ -872,7 +879,16 @@ macro_rules! try_with_f {
 
     let index = stability::Index::new(&hir_map);
 
+    let mut local_providers = ty::maps::Providers::default();
+    mir::provide(&mut local_providers);
+    typeck::provide(&mut local_providers);
+
+    let mut extern_providers = ty::maps::Providers::default();
+    cstore::provide(&mut extern_providers);
+
     TyCtxt::create_and_enter(sess,
+                             local_providers,
+                             extern_providers,
                              arenas,
                              arena,
                              resolutions,
@@ -900,8 +916,7 @@ macro_rules! try_with_f {
              || stability::check_unstable_api_usage(tcx));
 
         // passes are timed inside typeck
-        analysis.hir_ty_to_ty =
-            try_with_f!(typeck::check_crate(tcx), (tcx, analysis, incremental_hashes_map));
+        try_with_f!(typeck::check_crate(tcx), (tcx, analysis, incremental_hashes_map));
 
         time(time_passes,
              "const checking",
@@ -951,8 +966,7 @@ macro_rules! try_with_f {
             // in stage 4 below.
             passes.push_hook(box mir::transform::dump_mir::DumpMir);
             passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("initial"));
-            passes.push_pass(
-                box mir::transform::qualify_consts::QualifyAndPromoteConstants::default());
+            passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants);
             passes.push_pass(box mir::transform::type_check::TypeckMir);
             passes.push_pass(
                 box mir::transform::simplify_branches::SimplifyBranches::new("initial"));
index 21fe13997b787d05e5c765b065aa910c5370e9b8..064c4982ef00eb87adcbd828b18ac8701898e3e0 100644 (file)
@@ -201,7 +201,7 @@ fn call_with_pp_support<'tcx, A, B, F>(&self,
     fn call_with_pp_support_hir<'tcx, A, B, F>(&self,
                                                sess: &'tcx Session,
                                                hir_map: &hir_map::Map<'tcx>,
-                                               analysis: &ty::CrateAnalysis<'tcx>,
+                                               analysis: &ty::CrateAnalysis,
                                                resolutions: &Resolutions,
                                                arena: &'tcx DroplessArena,
                                                arenas: &'tcx GlobalArenas<'tcx>,
@@ -838,7 +838,7 @@ pub fn print_after_parsing(sess: &Session,
 
 pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                                                 hir_map: &hir_map::Map<'tcx>,
-                                                analysis: &ty::CrateAnalysis<'tcx>,
+                                                analysis: &ty::CrateAnalysis,
                                                 resolutions: &Resolutions,
                                                 input: &Input,
                                                 krate: &ast::Crate,
@@ -958,7 +958,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
 // Instead, we call that function ourselves.
 fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
                                        hir_map: &hir_map::Map<'tcx>,
-                                       analysis: &ty::CrateAnalysis<'tcx>,
+                                       analysis: &ty::CrateAnalysis,
                                        resolutions: &Resolutions,
                                        crate_name: &str,
                                        arena: &'tcx DroplessArena,
@@ -996,11 +996,13 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
                 } else {
                     match ppm {
                         PpmMir => {
-                            write_mir_pretty(tcx, tcx.mir_map.borrow().keys().into_iter(), &mut out)
+                            write_mir_pretty(tcx,
+                                             tcx.maps.mir.borrow().keys().into_iter(),
+                                             &mut out)
                         }
                         PpmMirCFG => {
                             write_mir_graphviz(tcx,
-                                               tcx.mir_map.borrow().keys().into_iter(),
+                                               tcx.maps.mir.borrow().keys().into_iter(),
                                                &mut out)
                         }
                         _ => unreachable!(),
index 5481de1811d78b91b411b6b470b288bec54dc154..9568cc3d6de0e35c8cc00fce917dc91b73e344c0 100644 (file)
@@ -139,6 +139,8 @@ fn test_env<F>(source_string: &str,
     let region_map = region::resolve_crate(&sess, &hir_map);
     let index = stability::Index::new(&hir_map);
     TyCtxt::create_and_enter(&sess,
+                             ty::maps::Providers::default(),
+                             ty::maps::Providers::default(),
                              &arenas,
                              &arena,
                              resolutions,
@@ -149,7 +151,7 @@ fn test_env<F>(source_string: &str,
                              index,
                              "test_crate",
                              |tcx| {
-        tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
+        tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
 
             body(Env { infcx: &infcx });
             let free_regions = FreeRegionMap::new();
@@ -268,11 +270,13 @@ pub fn assert_eq(&self, a: Ty<'tcx>, b: Ty<'tcx>) {
     }
 
     pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.infcx.tcx.mk_fn_ptr(self.infcx.tcx.mk_bare_fn(ty::BareFnTy {
-            unsafety: hir::Unsafety::Normal,
-            abi: Abi::Rust,
-            sig: ty::Binder(self.infcx.tcx.mk_fn_sig(input_tys.iter().cloned(), output_ty, false)),
-        }))
+        self.infcx.tcx.mk_fn_ptr(ty::Binder(self.infcx.tcx.mk_fn_sig(
+            input_tys.iter().cloned(),
+            output_ty,
+            false,
+            hir::Unsafety::Normal,
+            Abi::Rust
+        )))
     }
 
     pub fn t_nil(&self) -> Ty<'tcx> {
index c7512f2971b33990269ddf68a317f637b6b45eb4..b075fa599924996650b2571afa356f312f2484c7 100644 (file)
@@ -63,8 +63,7 @@ pub fn new(st: &'a mut IchHasher,
                hash_spans: bool,
                hash_bodies: bool)
                -> Self {
-        let check_overflow = tcx.sess.opts.debugging_opts.force_overflow_checks
-            .unwrap_or(tcx.sess.opts.debug_assertions);
+        let check_overflow = tcx.sess.overflow_checks();
 
         StrictVersionHashVisitor {
             st: st,
@@ -338,8 +337,10 @@ fn saw_expr<'a>(node: &'a Expr_,
         ExprIndex(..)            => (SawExprIndex, true),
         ExprPath(_)              => (SawExprPath, false),
         ExprAddrOf(m, _)         => (SawExprAddrOf(m), false),
-        ExprBreak(label, _)      => (SawExprBreak(label.map(|l| l.name.as_str())), false),
-        ExprAgain(label)         => (SawExprAgain(label.map(|l| l.name.as_str())), false),
+        ExprBreak(label, _)      => (SawExprBreak(label.ident.map(|i|
+                                                    i.node.name.as_str())), false),
+        ExprAgain(label)         => (SawExprAgain(label.ident.map(|i|
+                                                    i.node.name.as_str())), false),
         ExprRet(..)              => (SawExprRet, false),
         ExprInlineAsm(ref a,..)  => (SawExprInlineAsm(StableInlineAsm(a)), false),
         ExprStruct(..)           => (SawExprStruct, false),
@@ -1043,26 +1044,6 @@ fn hash_token_tree(&mut self, tt: &tokenstream::TokenTree) {
                     self.hash_token_tree(sub_tt);
                 }
             }
-            tokenstream::TokenTree::Sequence(span, ref sequence_repetition) => {
-                hash_span!(self, span);
-                let tokenstream::SequenceRepetition {
-                    ref tts,
-                    ref separator,
-                    op,
-                    num_captures,
-                } = **sequence_repetition;
-
-                tts.len().hash(self.st);
-                for sub_tt in tts {
-                    self.hash_token_tree(sub_tt);
-                }
-                self.hash_discriminant(separator);
-                if let Some(ref separator) = *separator {
-                    self.hash_token(separator, span);
-                }
-                op.hash(self.st);
-                num_captures.hash(self.st);
-            }
         }
     }
 
@@ -1128,10 +1109,6 @@ fn hash_token(&mut self,
             token::Token::Ident(ident) |
             token::Token::Lifetime(ident) |
             token::Token::SubstNt(ident) => ident.name.as_str().hash(self.st),
-            token::Token::MatchNt(ident1, ident2) => {
-                ident1.name.as_str().hash(self.st);
-                ident2.name.as_str().hash(self.st);
-            }
 
             token::Token::Interpolated(ref non_terminal) => {
                 // FIXME(mw): This could be implemented properly. It's just a
@@ -1166,6 +1143,9 @@ pub fn hash_crate_root_module(&mut self, krate: &'tcx Crate) {
             trait_items: _,
             impl_items: _,
             bodies: _,
+
+            trait_impls: _,
+            trait_default_impl: _,
         } = *krate;
 
         visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
index 60f24b71de2452eb3660dfcb9f743153837d6e7f..673f1ae10843cc4c70bdae676192ff8ee7d0a755 100644 (file)
 pub struct SerializedDepGraph {
     pub edges: Vec<SerializedEdgeSet>,
 
+    /// These are output nodes that have no incoming edges. We track
+    /// these separately so that when we reload all edges, we don't
+    /// lose track of these nodes.
+    pub bootstrap_outputs: Vec<DepNode<DefPathIndex>>,
+
     /// These are hashes of two things:
     /// - the HIR nodes in this crate
     /// - the metadata nodes from dependent crates we use
index a0bcb54af320fa1a1728ff893ca11ee5a4205e6a..156f8b9e7c489a27750f346b7266b86898bc31e4 100644 (file)
@@ -257,6 +257,12 @@ pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> {
 impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         self.check_item(item.id, item.span);
+
+        if let hir::ItemEnum(ref def, _) = item.node {
+            for v in &def.variants {
+                self.check_item(v.node.data.id(), v.span);
+            }
+        }
     }
 
     fn visit_trait_item(&mut self, item: &hir::TraitItem) {
index 7724658a9d6fead0f25ec19c116c9b26fd0e654e..03411e01a57980e4be577309158eaa431dff956e 100644 (file)
@@ -184,6 +184,18 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
     }
 
+    // Recreate bootstrap outputs, which are outputs that have no incoming edges (and hence cannot
+    // be dirty).
+    for bootstrap_output in &serialized_dep_graph.bootstrap_outputs {
+        if let Some(n) = retraced.map(bootstrap_output) {
+            if let DepNode::WorkProduct(ref wp) = n {
+                clean_work_products.insert(wp.clone());
+            }
+
+            tcx.dep_graph.with_task(n, || ()); // create the node with no inputs
+        }
+    }
+
     // Subtle. Sometimes we have intermediate nodes that we can't recreate in the new graph.
     // This is pretty unusual but it arises in a scenario like this:
     //
index a80620fbde66fad189b134e9449e3d8c33283951..f6a37c7a12265469ec0fe9319c3cc814406ba66c 100644 (file)
@@ -11,7 +11,7 @@
 use rustc::dep_graph::{DepGraphQuery, DepNode};
 use rustc::hir::def_id::DefId;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::graph::Graph;
+use rustc_data_structures::graph::{Graph, NodeIndex};
 
 use super::hash::*;
 use ich::Fingerprint;
@@ -28,6 +28,14 @@ pub struct Predecessors<'query> {
     // of the graph down.
     pub reduced_graph: Graph<&'query DepNode<DefId>, ()>,
 
+    // These are output nodes that have no incoming edges. We have to
+    // track these specially because, when we load the data back up
+    // again, we want to make sure and recreate these nodes (we want
+    // to recreate the nodes where all incoming edges are clean; but
+    // since we ordinarily just serialize edges, we wind up just
+    // forgetting that bootstrap outputs even exist in that case.)
+    pub bootstrap_outputs: Vec<&'query DepNode<DefId>>,
+
     // For the inputs (hir/foreign-metadata), we include hashes.
     pub hashes: FxHashMap<&'query DepNode<DefId>, Fingerprint>,
 }
@@ -57,7 +65,7 @@ pub fn new(query: &'q DepGraphQuery<DefId>, hcx: &mut HashContext) -> Self {
 
         // Reduce the graph to the most important nodes.
         let compress::Reduction { graph, input_nodes } =
-            compress::reduce_graph(&query.graph, HashContext::is_hashable, is_output);
+            compress::reduce_graph(&query.graph, HashContext::is_hashable, |n| is_output(n));
 
         let mut hashes = FxHashMap();
         for input_index in input_nodes {
@@ -67,8 +75,17 @@ pub fn new(query: &'q DepGraphQuery<DefId>, hcx: &mut HashContext) -> Self {
                   .or_insert_with(|| hcx.hash(input).unwrap());
         }
 
+        let bootstrap_outputs: Vec<&'q DepNode<DefId>> =
+            (0 .. graph.len_nodes())
+            .map(NodeIndex)
+            .filter(|&n| graph.incoming_edges(n).next().is_none())
+            .map(|n| *graph.node_data(n))
+            .filter(|n| is_output(n))
+            .collect();
+
         Predecessors {
             reduced_graph: graph,
+            bootstrap_outputs: bootstrap_outputs,
             hashes: hashes,
         }
     }
index 34bb125ef3f45d130dd8a53a14162103559f62f7..dfa6bf6bbb5e721d4a1596b109cffd314e4e7ccd 100644 (file)
@@ -204,11 +204,15 @@ pub fn encode_dep_graph(preds: &Predecessors,
     }
 
     // Create the serialized dep-graph.
+    let bootstrap_outputs = preds.bootstrap_outputs.iter()
+                                                   .map(|n| builder.map(n))
+                                                   .collect();
     let edges = edges.into_iter()
                      .map(|(k, v)| SerializedEdgeSet { source: k, targets: v })
                      .collect();
     let graph = SerializedDepGraph {
-        edges: edges,
+        bootstrap_outputs,
+        edges,
         hashes: preds.hashes
             .iter()
             .map(|(&dep_node, &hash)| {
@@ -221,6 +225,7 @@ pub fn encode_dep_graph(preds: &Predecessors,
     };
 
     if tcx.sess.opts.debugging_opts.incremental_info {
+        println!("incremental: {} nodes in reduced dep-graph", preds.reduced_graph.len_nodes());
         println!("incremental: {} edges in serialized dep-graph", graph.edges.len());
         println!("incremental: {} hashes in serialized dep-graph", graph.hashes.len());
     }
index 0c86eb42e7acb745898b530695585c50abdfd224..353b86820c405e3811d9f438cc5a55cd797fdeea 100644 (file)
@@ -29,7 +29,7 @@ pub enum MethodLateContext {
 
 pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext {
     let def_id = cx.tcx.hir.local_def_id(id);
-    match cx.tcx.associated_items.borrow().get(&def_id) {
+    match cx.tcx.maps.associated_item.borrow().get(&def_id) {
         None => span_bug!(span, "missing method descriptor?!"),
         Some(item) => {
             match item.container {
index 1592d178176413622851fd0ce664e4863fde72e7..b3f09c28277ada98725c0c6729d148ee23499fdf 100644 (file)
@@ -523,7 +523,7 @@ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
             }
             _ => return,
         };
-        if def.has_dtor() {
+        if def.has_dtor(cx.tcx) {
             return;
         }
         let parameter_environment = cx.tcx.empty_parameter_environment();
@@ -882,7 +882,7 @@ fn method_call_refers_to_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     let node_id = tcx.hir.as_local_node_id(method.def_id).unwrap();
 
                     let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
-                    tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
+                    tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
                         let mut selcx = traits::SelectionContext::new(&infcx);
                         match selcx.select(&obligation) {
                             // The method comes from a `T: Trait` bound.
@@ -1082,9 +1082,9 @@ fn get_transmute_from_to<'a, 'tcx>
                 }
                 let typ = cx.tables.node_id_to_type(expr.id);
                 match typ.sty {
-                    ty::TyFnDef(.., ref bare_fn) if bare_fn.abi == RustIntrinsic => {
-                        let from = bare_fn.sig.skip_binder().inputs()[0];
-                        let to = bare_fn.sig.skip_binder().output();
+                    ty::TyFnDef(.., bare_fn) if bare_fn.abi() == RustIntrinsic => {
+                        let from = bare_fn.inputs().skip_binder()[0];
+                        let to = *bare_fn.output().skip_binder();
                         return Some((&from.sty, &to.sty));
                     }
                     _ => (),
@@ -1095,7 +1095,7 @@ fn get_transmute_from_to<'a, 'tcx>
 
         fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool {
             match cx.tcx.item_type(def_id).sty {
-                ty::TyFnDef(.., ref bfty) if bfty.abi == RustIntrinsic => (),
+                ty::TyFnDef(.., bfty) if bfty.abi() == RustIntrinsic => (),
                 _ => return false,
             }
             cx.tcx.item_name(def_id) == "transmute"
index 8fb1740e66eacbfccf65cd8991bcd67aaea28130..443a219928f1c04229ed0f728fb9b2c436fafcd3 100644 (file)
@@ -195,10 +195,6 @@ macro_rules! add_lint_group {
             id: LintId::of(SUPER_OR_SELF_IN_GLOBAL_PATH),
             reference: "issue #36888 <https://github.com/rust-lang/rust/issues/36888>",
         },
-        FutureIncompatibleInfo {
-            id: LintId::of(TRANSMUTE_FROM_FN_ITEM_TYPES),
-            reference: "issue #19925 <https://github.com/rust-lang/rust/issues/19925>",
-        },
         FutureIncompatibleInfo {
             id: LintId::of(OVERLAPPING_INHERENT_IMPLS),
             reference: "issue #36889 <https://github.com/rust-lang/rust/issues/36889>",
@@ -247,6 +243,10 @@ macro_rules! add_lint_group {
             id: LintId::of(LEGACY_CONSTRUCTOR_VISIBILITY),
             reference: "issue #39207 <https://github.com/rust-lang/rust/issues/39207>",
         },
+        FutureIncompatibleInfo {
+            id: LintId::of(MISSING_FRAGMENT_SPECIFIER),
+            reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
+        },
         ]);
 
     // Register renamed and removed lints
@@ -260,4 +260,6 @@ macro_rules! add_lint_group {
     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");
+    store.register_removed("transmute_from_fn_item_types",
+        "always cast functions before transmuting them");
 }
index 8feb07953db81b4df59b70fcc0d677136d0b8432..529afe0215e53672eebee1ea1538e3c9c87719ae 100644 (file)
@@ -17,7 +17,6 @@
 use rustc::traits::Reveal;
 use middle::const_val::ConstVal;
 use rustc_const_eval::ConstContext;
-use rustc_const_eval::EvalHint::ExprTypeChecked;
 use util::nodemap::FxHashSet;
 use lint::{LateContext, LintContext, LintArray};
 use lint::{LintPass, LateLintPass};
@@ -109,7 +108,7 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
                             }
                         } else {
                             let const_cx = ConstContext::with_tables(cx.tcx, cx.tables);
-                            match const_cx.eval(&r, ExprTypeChecked) {
+                            match const_cx.eval(&r) {
                                 Ok(ConstVal::Integral(i)) => {
                                     i.is_negative() ||
                                     i.to_u64()
@@ -381,6 +380,17 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     false
 }
 
+fn is_ffi_safe(ty: attr::IntType) -> bool {
+    match ty {
+        attr::SignedInt(ast::IntTy::I8) | attr::UnsignedInt(ast::UintTy::U8) |
+        attr::SignedInt(ast::IntTy::I16) | attr::UnsignedInt(ast::UintTy::U16) |
+        attr::SignedInt(ast::IntTy::I32) | attr::UnsignedInt(ast::UintTy::U32) |
+        attr::SignedInt(ast::IntTy::I64) | attr::UnsignedInt(ast::UintTy::U64) |
+        attr::SignedInt(ast::IntTy::I128) | attr::UnsignedInt(ast::UintTy::U128) => true,
+        attr::SignedInt(ast::IntTy::Is) | attr::UnsignedInt(ast::UintTy::Us) => false
+    }
+}
+
 impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     /// Check if the given type is "ffi-safe" (has a stable, well-defined
     /// representation which can be exported to C code).
@@ -406,7 +416,7 @@ fn check_type_for_ffi(&self,
                 }
                 match def.adt_kind() {
                     AdtKind::Struct => {
-                        if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
+                        if !def.repr.c {
                             return FfiUnsafe("found struct without foreign-function-safe \
                                               representation annotation in foreign module, \
                                               consider adding a #[repr(C)] attribute to the type");
@@ -440,7 +450,7 @@ fn check_type_for_ffi(&self,
                         if all_phantom { FfiPhantom } else { FfiSafe }
                     }
                     AdtKind::Union => {
-                        if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
+                        if !def.repr.c {
                             return FfiUnsafe("found union without foreign-function-safe \
                                               representation annotation in foreign module, \
                                               consider adding a #[repr(C)] attribute to the type");
@@ -479,35 +489,28 @@ fn check_type_for_ffi(&self,
 
                         // Check for a repr() attribute to specify the size of the
                         // discriminant.
-                        let repr_hints = cx.lookup_repr_hints(def.did);
-                        match &repr_hints[..] {
-                            &[] => {
-                                // Special-case types like `Option<extern fn()>`.
-                                if !is_repr_nullable_ptr(cx, def, substs) {
-                                    return FfiUnsafe("found enum without foreign-function-safe \
-                                                      representation annotation in foreign \
-                                                      module, consider adding a #[repr(...)] \
-                                                      attribute to the type");
-                                }
+                        if !def.repr.c && def.repr.int.is_none() {
+                            // Special-case types like `Option<extern fn()>`.
+                            if !is_repr_nullable_ptr(cx, def, substs) {
+                                return FfiUnsafe("found enum without foreign-function-safe \
+                                                  representation annotation in foreign \
+                                                  module, consider adding a #[repr(...)] \
+                                                  attribute to the type");
                             }
-                            &[ref hint] => {
-                                if !hint.is_ffi_safe() {
-                                    // FIXME: This shouldn't be reachable: we should check
-                                    // this earlier.
-                                    return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
-                                }
-
-                                // Enum with an explicitly sized discriminant; either
-                                // a C-style enum or a discriminated union.
+                        }
 
-                                // The layout of enum variants is implicitly repr(C).
-                                // FIXME: Is that correct?
-                            }
-                            _ => {
+                        if let Some(int_ty) = def.repr.int {
+                            if !is_ffi_safe(int_ty) {
                                 // FIXME: This shouldn't be reachable: we should check
                                 // this earlier.
-                                return FfiUnsafe("enum has too many #[repr(...)] attributes");
+                                return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
                             }
+
+                            // Enum with an explicitly sized discriminant; either
+                            // a C-style enum or a discriminated union.
+
+                            // The layout of enum variants is implicitly repr(C).
+                            // FIXME: Is that correct?
                         }
 
                         // Check the contained variants.
@@ -568,8 +571,8 @@ fn check_type_for_ffi(&self,
 
             ty::TyArray(ty, _) => self.check_type_for_ffi(cache, ty),
 
-            ty::TyFnPtr(bare_fn) => {
-                match bare_fn.abi {
+            ty::TyFnPtr(sig) => {
+                match sig.abi() {
                     Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
                         return FfiUnsafe("found function pointer with Rust calling convention in \
                                           foreign module; consider using an `extern` function \
@@ -578,7 +581,7 @@ fn check_type_for_ffi(&self,
                     _ => {}
                 }
 
-                let sig = cx.erase_late_bound_regions(&bare_fn.sig);
+                let sig = cx.erase_late_bound_regions(&sig);
                 if !sig.output().is_nil() {
                     let r = self.check_type_for_ffi(cache, sig.output());
                     match r {
index adf8067987e405ed27597fafc2cce581662bacd2..26c7a9166e68e9280ed8a683cc421944d530de60 100644 (file)
@@ -53,6 +53,7 @@ pub enum CallConv {
     X86_64_SysV = 78,
     X86_64_Win64 = 79,
     X86_VectorCall = 80,
+    X86_Intr = 83,
 }
 
 /// LLVMRustLinkage
index 104d76b1f600d6cd8971d82752898a6f0cf28e01..49dcffb4830a1da67eb69f88b486a2c68091bdc9 100644 (file)
@@ -586,7 +586,7 @@ fn load_derive_macros(&mut self, root: &CrateRoot, dylib: Option<PathBuf>, span:
         use proc_macro::__internal::Registry;
         use rustc_back::dynamic_lib::DynamicLibrary;
         use syntax_ext::deriving::custom::ProcMacroDerive;
-        use syntax_ext::proc_macro_impl::AttrProcMacro;
+        use syntax_ext::proc_macro_impl::{AttrProcMacro, BangProcMacro};
 
         let path = match dylib {
             Some(dylib) => dylib,
@@ -630,6 +630,15 @@ fn register_attr_proc_macro(&mut self,
                 );
                 self.0.push((Symbol::intern(name), Rc::new(expand)));
             }
+
+            fn register_bang_proc_macro(&mut self,
+                                        name: &str,
+                                        expand: fn(TokenStream) -> TokenStream) {
+                let expand = SyntaxExtension::ProcMacro(
+                    Box::new(BangProcMacro { inner: expand })
+                );
+                self.0.push((Symbol::intern(name), Rc::new(expand)));
+            }
         }
 
         let mut my_registrar = MyRegistrar(Vec::new());
@@ -1077,10 +1086,20 @@ fn postprocess(&mut self, krate: &ast::Crate) {
             let mut found = false;
             for lib in self.cstore.get_used_libraries().borrow_mut().iter_mut() {
                 if lib.name == name as &str {
-                    lib.kind = kind;
+                    let mut changed = false;
+                    if let Some(k) = kind {
+                        lib.kind = k;
+                        changed = true;
+                    }
                     if let &Some(ref new_name) = new_name {
                         lib.name = Symbol::intern(new_name);
+                        changed = true;
                     }
+                    if !changed {
+                        self.sess.warn(&format!("redundant linker flag specified for library `{}`",
+                                                name));
+                    }
+
                     found = true;
                 }
             }
@@ -1089,7 +1108,7 @@ fn postprocess(&mut self, krate: &ast::Crate) {
                 let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
                 let lib = NativeLibrary {
                     name: Symbol::intern(new_name.unwrap_or(name)),
-                    kind: kind,
+                    kind: if let Some(k) = kind { k } else { cstore::NativeUnknown },
                     cfg: None,
                     foreign_items: Vec::new(),
                 };
index 4709ca6101c7908f11e8ce5ef7e9cd5a96d090ec..bb30245df5f56315a1069c07c9da2d607626795c 100644 (file)
@@ -35,6 +35,8 @@
 pub use rustc::middle::cstore::NativeLibraryKind::*;
 pub use rustc::middle::cstore::{CrateSource, LinkMeta, LibSource};
 
+pub use cstore_impl::provide;
+
 // A map from external crate numbers (as decoded from some crate file) to
 // local crate numbers (as generated during this session). Each external
 // crate may refer to types in other external crates, and each has their
index 7b0177bfd23ed966a2b4fef4a5e6195770e7edb5..7b02280ef904bda504369b93dd1bb07a42428fa4 100644 (file)
 use locator;
 use schema;
 
+use rustc::dep_graph::DepTrackingMapConfig;
 use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, ExternCrate};
 use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro};
 use rustc::hir::def::{self, Def};
 use rustc::middle::lang_items;
-use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
 use rustc::session::Session;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, TyCtxt};
+use rustc::ty::maps::Providers;
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 
 use rustc::dep_graph::DepNode;
 use rustc::hir::map::{DefKey, DefPath, DisambiguatedDefPathData};
-use rustc::mir::Mir;
 use rustc::util::nodemap::{NodeSet, DefIdMap};
 use rustc_back::PanicStrategy;
 
+use std::any::Any;
+use std::mem;
+use std::rc::Rc;
+
 use syntax::ast;
 use syntax::attr;
 use syntax::parse::filemap_to_tts;
 
 use std::collections::BTreeMap;
 
-impl<'tcx> CrateStore<'tcx> for cstore::CStore {
-    fn describe_def(&self, def: DefId) -> Option<Def> {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_def(def.index)
-    }
-
-    fn def_span(&self, sess: &Session, def: DefId) -> Span {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_span(def.index, sess)
-    }
-
-    fn stability(&self, def: DefId) -> Option<attr::Stability> {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_stability(def.index)
+macro_rules! provide {
+    (<$lt:tt> $tcx:ident, $def_id:ident, $cdata:ident $($name:ident => $compute:block)*) => {
+        pub fn provide<$lt>(providers: &mut Providers<$lt>) {
+            $(fn $name<'a, $lt:$lt>($tcx: TyCtxt<'a, $lt, $lt>, $def_id: DefId)
+                                    -> <ty::queries::$name<$lt> as
+                                        DepTrackingMapConfig>::Value {
+                assert!(!$def_id.is_local());
+
+                $tcx.dep_graph.read(DepNode::MetaData($def_id));
+
+                let $cdata = $tcx.sess.cstore.crate_data_as_rc_any($def_id.krate);
+                let $cdata = $cdata.downcast_ref::<cstore::CrateMetadata>()
+                    .expect("CrateStore crated ata is not a CrateMetadata");
+                $compute
+            })*
+
+            *providers = Providers {
+                $($name,)*
+                ..*providers
+            };
+        }
     }
+}
 
-    fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_deprecation(def.index)
+provide! { <'tcx> tcx, def_id, cdata
+    ty => { cdata.get_type(def_id.index, tcx) }
+    generics => { tcx.alloc_generics(cdata.get_generics(def_id.index)) }
+    predicates => { cdata.get_predicates(def_id.index, tcx) }
+    super_predicates => { cdata.get_super_predicates(def_id.index, tcx) }
+    trait_def => {
+        tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx))
+    }
+    adt_def => { cdata.get_adt_def(def_id.index, tcx) }
+    variances => { Rc::new(cdata.get_item_variances(def_id.index)) }
+    associated_item_def_ids => {
+        let mut result = vec![];
+        cdata.each_child_of_item(def_id.index, |child| result.push(child.def.def_id()));
+        Rc::new(result)
+    }
+    associated_item => { cdata.get_associated_item(def_id.index) }
+    impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
+    custom_coerce_unsized_kind => {
+        cdata.get_custom_coerce_unsized_kind(def_id.index).unwrap_or_else(|| {
+            bug!("custom_coerce_unsized_kind: `{:?}` is missing its kind", def_id);
+        })
     }
+    mir => {
+        let mir = cdata.maybe_get_item_mir(tcx, def_id.index).unwrap_or_else(|| {
+            bug!("get_item_mir: missing MIR for `{:?}`", def_id)
+        });
 
-    fn visibility(&self, def: DefId) -> ty::Visibility {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_visibility(def.index)
-    }
+        let mir = tcx.alloc_mir(mir);
 
-    fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind
-    {
-        assert!(!def_id.is_local());
-        self.dep_graph.read(DepNode::MetaData(def_id));
-        self.get_crate_data(def_id.krate).closure_kind(def_id.index)
-    }
+        // Perma-borrow MIR from extern crates to prevent mutation.
+        mem::forget(mir.borrow());
 
-    fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> {
-        assert!(!def_id.is_local());
-        self.dep_graph.read(DepNode::MetaData(def_id));
-        self.get_crate_data(def_id.krate).closure_ty(def_id.index, tcx)
+        mir
     }
+    mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
+    typeck_tables => { cdata.item_body_tables(def_id.index, tcx) }
+    closure_kind => { cdata.closure_kind(def_id.index) }
+    closure_type => { cdata.closure_ty(def_id.index, tcx) }
+}
 
-    fn item_variances(&self, def: DefId) -> Vec<ty::Variance> {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_item_variances(def.index)
+impl CrateStore for cstore::CStore {
+    fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any> {
+        self.get_crate_data(krate)
     }
 
-    fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                     -> Ty<'tcx>
-    {
+    fn describe_def(&self, def: DefId) -> Option<Def> {
         self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_type(def.index, tcx)
+        self.get_crate_data(def.krate).get_def(def.index)
     }
 
-    fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                           -> ty::GenericPredicates<'tcx>
-    {
+    fn def_span(&self, sess: &Session, def: DefId) -> Span {
         self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_predicates(def.index, tcx)
+        self.get_crate_data(def.krate).get_span(def.index, sess)
     }
 
-    fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                                 -> ty::GenericPredicates<'tcx>
-    {
+    fn stability(&self, def: DefId) -> Option<attr::Stability> {
         self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_super_predicates(def.index, tcx)
+        self.get_crate_data(def.krate).get_stability(def.index)
     }
 
-    fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                         -> ty::Generics<'tcx>
-    {
+    fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> {
         self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_generics(def.index, tcx)
+        self.get_crate_data(def.krate).get_deprecation(def.index)
     }
 
-    fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize) {
+    fn visibility(&self, def: DefId) -> ty::Visibility {
         self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).generics_own_param_counts(def.index)
+        self.get_crate_data(def.krate).get_visibility(def.index)
     }
 
-    fn item_generics_object_lifetime_defaults(&self, def: DefId)
-                                              -> Vec<ObjectLifetimeDefault> {
+    fn item_generics_cloned(&self, def: DefId) -> ty::Generics {
         self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).generics_object_lifetime_defaults(def.index)
+        self.get_crate_data(def.krate).get_generics(def.index)
     }
 
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>
@@ -128,18 +148,6 @@ fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>
         self.get_crate_data(def_id.krate).get_item_attrs(def_id.index)
     }
 
-    fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::TraitDef
-    {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_trait_def(def.index, tcx)
-    }
-
-    fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef
-    {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_adt_def(def.index, tcx)
-    }
-
     fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>
     {
         // FIXME(#38501) We've skipped a `read` on the `HirBody` of
@@ -168,34 +176,12 @@ fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>
         result
     }
 
-    fn associated_item_def_ids(&self, def_id: DefId) -> Vec<DefId> {
-        self.dep_graph.read(DepNode::MetaData(def_id));
-        let mut result = vec![];
-        self.get_crate_data(def_id.krate)
-            .each_child_of_item(def_id.index, |child| result.push(child.def.def_id()));
-        result
-    }
-
     fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity
     {
         self.dep_graph.read(DepNode::MetaData(def));
         self.get_crate_data(def.krate).get_impl_polarity(def.index)
     }
 
-    fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                          -> Option<ty::TraitRef<'tcx>>
-    {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_impl_trait(def.index, tcx)
-    }
-
-    fn custom_coerce_unsized_kind(&self, def: DefId)
-                                  -> Option<ty::adjustment::CustomCoerceUnsized>
-    {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_custom_coerce_unsized_kind(def.index)
-    }
-
     fn impl_parent(&self, impl_def: DefId) -> Option<DefId> {
         self.dep_graph.read(DepNode::MetaData(impl_def));
         self.get_crate_data(impl_def.krate).get_parent_impl(impl_def.index)
@@ -206,7 +192,7 @@ fn trait_of_item(&self, def_id: DefId) -> Option<DefId> {
         self.get_crate_data(def_id.krate).get_trait_of_item(def_id.index)
     }
 
-    fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem>
+    fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem
     {
         self.dep_graph.read(DepNode::MetaData(def));
         self.get_crate_data(def.krate).get_associated_item(def.index)
@@ -218,12 +204,6 @@ fn is_const_fn(&self, did: DefId) -> bool
         self.get_crate_data(did.krate).is_const_fn(did.index)
     }
 
-    fn is_defaulted_trait(&self, trait_def_id: DefId) -> bool
-    {
-        self.dep_graph.read(DepNode::MetaData(trait_def_id));
-        self.get_crate_data(trait_def_id.krate).is_defaulted_trait(trait_def_id.index)
-    }
-
     fn is_default_impl(&self, impl_did: DefId) -> bool {
         self.dep_graph.read(DepNode::MetaData(impl_did));
         self.get_crate_data(impl_did.krate).is_default_impl(impl_did.index)
@@ -439,10 +419,10 @@ fn load_macro(&self, id: DefId, sess: &Session) -> LoadedMacro {
         })
     }
 
-    fn maybe_get_item_body<'a>(&'tcx self,
-                               tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                               def_id: DefId)
-                               -> Option<&'tcx hir::Body>
+    fn maybe_get_item_body<'a, 'tcx>(&self,
+                                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                     def_id: DefId)
+                                     -> Option<&'tcx hir::Body>
     {
         if let Some(cached) = tcx.hir.get_inlined_body(def_id) {
             return Some(cached);
@@ -464,13 +444,6 @@ fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool {
         self.get_crate_data(def.krate).const_is_rvalue_promotable_to_static(def.index)
     }
 
-    fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx> {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).maybe_get_item_mir(tcx, def.index).unwrap_or_else(|| {
-            bug!("get_item_mir: missing MIR for {}", tcx.item_path_str(def))
-        })
-    }
-
     fn is_item_mir_available(&self, def: DefId) -> bool {
         self.dep_graph.read(DepNode::MetaData(def));
         self.get_crate_data(def.krate).is_item_mir_available(def.index)
@@ -518,10 +491,10 @@ fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum>
         self.do_extern_mod_stmt_cnum(emod_id)
     }
 
-    fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                           reexports: &def::ExportMap,
-                           link_meta: &LinkMeta,
-                           reachable: &NodeSet) -> Vec<u8>
+    fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                 reexports: &def::ExportMap,
+                                 link_meta: &LinkMeta,
+                                 reachable: &NodeSet) -> Vec<u8>
     {
         encoder::encode_metadata(tcx, self, reexports, link_meta, reachable)
     }
index abc3ffcf86b11d49c35fdb405d7f11079ce06275..b4b9966cbe47b98138d8ad1afe0e3b047d5537a6 100644 (file)
@@ -20,7 +20,6 @@
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc::middle::lang_items;
-use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
 use rustc::session::Session;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::Substs;
@@ -39,6 +38,7 @@
 use syntax::attr;
 use syntax::ast;
 use syntax::codemap;
+use syntax::ext::base::MacroKind;
 use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP};
 
 pub struct DecodeContext<'a, 'tcx: 'a> {
@@ -363,12 +363,6 @@ fn specialized_decode(&mut self) -> Result<&'tcx ty::Slice<Ty<'tcx>>, Self::Erro
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::BareFnTy<'tcx>> for DecodeContext<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<&'tcx ty::BareFnTy<'tcx>, Self::Error> {
-        Ok(self.tcx().mk_bare_fn(Decodable::decode(self)?))
-    }
-}
-
 impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::AdtDef> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<&'tcx ty::AdtDef, Self::Error> {
         let def_id = DefId::decode(self)?;
@@ -417,8 +411,8 @@ pub fn list_crate_metadata(&self, out: &mut io::Write) -> io::Result<()> {
 impl<'tcx> EntryKind<'tcx> {
     fn to_def(&self, did: DefId) -> Option<Def> {
         Some(match *self {
-            EntryKind::Const => Def::Const(did),
-            EntryKind::AssociatedConst(_) => Def::AssociatedConst(did),
+            EntryKind::Const(_) => Def::Const(did),
+            EntryKind::AssociatedConst(..) => Def::AssociatedConst(did),
             EntryKind::ImmStatic |
             EntryKind::ForeignImmStatic => Def::Static(did, false),
             EntryKind::MutStatic |
@@ -434,7 +428,7 @@ fn to_def(&self, did: DefId) -> Option<Def> {
             EntryKind::Variant(_) => Def::Variant(did),
             EntryKind::Trait(_) => Def::Trait(did),
             EntryKind::Enum(..) => Def::Enum(did),
-            EntryKind::MacroDef(_) => Def::Macro(did),
+            EntryKind::MacroDef(_) => Def::Macro(did, MacroKind::Bang),
 
             EntryKind::ForeignMod |
             EntryKind::Impl(_) |
@@ -483,9 +477,11 @@ fn item_name(&self, item_index: DefIndex) -> ast::Name {
     }
 
     pub fn get_def(&self, index: DefIndex) -> Option<Def> {
-        match self.is_proc_macro(index) {
-            true => Some(Def::Macro(self.local_def_id(index))),
-            false => self.entry(index).kind.to_def(self.local_def_id(index)),
+        if !self.is_proc_macro(index) {
+            self.entry(index).kind.to_def(self.local_def_id(index))
+        } else {
+            let kind = self.proc_macros.as_ref().unwrap()[index.as_usize() - 1].1.kind();
+            Some(Def::Macro(self.local_def_id(index), kind))
         }
     }
 
@@ -505,15 +501,22 @@ pub fn get_trait_def(&self,
             _ => bug!(),
         };
 
-        ty::TraitDef::new(self.local_def_id(item_id),
-                          data.unsafety,
-                          data.paren_sugar,
-                          self.def_path(item_id).deterministic_hash(tcx))
+        let def = ty::TraitDef::new(self.local_def_id(item_id),
+                                    data.unsafety,
+                                    data.paren_sugar,
+                                    self.def_path(item_id).deterministic_hash(tcx));
+
+        if data.has_default_impl {
+            def.record_has_default_impl();
+        }
+
+        def
     }
 
     fn get_variant(&self,
                    item: &Entry<'tcx>,
-                   index: DefIndex)
+                   index: DefIndex,
+                   tcx: TyCtxt<'a, 'tcx, 'tcx>)
                    -> (ty::VariantDef, Option<DefIndex>) {
         let data = match item.kind {
             EntryKind::Variant(data) |
@@ -522,6 +525,11 @@ fn get_variant(&self,
             _ => bug!(),
         };
 
+        if let ty::VariantDiscr::Explicit(def_id) = data.discr {
+            let result = data.evaluated_discr.map_or(Err(()), Ok);
+            tcx.maps.monomorphic_const_eval.borrow_mut().insert(def_id, result);
+        }
+
         (ty::VariantDef {
             did: self.local_def_id(data.struct_ctor.unwrap_or(index)),
             name: self.item_name(index),
@@ -533,7 +541,7 @@ fn get_variant(&self,
                     vis: f.visibility.decode(self)
                 }
             }).collect(),
-            disr_val: data.disr,
+            discr: data.discr,
             ctor_kind: data.ctor_kind,
         }, data.struct_ctor)
     }
@@ -544,10 +552,10 @@ pub fn get_adt_def(&self,
                        -> &'tcx ty::AdtDef {
         let item = self.entry(item_id);
         let did = self.local_def_id(item_id);
-        let (kind, ty) = match item.kind {
-            EntryKind::Enum(dt, _) => (ty::AdtKind::Enum, Some(dt.decode(self))),
-            EntryKind::Struct(_, _) => (ty::AdtKind::Struct, None),
-            EntryKind::Union(_, _) => (ty::AdtKind::Union, None),
+        let kind = match item.kind {
+            EntryKind::Enum(_) => ty::AdtKind::Enum,
+            EntryKind::Struct(_, _) => ty::AdtKind::Struct,
+            EntryKind::Union(_, _) => ty::AdtKind::Union,
             _ => bug!("get_adt_def called on a non-ADT {:?}", did),
         };
         let mut ctor_index = None;
@@ -555,27 +563,28 @@ pub fn get_adt_def(&self,
             item.children
                 .decode(self)
                 .map(|index| {
-                    let (variant, struct_ctor) = self.get_variant(&self.entry(index), index);
+                    let (variant, struct_ctor) =
+                        self.get_variant(&self.entry(index), index, tcx);
                     assert_eq!(struct_ctor, None);
                     variant
                 })
                 .collect()
         } else {
-            let (variant, struct_ctor) = self.get_variant(&item, item_id);
+            let (variant, struct_ctor) = self.get_variant(&item, item_id, tcx);
             ctor_index = struct_ctor;
             vec![variant]
         };
         let (kind, repr) = match item.kind {
-            EntryKind::Enum(_, repr) => (ty::AdtKind::Enum, repr),
+            EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr),
             EntryKind::Struct(_, repr) => (ty::AdtKind::Struct, repr),
             EntryKind::Union(_, repr) => (ty::AdtKind::Union, repr),
             _ => bug!("get_adt_def called on a non-ADT {:?}", did),
         };
 
-        let adt = tcx.alloc_adt_def(did, kind, ty, variants, repr);
+        let adt = tcx.alloc_adt_def(did, kind, variants, repr);
         if let Some(ctor_index) = ctor_index {
             // Make adt definition available through constructor id as well.
-            tcx.adt_defs.borrow_mut().insert(self.local_def_id(ctor_index), adt);
+            tcx.maps.adt_def.borrow_mut().insert(self.local_def_id(ctor_index), adt);
         }
 
         adt
@@ -598,30 +607,8 @@ pub fn get_super_predicates(&self,
         }
     }
 
-    pub fn get_generics(&self,
-                        item_id: DefIndex,
-                        tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                        -> ty::Generics<'tcx> {
-        let g = self.entry(item_id).generics.unwrap().decode(self);
-        ty::Generics {
-            parent: g.parent,
-            parent_regions: g.parent_regions,
-            parent_types: g.parent_types,
-            regions: g.regions.decode((self, tcx)).collect(),
-            types: g.types.decode((self, tcx)).collect(),
-            has_self: g.has_self,
-        }
-    }
-
-    pub fn generics_own_param_counts(&self, item_id: DefIndex) -> (usize, usize) {
-        let g = self.entry(item_id).generics.unwrap().decode(self);
-        (g.regions.len, g.types.len)
-    }
-
-    pub fn generics_object_lifetime_defaults(&self, item_id: DefIndex)
-                                             -> Vec<ObjectLifetimeDefault> {
+    pub fn get_generics(&self, item_id: DefIndex) -> ty::Generics {
         self.entry(item_id).generics.unwrap().decode(self)
-                           .object_lifetime_defaults.decode(self).collect()
     }
 
     pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
@@ -688,8 +675,14 @@ pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F)
     {
         if let Some(ref proc_macros) = self.proc_macros {
             if id == CRATE_DEF_INDEX {
-                for (id, &(name, _)) in proc_macros.iter().enumerate() {
-                    let def = Def::Macro(DefId { krate: self.cnum, index: DefIndex::new(id + 1) });
+                for (id, &(name, ref ext)) in proc_macros.iter().enumerate() {
+                    let def = Def::Macro(
+                        DefId {
+                            krate: self.cnum,
+                            index: DefIndex::new(id + 1)
+                        },
+                        ext.kind()
+                    );
                     callback(def::Export { name: name, def: def });
                 }
             }
@@ -793,16 +786,19 @@ pub fn maybe_get_item_body(&self,
         if self.is_proc_macro(id) { return None; }
         self.entry(id).ast.map(|ast| {
             let def_id = self.local_def_id(id);
-            let ast = ast.decode(self);
-
-            let tables = ast.tables.decode((self, tcx));
-            tcx.tables.borrow_mut().insert(def_id, tcx.alloc_tables(tables));
-
-            let body = ast.body.decode((self, tcx));
+            let body = ast.decode(self).body.decode(self);
             tcx.hir.intern_inlined_body(def_id, body)
         })
     }
 
+    pub fn item_body_tables(&self,
+                            id: DefIndex,
+                            tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                            -> &'tcx ty::TypeckTables<'tcx> {
+        let ast = self.entry(id).ast.unwrap().decode(self);
+        tcx.alloc_tables(ast.tables.decode((self, tcx)))
+    }
+
     pub fn item_body_nested_bodies(&self, id: DefIndex) -> BTreeMap<hir::BodyId, hir::Body> {
         self.entry(id).ast.into_iter().flat_map(|ast| {
             ast.decode(self).nested_bodies.decode(self).map(|body| (body.id(), body))
@@ -829,54 +825,46 @@ pub fn maybe_get_item_mir(&self,
         }
     }
 
-    pub fn get_associated_item(&self, id: DefIndex) -> Option<ty::AssociatedItem> {
+    pub fn mir_const_qualif(&self, id: DefIndex) -> u8 {
+        match self.entry(id).kind {
+            EntryKind::Const(qualif) |
+            EntryKind::AssociatedConst(AssociatedContainer::ImplDefault, qualif) |
+            EntryKind::AssociatedConst(AssociatedContainer::ImplFinal, qualif) => {
+                qualif
+            }
+            _ => bug!(),
+        }
+    }
+
+    pub fn get_associated_item(&self, id: DefIndex) -> ty::AssociatedItem {
         let item = self.entry(id);
-        let parent_and_name = || {
-            let def_key = self.def_key(id);
-            (self.local_def_id(def_key.parent.unwrap()),
-             def_key.disambiguated_data.data.get_opt_name().unwrap())
-        };
+        let def_key = self.def_key(id);
+        let parent = self.local_def_id(def_key.parent.unwrap());
+        let name = def_key.disambiguated_data.data.get_opt_name().unwrap();
 
-        Some(match item.kind {
-            EntryKind::AssociatedConst(container) => {
-                let (parent, name) = parent_and_name();
-                ty::AssociatedItem {
-                    name: name,
-                    kind: ty::AssociatedKind::Const,
-                    vis: item.visibility.decode(self),
-                    defaultness: container.defaultness(),
-                    def_id: self.local_def_id(id),
-                    container: container.with_def_id(parent),
-                    method_has_self_argument: false
-                }
+        let (kind, container, has_self) = match item.kind {
+            EntryKind::AssociatedConst(container, _) => {
+                (ty::AssociatedKind::Const, container, false)
             }
             EntryKind::Method(data) => {
-                let (parent, name) = parent_and_name();
                 let data = data.decode(self);
-                ty::AssociatedItem {
-                    name: name,
-                    kind: ty::AssociatedKind::Method,
-                    vis: item.visibility.decode(self),
-                    defaultness: data.container.defaultness(),
-                    def_id: self.local_def_id(id),
-                    container: data.container.with_def_id(parent),
-                    method_has_self_argument: data.has_self
-                }
+                (ty::AssociatedKind::Method, data.container, data.has_self)
             }
             EntryKind::AssociatedType(container) => {
-                let (parent, name) = parent_and_name();
-                ty::AssociatedItem {
-                    name: name,
-                    kind: ty::AssociatedKind::Type,
-                    vis: item.visibility.decode(self),
-                    defaultness: container.defaultness(),
-                    def_id: self.local_def_id(id),
-                    container: container.with_def_id(parent),
-                    method_has_self_argument: false
-                }
+                (ty::AssociatedKind::Type, container, false)
             }
-            _ => return None,
-        })
+            _ => bug!()
+        };
+
+        ty::AssociatedItem {
+            name: name,
+            kind: kind,
+            vis: item.visibility.decode(self),
+            defaultness: container.defaultness(),
+            def_id: self.local_def_id(id),
+            container: container.with_def_id(parent),
+            method_has_self_argument: has_self
+        }
     }
 
     pub fn get_item_variances(&self, id: DefIndex) -> Vec<ty::Variance> {
@@ -1056,13 +1044,6 @@ pub fn is_dllimport_foreign_item(&self, id: DefIndex) -> bool {
         self.dllimport_foreign_items.contains(&id)
     }
 
-    pub fn is_defaulted_trait(&self, trait_id: DefIndex) -> bool {
-        match self.entry(trait_id).kind {
-            EntryKind::Trait(data) => data.decode(self).has_default_impl,
-            _ => bug!(),
-        }
-    }
-
     pub fn is_default_impl(&self, impl_id: DefIndex) -> bool {
         match self.entry(impl_id).kind {
             EntryKind::DefaultImpl(_) => true,
@@ -1080,7 +1061,7 @@ pub fn closure_kind(&self, closure_id: DefIndex) -> ty::ClosureKind {
     pub fn closure_ty(&self,
                       closure_id: DefIndex,
                       tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                      -> ty::ClosureTy<'tcx> {
+                      -> ty::PolyFnSig<'tcx> {
         match self.entry(closure_id).kind {
             EntryKind::Closure(data) => data.decode(self).ty.decode((self, tcx)),
             _ => bug!(),
index 0f9491aaf15b4385b2ffde92b21500fcd5342954..af0edab7a83bd9eee79893a85d7b8c3d40b9189b 100644 (file)
@@ -36,7 +36,7 @@
 use syntax::codemap::Spanned;
 use syntax::attr;
 use syntax::symbol::Symbol;
-use syntax_pos;
+use syntax_pos::{self, DUMMY_SP};
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
@@ -261,7 +261,13 @@ fn encode_enum_variant_info(&mut self,
 
         let data = VariantData {
             ctor_kind: variant.ctor_kind,
-            disr: variant.disr_val,
+            discr: variant.discr,
+            evaluated_discr: match variant.discr {
+                ty::VariantDiscr::Explicit(def_id) => {
+                    ty::queries::monomorphic_const_eval::get(tcx, DUMMY_SP, def_id).ok()
+                }
+                ty::VariantDiscr::Relative(_) => None
+            },
             struct_ctor: None,
         };
 
@@ -388,7 +394,8 @@ fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<
 
         let data = VariantData {
             ctor_kind: variant.ctor_kind,
-            disr: variant.disr_val,
+            discr: variant.discr,
+            evaluated_discr: None,
             struct_ctor: Some(def_id.index),
         };
 
@@ -423,26 +430,9 @@ fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<
         }
     }
 
-    fn encode_generics(&mut self, def_id: DefId) -> Lazy<Generics<'tcx>> {
+    fn encode_generics(&mut self, def_id: DefId) -> Lazy<ty::Generics> {
         let tcx = self.tcx;
-        let g = tcx.item_generics(def_id);
-        let regions = self.lazy_seq_ref(&g.regions);
-        let types = self.lazy_seq_ref(&g.types);
-        let mut object_lifetime_defaults = LazySeq::empty();
-        if let Some(id) = tcx.hir.as_local_node_id(def_id) {
-            if let Some(o) = tcx.named_region_map.object_lifetime_defaults.get(&id) {
-                object_lifetime_defaults = self.lazy_seq_ref(o);
-            }
-        }
-        self.lazy(&Generics {
-            parent: g.parent,
-            parent_regions: g.parent_regions,
-            parent_types: g.parent_types,
-            regions: regions,
-            types: types,
-            has_self: g.has_self,
-            object_lifetime_defaults: object_lifetime_defaults,
-        })
+        self.lazy(tcx.item_generics(def_id))
     }
 
     fn encode_predicates(&mut self, def_id: DefId) -> Lazy<ty::GenericPredicates<'tcx>> {
@@ -467,7 +457,9 @@ fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> {
         };
 
         let kind = match trait_item.kind {
-            ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
+            ty::AssociatedKind::Const => {
+                EntryKind::AssociatedConst(container, 0)
+            }
             ty::AssociatedKind::Method => {
                 let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node {
                     let arg_names = match *m {
@@ -543,7 +535,10 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
         };
 
         let kind = match impl_item.kind {
-            ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
+            ty::AssociatedKind::Const => {
+                EntryKind::AssociatedConst(container,
+                    ty::queries::mir_const_qualif::get(self.tcx, ast_item.span, def_id))
+            }
             ty::AssociatedKind::Method => {
                 let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
                     FnData {
@@ -614,12 +609,12 @@ fn encode_fn_arg_names(&mut self, names: &[Spanned<ast::Name>])
     }
 
     fn encode_mir(&mut self, def_id: DefId) -> Option<Lazy<mir::Mir<'tcx>>> {
-        self.tcx.mir_map.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow()))
+        self.tcx.maps.mir.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow()))
     }
 
     // Encodes the inherent implementations of a structure, enumeration, or trait.
     fn encode_inherent_implementations(&mut self, def_id: DefId) -> LazySeq<DefIndex> {
-        match self.tcx.inherent_impls.borrow().get(&def_id) {
+        match self.tcx.maps.inherent_impls.borrow().get(&def_id) {
             None => LazySeq::empty(),
             Some(implementations) => {
                 self.lazy_seq(implementations.iter().map(|&def_id| {
@@ -647,7 +642,9 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
         let kind = match item.node {
             hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic,
             hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic,
-            hir::ItemConst(..) => EntryKind::Const,
+            hir::ItemConst(..) => {
+                EntryKind::Const(ty::queries::mir_const_qualif::get(tcx, item.span, def_id))
+            }
             hir::ItemFn(_, _, constness, .., body) => {
                 let data = FnData {
                     constness: constness,
@@ -661,8 +658,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
             }
             hir::ItemForeignMod(_) => EntryKind::ForeignMod,
             hir::ItemTy(..) => EntryKind::Type,
-            hir::ItemEnum(..) => EntryKind::Enum(self.lazy(&tcx.lookup_adt_def(def_id).discr_ty),
-                                                 get_repr_options(&tcx, def_id)),
+            hir::ItemEnum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)),
             hir::ItemStruct(ref struct_def, _) => {
                 let variant = tcx.lookup_adt_def(def_id).struct_variant();
 
@@ -679,7 +675,8 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
 
                 EntryKind::Struct(self.lazy(&VariantData {
                     ctor_kind: variant.ctor_kind,
-                    disr: variant.disr_val,
+                    discr: variant.discr,
+                    evaluated_discr: None,
                     struct_ctor: struct_ctor,
                 }), repr_options)
             }
@@ -689,7 +686,8 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
 
                 EntryKind::Union(self.lazy(&VariantData {
                     ctor_kind: variant.ctor_kind,
-                    disr: variant.disr_val,
+                    discr: variant.discr,
+                    evaluated_discr: None,
                     struct_ctor: None,
                 }), repr_options)
             }
@@ -720,7 +718,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
                 let data = ImplData {
                     polarity: polarity,
                     parent_impl: parent,
-                    coerce_unsized_kind: tcx.custom_coerce_unsized_kinds
+                    coerce_unsized_kind: tcx.maps.custom_coerce_unsized_kind
                         .borrow()
                         .get(&def_id)
                         .cloned(),
@@ -1008,6 +1006,10 @@ fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) {
                           EncodeContext::encode_info_for_foreign_item,
                           (def_id, ni));
     }
+    fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
+        intravisit::walk_generics(self, generics);
+        self.index.encode_info_for_generics(generics);
+    }
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
         intravisit::walk_ty(self, ty);
         self.index.encode_info_for_ty(ty);
@@ -1019,6 +1021,14 @@ fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef) {
 }
 
 impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
+    fn encode_info_for_generics(&mut self, generics: &hir::Generics) {
+        for ty_param in &generics.ty_params {
+            let def_id = self.tcx.hir.local_def_id(ty_param.id);
+            let has_default = Untracked(ty_param.default.is_some());
+            self.record(def_id, EncodeContext::encode_info_for_ty_param, (def_id, has_default));
+        }
+    }
+
     fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
         if let hir::TyImplTrait(_) = ty.node {
             let def_id = self.tcx.hir.local_def_id(ty.id);
@@ -1038,6 +1048,34 @@ fn encode_info_for_expr(&mut self, expr: &hir::Expr) {
 }
 
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+    fn encode_info_for_ty_param(&mut self,
+                                (def_id, Untracked(has_default)): (DefId, Untracked<bool>))
+                                -> Entry<'tcx> {
+        let tcx = self.tcx;
+        Entry {
+            kind: EntryKind::Type,
+            visibility: self.lazy(&ty::Visibility::Public),
+            span: self.lazy(&tcx.def_span(def_id)),
+            attributes: LazySeq::empty(),
+            children: LazySeq::empty(),
+            stability: None,
+            deprecation: None,
+
+            ty: if has_default {
+                Some(self.encode_item_type(def_id))
+            } else {
+                None
+            },
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: None,
+            predicates: None,
+
+            ast: None,
+            mir: None,
+        }
+    }
+
     fn encode_info_for_anon_ty(&mut self, def_id: DefId) -> Entry<'tcx> {
         let tcx = self.tcx;
         Entry {
@@ -1065,7 +1103,7 @@ fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'tcx> {
 
         let data = ClosureData {
             kind: tcx.closure_kind(def_id),
-            ty: self.lazy(&tcx.closure_tys.borrow()[&def_id]),
+            ty: self.lazy(&tcx.closure_type(def_id)),
         };
 
         Entry {
index 2fbdb8c0de676dec7f7921e3037e9c6410811c0f..0ce886ce9e9dfc92a8ad9c35a4a5c76b22478eb3 100644 (file)
@@ -20,6 +20,7 @@
 #![feature(box_patterns)]
 #![feature(conservative_impl_trait)]
 #![feature(core_intrinsics)]
+#![cfg_attr(stage0, feature(field_init_shorthand))]
 #![feature(i128_type)]
 #![feature(proc_macro_internals)]
 #![feature(quote)]
index 777af02772ec17565a15c677ba691145d182e330..4a20913d0b3fd19e16cef779f1817c42880f1a81 100644 (file)
@@ -14,9 +14,9 @@
 use rustc::hir;
 use rustc::hir::def::{self, CtorKind};
 use rustc::hir::def_id::{DefIndex, DefId};
+use rustc::middle::const_val::ConstVal;
 use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
 use rustc::middle::lang_items;
-use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
 use rustc::mir;
 use rustc::ty::{self, Ty, ReprOptions};
 use rustc_back::PanicStrategy;
@@ -212,7 +212,7 @@ pub struct Entry<'tcx> {
     pub ty: Option<Lazy<Ty<'tcx>>>,
     pub inherent_impls: LazySeq<DefIndex>,
     pub variances: LazySeq<ty::Variance>,
-    pub generics: Option<Lazy<Generics<'tcx>>>,
+    pub generics: Option<Lazy<ty::Generics>>,
     pub predicates: Option<Lazy<ty::GenericPredicates<'tcx>>>,
 
     pub ast: Option<Lazy<astencode::Ast<'tcx>>>,
@@ -221,18 +221,18 @@ pub struct Entry<'tcx> {
 
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
 pub enum EntryKind<'tcx> {
-    Const,
+    Const(u8),
     ImmStatic,
     MutStatic,
     ForeignImmStatic,
     ForeignMutStatic,
     ForeignMod,
     Type,
-    Enum(Lazy<attr::IntType>, ReprOptions),
+    Enum(ReprOptions),
     Field,
-    Variant(Lazy<VariantData>),
-    Struct(Lazy<VariantData>, ReprOptions),
-    Union(Lazy<VariantData>, ReprOptions),
+    Variant(Lazy<VariantData<'tcx>>),
+    Struct(Lazy<VariantData<'tcx>>, ReprOptions),
+    Union(Lazy<VariantData<'tcx>>, ReprOptions),
     Fn(Lazy<FnData>),
     ForeignFn(Lazy<FnData>),
     Mod(Lazy<ModData>),
@@ -243,21 +243,7 @@ pub enum EntryKind<'tcx> {
     DefaultImpl(Lazy<ImplData<'tcx>>),
     Method(Lazy<MethodData>),
     AssociatedType(AssociatedContainer),
-    AssociatedConst(AssociatedContainer),
-}
-
-/// A copy of `ty::Generics` which allows lazy decoding of
-/// `regions` and `types` (e.g. knowing the number of type
-/// and lifetime parameters before `TyCtxt` is created).
-#[derive(RustcEncodable, RustcDecodable)]
-pub struct Generics<'tcx> {
-    pub parent: Option<DefId>,
-    pub parent_regions: u32,
-    pub parent_types: u32,
-    pub regions: LazySeq<ty::RegionParameterDef>,
-    pub types: LazySeq<ty::TypeParameterDef<'tcx>>,
-    pub has_self: bool,
-    pub object_lifetime_defaults: LazySeq<ObjectLifetimeDefault>,
+    AssociatedConst(AssociatedContainer, u8),
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
@@ -277,9 +263,10 @@ pub struct FnData {
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct VariantData {
+pub struct VariantData<'tcx> {
     pub ctor_kind: CtorKind,
-    pub disr: u128,
+    pub discr: ty::VariantDiscr,
+    pub evaluated_discr: Option<ConstVal<'tcx>>,
 
     /// If this is a struct's only variant, this
     /// is the index of the "struct ctor" item.
@@ -350,5 +337,5 @@ pub struct MethodData {
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct ClosureData<'tcx> {
     pub kind: ty::ClosureKind,
-    pub ty: Lazy<ty::ClosureTy<'tcx>>,
+    pub ty: Lazy<ty::PolyFnSig<'tcx>>,
 }
index 0487e277a338bb84ebfe0634ffb4ab76031e698c..5abfe084f22581b646aaec8cecbdcd2b55d363a9 100644 (file)
@@ -99,6 +99,7 @@ fn expr_as_lvalue(&mut self,
             ExprKind::Use { .. } |
             ExprKind::NeverToAny { .. } |
             ExprKind::ReifyFnPointer { .. } |
+            ExprKind::ClosureFnPointer { .. } |
             ExprKind::UnsafeFnPointer { .. } |
             ExprKind::Unsize { .. } |
             ExprKind::Repeat { .. } |
index 7adcc0e730b15710425c9ead59b7586b2048fc87..7c3807a5edca5cb53cd88f4e138a268d36fe6f35 100644 (file)
@@ -112,6 +112,10 @@ fn expr_as_rvalue(&mut self,
                 let source = unpack!(block = this.as_operand(block, source));
                 block.and(Rvalue::Cast(CastKind::UnsafeFnPointer, source, expr.ty))
             }
+            ExprKind::ClosureFnPointer { source } => {
+                let source = unpack!(block = this.as_operand(block, source));
+                block.and(Rvalue::Cast(CastKind::ClosureFnPointer, source, expr.ty))
+            }
             ExprKind::Unsize { source } => {
                 let source = unpack!(block = this.as_operand(block, source));
                 block.and(Rvalue::Cast(CastKind::Unsize, source, expr.ty))
@@ -144,12 +148,13 @@ fn expr_as_rvalue(&mut self,
                 //     to the same MIR as `let x = ();`.
 
                 // first process the set of fields
+                let el_ty = expr.ty.sequence_element_type(this.hir.tcx());
                 let fields: Vec<_> =
                     fields.into_iter()
                           .map(|f| unpack!(block = this.as_operand(block, f)))
                           .collect();
 
-                block.and(Rvalue::Aggregate(AggregateKind::Array, fields))
+                block.and(Rvalue::Aggregate(AggregateKind::Array(el_ty), fields))
             }
             ExprKind::Tuple { fields } => { // see (*) above
                 // first process the set of fields
index 6e57c10964cb21b762aa99c8042180534e99c2f9..35173bb598c7cfc0384a81a487a4c57ab3f13173 100644 (file)
@@ -70,6 +70,7 @@ pub fn of<'tcx>(ek: &ExprKind<'tcx>) -> Option<Category> {
             ExprKind::Cast { .. } |
             ExprKind::Use { .. } |
             ExprKind::ReifyFnPointer { .. } |
+            ExprKind::ClosureFnPointer { .. } |
             ExprKind::UnsafeFnPointer { .. } |
             ExprKind::Unsize { .. } |
             ExprKind::Repeat { .. } |
index e66f2b4e2bfc0a018df4f4e1927beac6ca80f58f..ae51951b519bd3420bb9281561c681a6adf75a7e 100644 (file)
@@ -202,7 +202,7 @@ pub fn into_expr(&mut self,
                 let diverges = match ty.sty {
                     ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
                         // FIXME(canndrew): This is_never should probably be an is_uninhabited
-                        f.sig.skip_binder().output().is_never()
+                        f.output().skip_binder().is_never()
                     }
                     _ => false
                 };
@@ -244,6 +244,7 @@ pub fn into_expr(&mut self,
             ExprKind::Cast { .. } |
             ExprKind::Use { .. } |
             ExprKind::ReifyFnPointer { .. } |
+            ExprKind::ClosureFnPointer { .. } |
             ExprKind::UnsafeFnPointer { .. } |
             ExprKind::Unsize { .. } |
             ExprKind::Repeat { .. } |
index a28bc5d6ce36db5b99c59224edf870d04a0e8223..6b6acb054b1b0200cb16f887a267815b28d1dff6 100644 (file)
@@ -309,13 +309,13 @@ enum TestKind<'tcx> {
     // test the branches of enum
     SwitchInt {
         switch_ty: Ty<'tcx>,
-        options: Vec<ConstVal>,
-        indices: FxHashMap<ConstVal, usize>,
+        options: Vec<ConstVal<'tcx>>,
+        indices: FxHashMap<ConstVal<'tcx>, usize>,
     },
 
     // test for equality
     Eq {
-        value: ConstVal,
+        value: ConstVal<'tcx>,
         ty: Ty<'tcx>,
     },
 
index 01c0433112bf33aa1edd2929d187bc1564ed9e14..f4fdf8ade900a0ba7951491a80889477d00ca4f5 100644 (file)
@@ -20,7 +20,7 @@
 use hair::*;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::bitvec::BitVector;
-use rustc::middle::const_val::{ConstVal, ConstInt};
+use rustc::middle::const_val::ConstVal;
 use rustc::ty::{self, Ty};
 use rustc::ty::util::IntTypeExt;
 use rustc::mir::*;
@@ -112,8 +112,8 @@ pub fn add_cases_to_switch<'pat>(&mut self,
                                      test_lvalue: &Lvalue<'tcx>,
                                      candidate: &Candidate<'pat, 'tcx>,
                                      switch_ty: Ty<'tcx>,
-                                     options: &mut Vec<ConstVal>,
-                                     indices: &mut FxHashMap<ConstVal, usize>)
+                                     options: &mut Vec<ConstVal<'tcx>>,
+                                     indices: &mut FxHashMap<ConstVal<'tcx>, usize>)
                                      -> bool
     {
         let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
@@ -191,11 +191,8 @@ pub fn perform_test(&mut self,
                 let mut targets = Vec::with_capacity(used_variants + 1);
                 let mut values = Vec::with_capacity(used_variants);
                 let tcx = self.hir.tcx();
-                for (idx, variant) in adt_def.variants.iter().enumerate() {
+                for (idx, discr) in adt_def.discriminants(tcx).enumerate() {
                     target_blocks.place_back() <- if variants.contains(idx) {
-                        let discr = ConstInt::new_inttype(variant.disr_val, adt_def.discr_ty,
-                                                          tcx.sess.target.uint_type,
-                                                          tcx.sess.target.int_type).unwrap();
                         values.push(discr);
                         *(targets.place_back() <- self.cfg.start_new_block())
                     } else {
@@ -212,7 +209,7 @@ pub fn perform_test(&mut self,
                 }
                 debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
                        num_enum_variants, values, variants);
-                let discr_ty = adt_def.discr_ty.to_ty(tcx);
+                let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
                 let discr = self.temp(discr_ty);
                 self.cfg.push_assign(block, source_info, &discr,
                                      Rvalue::Discriminant(lvalue.clone()));
index ecdc58ba55d6cbfef15d5d1eb20477b45ad5739c..41374a0012327a4e78cb7d49e1b9682b682c2890 100644 (file)
@@ -223,6 +223,17 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
     builder.finish(vec![], ty)
 }
 
+pub fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
+                                       body_id: hir::BodyId)
+                                       -> Mir<'tcx> {
+    let span = hir.tcx().hir.span(hir.tcx().hir.body_owner(body_id));
+    let ty = hir.tcx().types.err;
+    let mut builder = Builder::new(hir, span, 0, ty);
+    let source_info = builder.source_info(span);
+    builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
+    builder.finish(vec![], ty)
+}
+
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     fn new(hir: Cx<'a, 'gcx, 'tcx>,
            span: Span,
index c702a142fab342fc1520b5643565d544be117d75..282361fc13e27054f37a759ff1793de2004cead4 100644 (file)
@@ -385,22 +385,14 @@ pub fn new_visibility_scope(&mut self, span: Span) -> VisibilityScope {
     /// resolving `break` and `continue`.
     pub fn find_loop_scope(&mut self,
                            span: Span,
-                           label: Option<CodeExtent>)
+                           label: CodeExtent)
                            -> &mut LoopScope<'tcx> {
-        let loop_scopes = &mut self.loop_scopes;
-        match label {
-            None => {
-                // no label? return the innermost loop scope
-                loop_scopes.iter_mut().rev().next()
-            }
-            Some(label) => {
-                // otherwise, find the loop-scope with the correct id
-                loop_scopes.iter_mut()
-                           .rev()
-                           .filter(|loop_scope| loop_scope.extent == label)
-                           .next()
-            }
-        }.unwrap_or_else(|| span_bug!(span, "no enclosing loop scope found?"))
+        // find the loop-scope with the correct id
+        self.loop_scopes.iter_mut()
+            .rev()
+            .filter(|loop_scope| loop_scope.extent == label)
+            .next()
+            .unwrap_or_else(|| span_bug!(span, "no enclosing loop scope found?"))
     }
 
     /// Given a span and the current visibility scope, make a SourceInfo.
index 7eaf1fe13986518e85fd8ccd4c44759cb6b6bd7a..c67bb8ec6c585346fc7d646addcecfaeda46df6f 100644 (file)
@@ -17,7 +17,7 @@
 use rustc::hir::map;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::middle::const_val::ConstVal;
-use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err};
+use rustc_const_eval::{ConstContext, fatal_const_eval_err};
 use rustc::ty::{self, AdtKind, VariantDef, Ty};
 use rustc::ty::cast::CastKind as TyCastKind;
 use rustc::hir;
@@ -60,6 +60,15 @@ fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
                     kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
                 };
             }
+            Some((ty::adjustment::Adjust::ClosureFnPointer, adjusted_ty)) => {
+                expr = Expr {
+                    temp_lifetime: temp_lifetime,
+                    temp_lifetime_was_shrunk: was_shrunk,
+                    ty: adjusted_ty,
+                    span: self.span,
+                    kind: ExprKind::ClosureFnPointer { source: expr.to_ref() },
+                };
+            }
             Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => {
                 expr = Expr {
                     temp_lifetime: temp_lifetime,
@@ -258,13 +267,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
                 let method = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
 
-                let sig = match method.ty.sty {
-                    ty::TyFnDef(.., fn_ty) => &fn_ty.sig,
-                    _ => span_bug!(expr.span, "type of method is not an fn"),
-                };
+                let sig = method.ty.fn_sig();
 
                 let sig = cx.tcx
-                    .no_late_bound_regions(sig)
+                    .no_late_bound_regions(&sig)
                     .unwrap_or_else(|| span_bug!(expr.span, "method call has late-bound regions"));
 
                 assert_eq!(sig.inputs().len(), 2);
@@ -588,7 +594,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprRepeat(ref v, count) => {
             let tcx = cx.tcx.global_tcx();
             let c = &cx.tcx.hir.body(count).value;
-            let count = match ConstContext::new(tcx, count).eval(c, EvalHint::ExprTypeChecked) {
+            let count = match ConstContext::new(tcx, count).eval(c) {
                 Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
                 Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
                 Err(s) => fatal_const_eval_err(tcx, &s, c.span, "expression")
@@ -596,23 +602,26 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
             ExprKind::Repeat {
                 value: v.to_ref(),
-                count: TypedConstVal {
-                    ty: cx.tcx.types.usize,
-                    span: c.span,
-                    value: count
-                }
+                count: count,
             }
         }
         hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() },
         hir::ExprBreak(label, ref value) => {
-            ExprKind::Break {
-                label: label.map(|label| cx.tcx.region_maps.node_extent(label.loop_id)),
-                value: value.to_ref(),
+            match label.loop_id.into() {
+                Ok(loop_id) => ExprKind::Break {
+                    label: cx.tcx.region_maps.node_extent(loop_id),
+                    value: value.to_ref(),
+                },
+                Err(err) => bug!("invalid loop id for break: {}", err)
             }
+
         }
         hir::ExprAgain(label) => {
-            ExprKind::Continue {
-                label: label.map(|label| cx.tcx.region_maps.node_extent(label.loop_id)),
+            match label.loop_id.into() {
+                Ok(loop_id) => ExprKind::Continue {
+                    label: cx.tcx.region_maps.node_extent(loop_id),
+                },
+                Err(err) => bug!("invalid loop id for continue: {}", err)
             }
         }
         hir::ExprMatch(ref discr, ref arms, _) => {
index 5b3297cb694e855f5f3e305dbb05c621a2018319..c555ce1ab9c425de7e8c749a8c1a67826f6af472 100644 (file)
@@ -18,7 +18,7 @@
 use rustc::mir::transform::MirSource;
 
 use rustc::middle::const_val::ConstVal;
-use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err};
+use rustc_const_eval::{ConstContext, fatal_const_eval_err};
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::blocks::FnLikeNode;
@@ -59,13 +59,8 @@ pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, src: MirSource) -> Cx<'a, 'gcx,
         let mut check_overflow = attrs.iter()
             .any(|item| item.check_name("rustc_inherit_overflow_checks"));
 
-        // Respect -Z force-overflow-checks=on and -C debug-assertions.
-        check_overflow |= infcx.tcx
-            .sess
-            .opts
-            .debugging_opts
-            .force_overflow_checks
-            .unwrap_or(infcx.tcx.sess.opts.debug_assertions);
+        // Respect -C overflow-checks.
+        check_overflow |= infcx.tcx.sess.overflow_checks();
 
         // Constants and const fn's always need overflow checks.
         check_overflow |= constness == hir::Constness::Const;
@@ -118,7 +113,7 @@ pub fn false_literal(&mut self) -> Literal<'tcx> {
 
     pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> {
         let tcx = self.tcx.global_tcx();
-        match ConstContext::with_tables(tcx, self.tables()).eval(e, EvalHint::ExprTypeChecked) {
+        match ConstContext::with_tables(tcx, self.tables()).eval(e) {
             Ok(value) => Literal::Value { value: value },
             Err(s) => fatal_const_eval_err(tcx, &s, e.span, "expression")
         }
index 4ac67cfb2fca10fb935c06b486859fc9b6f4babb..2ee375dee08ac7a9a04eeaaddeb436bbcca8effb 100644 (file)
@@ -14,7 +14,8 @@
 //! unit-tested and separated from the Rust source and compiler data
 //! structures.
 
-use rustc::mir::{BinOp, BorrowKind, Field, Literal, UnOp, TypedConstVal};
+use rustc_const_math::ConstUsize;
+use rustc::mir::{BinOp, BorrowKind, Field, Literal, UnOp};
 use rustc::hir::def_id::DefId;
 use rustc::middle::region::CodeExtent;
 use rustc::ty::subst::Substs;
@@ -152,6 +153,9 @@ pub enum ExprKind<'tcx> {
     ReifyFnPointer {
         source: ExprRef<'tcx>,
     },
+    ClosureFnPointer {
+        source: ExprRef<'tcx>,
+    },
     UnsafeFnPointer {
         source: ExprRef<'tcx>,
     },
@@ -205,18 +209,18 @@ pub enum ExprKind<'tcx> {
         arg: ExprRef<'tcx>,
     },
     Break {
-        label: Option<CodeExtent>,
+        label: CodeExtent,
         value: Option<ExprRef<'tcx>>,
     },
     Continue {
-        label: Option<CodeExtent>,
+        label: CodeExtent,
     },
     Return {
         value: Option<ExprRef<'tcx>>,
     },
     Repeat {
         value: ExprRef<'tcx>,
-        count: TypedConstVal<'tcx>,
+        count: ConstUsize,
     },
     Array {
         fields: Vec<ExprRef<'tcx>>,
index 9a8fb1099d04bf84a6afa1992fa4c64afb95d471..a97495a0ebcc43d09599dc6606455b2bc28477d4 100644 (file)
@@ -53,3 +53,9 @@
 pub mod pretty;
 pub mod transform;
 
+use rustc::ty::maps::Providers;
+
+pub fn provide(providers: &mut Providers) {
+    mir_map::provide(providers);
+    transform::qualify_consts::provide(providers);
+}
index b7f90682c7c74a5382a4824f2d48213125dada4c..e0eb09fbf5d6f06e399b50d34216198f85bf16a8 100644 (file)
@@ -17,6 +17,7 @@
 //! - `#[rustc_mir(pretty="file.mir")]`
 
 use build;
+use rustc::hir::def_id::DefId;
 use rustc::dep_graph::DepNode;
 use rustc::mir::Mir;
 use rustc::mir::transform::MirSource;
@@ -24,9 +25,9 @@
 use pretty;
 use hair::cx::Cx;
 
-use rustc::infer::InferCtxt;
 use rustc::traits::Reveal;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::maps::Providers;
 use rustc::ty::subst::Substs;
 use rustc::hir;
 use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
@@ -34,6 +35,7 @@
 use syntax::ast;
 use syntax_pos::Span;
 
+use std::cell::RefCell;
 use std::mem;
 
 pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
@@ -42,6 +44,109 @@ pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     }.as_deep_visitor());
 }
 
+pub fn provide(providers: &mut Providers) {
+    providers.mir = build_mir;
+}
+
+fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
+                       -> &'tcx RefCell<Mir<'tcx>> {
+    let id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let unsupported = || {
+        span_bug!(tcx.hir.span(id), "can't build MIR for {:?}", def_id);
+    };
+
+    // Figure out what primary body this item has.
+    let body_id = match tcx.hir.get(id) {
+        hir::map::NodeItem(item) => {
+            match item.node {
+                hir::ItemConst(_, body) |
+                hir::ItemStatic(_, _, body) |
+                hir::ItemFn(.., body) => body,
+                _ => unsupported()
+            }
+        }
+        hir::map::NodeTraitItem(item) => {
+            match item.node {
+                hir::TraitItemKind::Const(_, Some(body)) |
+                hir::TraitItemKind::Method(_,
+                    hir::TraitMethod::Provided(body)) => body,
+                _ => unsupported()
+            }
+        }
+        hir::map::NodeImplItem(item) => {
+            match item.node {
+                hir::ImplItemKind::Const(_, body) |
+                hir::ImplItemKind::Method(_, body) => body,
+                _ => unsupported()
+            }
+        }
+        hir::map::NodeExpr(expr) => {
+            // FIXME(eddyb) Closures should have separate
+            // function definition IDs and expression IDs.
+            // Type-checking should not let closures get
+            // this far in a constant position.
+            // Assume that everything other than closures
+            // is a constant "initializer" expression.
+            match expr.node {
+                hir::ExprClosure(_, _, body, _) => body,
+                _ => hir::BodyId { node_id: expr.id }
+            }
+        }
+        _ => unsupported()
+    };
+
+    let src = MirSource::from_node(tcx, id);
+    tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
+        let cx = Cx::new(&infcx, src);
+        let mut mir = if cx.tables().tainted_by_errors {
+            build::construct_error(cx, body_id)
+        } else if let MirSource::Fn(id) = src {
+            // fetch the fully liberated fn signature (that is, all bound
+            // types/lifetimes replaced)
+            let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
+
+            let ty = tcx.item_type(tcx.hir.local_def_id(id));
+            let mut abi = fn_sig.abi;
+            let implicit_argument = if let ty::TyClosure(..) = ty.sty {
+                // HACK(eddyb) Avoid having RustCall on closures,
+                // as it adds unnecessary (and wrong) auto-tupling.
+                abi = Abi::Rust;
+                Some((closure_self_ty(tcx, id, body_id), None))
+            } else {
+                None
+            };
+
+            let body = tcx.hir.body(body_id);
+            let explicit_arguments =
+                body.arguments
+                    .iter()
+                    .enumerate()
+                    .map(|(index, arg)| {
+                        (fn_sig.inputs()[index], Some(&*arg.pat))
+                    });
+
+            let arguments = implicit_argument.into_iter().chain(explicit_arguments);
+            build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
+        } else {
+            build::construct_const(cx, body_id)
+        };
+
+        // Convert the Mir to global types.
+        let mut globalizer = GlobalizeMir {
+            tcx: tcx,
+            span: mir.span
+        };
+        globalizer.visit_mir(&mut mir);
+        let mir = unsafe {
+            mem::transmute::<Mir, Mir<'tcx>>(mir)
+        };
+
+        pretty::dump_mir(tcx, "mir_map", &0, src, &mir);
+
+        tcx.alloc_mir(mir)
+    })
+}
+
 /// A pass to lift all the types and substitutions in a Mir
 /// to the global tcx. Sadly, we don't have a "folder" that
 /// can change 'tcx so we have to transmute afterwards.
@@ -79,68 +184,13 @@ struct BuildMir<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>
 }
 
-fn build<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                         body_id: hir::BodyId)
-                         -> (Mir<'tcx>, MirSource) {
-    let tcx = infcx.tcx.global_tcx();
-
-    let item_id = tcx.hir.body_owner(body_id);
-    let src = MirSource::from_node(tcx, item_id);
-    let cx = Cx::new(infcx, src);
-    if let MirSource::Fn(id) = src {
-        // fetch the fully liberated fn signature (that is, all bound
-        // types/lifetimes replaced)
-        let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
-
-        let ty = tcx.item_type(tcx.hir.local_def_id(id));
-        let (abi, implicit_argument) = if let ty::TyClosure(..) = ty.sty {
-            (Abi::Rust, Some((closure_self_ty(tcx, id, body_id), None)))
-        } else {
-            (ty.fn_abi(), None)
-        };
-
-        let body = tcx.hir.body(body_id);
-        let explicit_arguments =
-            body.arguments
-                .iter()
-                .enumerate()
-                .map(|(index, arg)| {
-                    (fn_sig.inputs()[index], Some(&*arg.pat))
-                });
-
-        let arguments = implicit_argument.into_iter().chain(explicit_arguments);
-        (build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body), src)
-    } else {
-        (build::construct_const(cx, body_id), src)
-    }
-}
-
 impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
         NestedVisitorMap::None
     }
 
     fn visit_nested_body(&mut self, body_id: hir::BodyId) {
-        self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
-            let (mut mir, src) = build(&infcx, body_id);
-
-            // Convert the Mir to global types.
-            let tcx = infcx.tcx.global_tcx();
-            let mut globalizer = GlobalizeMir {
-                tcx: tcx,
-                span: mir.span
-            };
-            globalizer.visit_mir(&mut mir);
-            let mir = unsafe {
-                mem::transmute::<Mir, Mir<'tcx>>(mir)
-            };
-
-            pretty::dump_mir(tcx, "mir_map", &0, src, &mir);
-
-            let mir = tcx.alloc_mir(mir);
-            let def_id = tcx.hir.local_def_id(src.item_id());
-            tcx.mir_map.borrow_mut().insert(def_id, mir);
-        });
+        self.tcx.item_mir(self.tcx.hir.body_owner_def_id(body_id));
 
         let body = self.tcx.hir.body(body_id);
         self.visit_body(body);
index 4459142cfb2746dcc0ead02355fe2079bf99b9c7..e998665e035365056fafe6065ce5b694b4371980 100644 (file)
 
 use rustc_data_structures::bitvec::BitVector;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::traits::{self, Reveal};
-use rustc::ty::{self, TyCtxt, Ty};
+use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
 use rustc::ty::cast::CastTy;
+use rustc::ty::maps::Providers;
 use rustc::mir::*;
 use rustc::mir::traversal::ReversePostorder;
-use rustc::mir::transform::{Pass, MirPass, MirSource};
+use rustc::mir::transform::{Pass, MirMapPass, MirPassHook, MirSource};
 use rustc::mir::visit::{LvalueContext, Visitor};
-use rustc::util::nodemap::DefIdMap;
 use rustc::middle::lang_items;
 use syntax::abi::Abi;
 use syntax::feature_gate::UnstableFeatures;
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 
-use std::collections::hash_map::Entry;
 use std::fmt;
 use std::usize;
 
 
 bitflags! {
     flags Qualif: u8 {
-        // Const item's qualification while recursing.
-        // Recursive consts are an error.
-        const RECURSIVE         = 1 << 0,
-
         // Constant containing interior mutability (UnsafeCell).
-        const MUTABLE_INTERIOR  = 1 << 1,
+        const MUTABLE_INTERIOR  = 1 << 0,
 
         // Constant containing an ADT that implements Drop.
-        const NEEDS_DROP        = 1 << 2,
+        const NEEDS_DROP        = 1 << 1,
 
         // Function argument.
-        const FN_ARGUMENT       = 1 << 3,
+        const FN_ARGUMENT       = 1 << 2,
 
         // Static lvalue or move from a static.
-        const STATIC            = 1 << 4,
+        const STATIC            = 1 << 3,
 
         // Reference to a static.
-        const STATIC_REF        = 1 << 5,
+        const STATIC_REF        = 1 << 4,
 
         // Not constant at all - non-`const fn` calls, asm!,
         // pointer comparisons, ptr-to-int casts, etc.
-        const NOT_CONST         = 1 << 6,
+        const NOT_CONST         = 1 << 5,
 
         // Refers to temporaries which cannot be promoted as
         // promote_consts decided they weren't simple enough.
-        const NOT_PROMOTABLE    = 1 << 7,
+        const NOT_PROMOTABLE    = 1 << 6,
 
         // Borrows of temporaries can be promoted only
         // if they have none of the above qualifications.
-        const NEVER_PROMOTE     = !0,
+        const NEVER_PROMOTE     = 0b111_1111,
 
         // Const items can only have MUTABLE_INTERIOR
         // and NOT_PROMOTABLE without producing an error.
@@ -134,7 +130,6 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     rpo: ReversePostorder<'a, 'tcx>,
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     param_env: ty::ParameterEnvironment<'tcx>,
-    qualif_map: &'a mut DefIdMap<Qualif>,
     temp_qualif: IndexVec<Local, Option<Qualif>>,
     return_qualif: Option<Qualif>,
     qualif: Qualif,
@@ -146,7 +141,6 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
     fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
            param_env: ty::ParameterEnvironment<'tcx>,
-           qualif_map: &'a mut DefIdMap<Qualif>,
            def_id: DefId,
            mir: &'a Mir<'tcx>,
            mode: Mode)
@@ -162,7 +156,6 @@ fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             rpo: rpo,
             tcx: tcx,
             param_env: param_env,
-            qualif_map: qualif_map,
             temp_qualif: IndexVec::from_elem(None, &mir.local_decls),
             return_qualif: None,
             qualif: Qualif::empty(),
@@ -585,17 +578,12 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
                     if substs.types().next().is_some() {
                         self.add_type(constant.ty);
                     } else {
-                        let qualif = qualify_const_item_cached(self.tcx,
-                                                               self.qualif_map,
-                                                               def_id);
-                        self.add(qualif);
-                    }
+                        let bits = ty::queries::mir_const_qualif::get(self.tcx,
+                                                                      constant.span,
+                                                                      def_id);
 
-                    // FIXME(eddyb) check recursive constants here,
-                    // instead of rustc_passes::static_recursion.
-                    if self.qualif.intersects(Qualif::RECURSIVE) {
-                        span_bug!(constant.span,
-                                  "recursive constant wasn't caught earlier");
+                        let qualif = Qualif::from_bits(bits).expect("invalid mir_const_qualif");
+                        self.add(qualif);
                     }
 
                     // Let `const fn` transitively have destructors,
@@ -619,6 +607,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
             Rvalue::CheckedBinaryOp(..) |
             Rvalue::Cast(CastKind::ReifyFnPointer, ..) |
             Rvalue::Cast(CastKind::UnsafeFnPointer, ..) |
+            Rvalue::Cast(CastKind::ClosureFnPointer, ..) |
             Rvalue::Cast(CastKind::Unsize, ..) => {}
 
             Rvalue::Len(_) => {
@@ -757,13 +746,13 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
 
             Rvalue::Aggregate(ref kind, _) => {
                 if let AggregateKind::Adt(def, ..) = *kind {
-                    if def.has_dtor() {
+                    if def.has_dtor(self.tcx) {
                         self.add(Qualif::NEEDS_DROP);
                         self.deny_drop();
                     }
 
                     if Some(def.did) == self.tcx.lang_items.unsafe_cell_type() {
-                        let ty = rvalue.ty(self.mir, self.tcx).unwrap();
+                        let ty = rvalue.ty(self.mir, self.tcx);
                         self.add_type(ty);
                         assert!(self.qualif.intersects(Qualif::MUTABLE_INTERIOR));
                         // Even if the value inside may not need dropping,
@@ -787,7 +776,7 @@ fn visit_terminator_kind(&mut self,
             let fn_ty = func.ty(self.mir, self.tcx);
             let (is_shuffle, is_const_fn) = match fn_ty.sty {
                 ty::TyFnDef(def_id, _, f) => {
-                    (f.abi == Abi::PlatformIntrinsic &&
+                    (f.abi() == Abi::PlatformIntrinsic &&
                      self.tcx.item_name(def_id).as_str().starts_with("simd_shuffle"),
                      is_const_fn(self.tcx, def_id))
                 }
@@ -943,41 +932,64 @@ fn visit_terminator(&mut self,
     }
 }
 
-fn qualify_const_item_cached<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                       qualif_map: &mut DefIdMap<Qualif>,
-                                       def_id: DefId)
-                                       -> Qualif {
-    match qualif_map.entry(def_id) {
-        Entry::Occupied(entry) => return *entry.get(),
-        Entry::Vacant(entry) => {
-            // Guard against `const` recursion.
-            entry.insert(Qualif::RECURSIVE);
-        }
+pub fn provide(providers: &mut Providers) {
+    providers.mir_const_qualif = qualify_const_item;
+}
+
+fn qualify_const_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                def_id: DefId)
+                                -> u8 {
+    let mir = &tcx.item_mir(def_id);
+    if mir.return_ty.references_error() {
+        return Qualif::NOT_CONST.bits();
     }
 
-    let param_env = if def_id.is_local() {
-        let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
-        ty::ParameterEnvironment::for_item(tcx, node_id)
-    } else {
-        // These should only be monomorphic constants.
-        tcx.empty_parameter_environment()
-    };
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
 
-    let mir = &tcx.item_mir(def_id);
-    let mut qualifier = Qualifier::new(tcx, param_env, qualif_map, def_id, mir, Mode::Const);
-    let qualif = qualifier.qualify_const();
-    qualifier.qualif_map.insert(def_id, qualif);
-    qualif
+    let mut qualifier = Qualifier::new(tcx, param_env, def_id, mir, Mode::Const);
+    qualifier.qualify_const().bits()
 }
 
-#[derive(Default)]
-pub struct QualifyAndPromoteConstants {
-    qualif_map: DefIdMap<Qualif>
-}
+pub struct QualifyAndPromoteConstants;
 
 impl Pass for QualifyAndPromoteConstants {}
 
-impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants {
+impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants {
+    fn run_pass<'a>(&mut self,
+                    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                    hooks: &mut [Box<for<'s> MirPassHook<'s>>])
+    {
+        let def_ids = tcx.maps.mir.borrow().keys();
+        for def_id in def_ids {
+            if !def_id.is_local() {
+                continue;
+            }
+
+            let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
+            let id = tcx.hir.as_local_node_id(def_id).unwrap();
+            let src = MirSource::from_node(tcx, id);
+
+            if let MirSource::Const(_) = src {
+                ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
+                continue;
+            }
+
+            let mir = &mut tcx.maps.mir.borrow()[&def_id].borrow_mut();
+            tcx.dep_graph.write(DepNode::Mir(def_id));
+
+            for hook in &mut *hooks {
+                hook.on_mir_pass(tcx, src, mir, self, false);
+            }
+            self.run_pass(tcx, src, mir);
+            for hook in &mut *hooks {
+                hook.on_mir_pass(tcx, src, mir, self, true);
+            }
+        }
+    }
+}
+
+impl<'tcx> QualifyAndPromoteConstants {
     fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     src: MirSource, mir: &mut Mir<'tcx>) {
         let id = src.item_id();
@@ -990,18 +1002,9 @@ fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     Mode::Fn
                 }
             }
-            MirSource::Const(_) => {
-                match self.qualif_map.entry(def_id) {
-                    Entry::Occupied(_) => return,
-                    Entry::Vacant(entry) => {
-                        // Guard against `const` recursion.
-                        entry.insert(Qualif::RECURSIVE);
-                        Mode::Const
-                    }
-                }
-            }
             MirSource::Static(_, hir::MutImmutable) => Mode::Static,
             MirSource::Static(_, hir::MutMutable) => Mode::StaticMut,
+            MirSource::Const(_) |
             MirSource::Promoted(..) => return
         };
         let param_env = ty::ParameterEnvironment::for_item(tcx, id);
@@ -1011,7 +1014,6 @@ fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
             // which can't be mutated until its scope ends.
             let (temps, candidates) = {
                 let mut qualifier = Qualifier::new(tcx, param_env,
-                                                   &mut self.qualif_map,
                                                    def_id, mir, mode);
                 if mode == Mode::ConstFn {
                     // Enforce a constant-like CFG for `const fn`.
@@ -1028,20 +1030,14 @@ fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
             // Do the actual promotion, now that we know what's viable.
             promote_consts::promote_candidates(mir, tcx, temps, candidates);
         } else {
-            let mut qualifier = Qualifier::new(tcx, param_env,
-                                               &mut self.qualif_map,
-                                               def_id, mir, mode);
-            let qualif = qualifier.qualify_const();
-
-            if mode == Mode::Const {
-                qualifier.qualif_map.insert(def_id, qualif);
-            }
+            let mut qualifier = Qualifier::new(tcx, param_env, def_id, mir, mode);
+            qualifier.qualify_const();
         }
 
         // Statics must be Sync.
         if mode == Mode::Static {
             let ty = mir.return_ty;
-            tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
+            tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
                 let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
                 let mut fulfillment_cx = traits::FulfillmentContext::new();
                 fulfillment_cx.register_bound(&infcx, ty,
index 8d108815e0f3c8e44439b29efc80794b95bc2d58..c99c4323bb8a1c4c9d4b752a375736e4c8ba199e 100644 (file)
@@ -83,9 +83,8 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
 
     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);
-        }
+        let rval_ty = rvalue.ty(self.mir, self.tcx());
+        self.sanitize_type(rvalue, rval_ty);
     }
 
     fn visit_mir(&mut self, mir: &Mir<'tcx>) {
@@ -356,14 +355,10 @@ fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>) {
             StatementKind::Assign(ref lv, ref rv) => {
                 let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
                 let rv_ty = rv.ty(mir, tcx);
-                if let Some(rv_ty) = rv_ty {
-                    if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
-                        span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}",
-                                     lv_ty, rv_ty, terr);
-                    }
+                if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
+                    span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}",
+                                 lv_ty, rv_ty, terr);
                 }
-                // FIXME: rvalue with undeterminable type - e.g. AggregateKind::Array branch that
-                // returns `None`.
             }
             StatementKind::SetDiscriminant{ ref lvalue, variant_index } => {
                 let lvalue_type = lvalue.ty(mir, tcx).to_ty(tcx);
@@ -440,14 +435,14 @@ fn check_terminator(&mut self,
             TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
                 let func_ty = func.ty(mir, tcx);
                 debug!("check_terminator: call, func_ty={:?}", func_ty);
-                let func_ty = match func_ty.sty {
-                    ty::TyFnDef(.., func_ty) | ty::TyFnPtr(func_ty) => func_ty,
+                let sig = match func_ty.sty {
+                    ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => sig,
                     _ => {
                         span_mirbug!(self, term, "call to non-function {:?}", func_ty);
                         return;
                     }
                 };
-                let sig = tcx.erase_late_bound_regions(&func_ty.sig);
+                let sig = tcx.erase_late_bound_regions(&sig);
                 let sig = self.normalize(&sig);
                 self.check_call_dest(mir, term, &sig, destination);
 
@@ -699,7 +694,7 @@ fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
             return;
         }
         let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
-        tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
+        tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
             let mut checker = TypeChecker::new(&infcx, src.item_id());
             {
                 let mut verifier = TypeVerifier::new(&mut checker, mir);
index 0b55513f8318c3c45cd8228fb8f3823a0f15db35..930a13e36bdcaebf3ba853882381c975c3e91ff4 100644 (file)
@@ -28,9 +28,8 @@
 use rustc::ty::cast::CastKind;
 use rustc_const_eval::{ConstEvalErr, ConstContext};
 use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
-use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath, BadType};
-use rustc_const_eval::ErrKind::UnresolvedPath;
-use rustc_const_eval::EvalHint::ExprTypeChecked;
+use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
+use rustc_const_eval::ErrKind::{TypeckError};
 use rustc_const_math::{ConstMathErr, Op};
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
@@ -66,12 +65,12 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> {
 impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
     fn check_const_eval(&self, expr: &'gcx hir::Expr) {
         let const_cx = ConstContext::with_tables(self.tcx, self.tables);
-        if let Err(err) = const_cx.eval(expr, ExprTypeChecked) {
+        if let Err(err) = const_cx.eval(expr) {
             match err.kind {
                 UnimplementedConstVal(_) => {}
                 IndexOpFeatureGated => {}
                 ErroneousReferencedConstant(_) => {}
-                BadType(_) => {}
+                TypeckError => {}
                 _ => {
                     self.tcx.sess.add_lint(CONST_ERR,
                                            expr.id,
@@ -138,7 +137,7 @@ fn visit_nested_body(&mut self, body_id: hir::BodyId) {
             self.check_const_eval(&body.value);
         }
 
-        let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
+        let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
             let param_env = infcx.parameter_environment.clone();
             let outer_penv = mem::replace(&mut self.param_env, param_env);
             euv::ExprUseVisitor::new(self, &infcx).consume_body(body);
@@ -240,18 +239,17 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
 
         if self.in_fn && self.promotable {
             let const_cx = ConstContext::with_tables(self.tcx, self.tables);
-            match const_cx.eval(ex, ExprTypeChecked) {
+            match const_cx.eval(ex) {
                 Ok(_) => {}
                 Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |
                 Err(ConstEvalErr { kind: MiscCatchAll, .. }) |
                 Err(ConstEvalErr { kind: MiscBinaryOp, .. }) |
                 Err(ConstEvalErr { kind: NonConstPath, .. }) |
-                Err(ConstEvalErr { kind: UnresolvedPath, .. }) |
                 Err(ConstEvalErr { kind: ErroneousReferencedConstant(_), .. }) |
                 Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shr)), .. }) |
                 Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shl)), .. }) |
                 Err(ConstEvalErr { kind: IndexOpFeatureGated, .. }) => {}
-                Err(ConstEvalErr { kind: BadType(_), .. }) => {}
+                Err(ConstEvalErr { kind: TypeckError, .. }) => {}
                 Err(msg) => {
                     self.tcx.sess.add_lint(CONST_ERR,
                                            ex.id,
@@ -274,7 +272,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
 /// instead of producing errors.
 fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) {
     match node_ty.sty {
-        ty::TyAdt(def, _) if def.has_dtor() => {
+        ty::TyAdt(def, _) if def.has_dtor(v.tcx) => {
             v.promotable = false;
         }
         _ => {}
@@ -447,6 +445,7 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp
         Some(Adjust::NeverToAny) |
         Some(Adjust::ReifyFnPointer) |
         Some(Adjust::UnsafeFnPointer) |
+        Some(Adjust::ClosureFnPointer) |
         Some(Adjust::MutToConstPointer) => {}
 
         Some(Adjust::DerefRef { autoderefs, .. }) => {
index ef871959176af088e534eda9b70c54b451c30392..5f06eadb84a9248f13e6bbf3592423f79b91f68f 100644 (file)
@@ -241,6 +241,22 @@ pub fn foo() {}
 }
 ```
 "##,
+
+E0590: r##"
+`break` or `continue` must include a label when used in the condition of a
+`while` loop.
+
+Example of erroneous code:
+
+```compile_fail
+while break {}
+```
+
+To fix this, add a label specifying which loop is being broken out of:
+```
+`foo: while break `foo {}
+```
+"##
 }
 
 register_diagnostics! {
index a5bd69fff0138b73e71f7da9dce746733db4b670..b2d51be5bf72095bc3b4199dec8af37c285ae3e9 100644 (file)
@@ -87,23 +87,26 @@ fn visit_expr(&mut self, e: &'hir hir::Expr) {
                 self.with_context(Closure, |v| v.visit_nested_body(b));
             }
             hir::ExprBreak(label, ref opt_expr) => {
+                let loop_id = match label.loop_id.into() {
+                    Ok(loop_id) => loop_id,
+                    Err(hir::LoopIdError::OutsideLoopScope) => ast::DUMMY_NODE_ID,
+                    Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
+                        self.emit_unlabled_cf_in_while_condition(e.span, "break");
+                        ast::DUMMY_NODE_ID
+                    },
+                    Err(hir::LoopIdError::UnresolvedLabel) => ast::DUMMY_NODE_ID,
+                };
+
                 if opt_expr.is_some() {
-                    let loop_kind = if let Some(label) = label {
-                        if label.loop_id == ast::DUMMY_NODE_ID {
-                            None
-                        } else {
-                            Some(match self.hir_map.expect_expr(label.loop_id).node {
-                                hir::ExprWhile(..) => LoopKind::WhileLoop,
-                                hir::ExprLoop(_, _, source) => LoopKind::Loop(source),
-                                ref r => span_bug!(e.span,
-                                                   "break label resolved to a non-loop: {:?}", r),
-                            })
-                        }
-                    } else if let Loop(kind) = self.cx {
-                        Some(kind)
-                    } else {
-                        // `break` outside a loop - caught below
+                    let loop_kind = if loop_id == ast::DUMMY_NODE_ID {
                         None
+                    } else {
+                        Some(match self.hir_map.expect_expr(loop_id).node {
+                            hir::ExprWhile(..) => LoopKind::WhileLoop,
+                            hir::ExprLoop(_, _, source) => LoopKind::Loop(source),
+                            ref r => span_bug!(e.span,
+                                               "break label resolved to a non-loop: {:?}", r),
+                        })
                     };
                     match loop_kind {
                         None | Some(LoopKind::Loop(hir::LoopSource::Loop)) => (),
@@ -117,9 +120,15 @@ fn visit_expr(&mut self, e: &'hir hir::Expr) {
                         }
                     }
                 }
+
                 self.require_loop("break", e.span);
             }
-            hir::ExprAgain(_) => self.require_loop("continue", e.span),
+            hir::ExprAgain(label) => {
+                if let Err(hir::LoopIdError::UnlabeledCfInWhileCondition) = label.loop_id.into() {
+                    self.emit_unlabled_cf_in_while_condition(e.span, "continue");
+                }
+                self.require_loop("continue", e.span)
+            },
             _ => intravisit::walk_expr(self, e),
         }
     }
@@ -150,4 +159,12 @@ fn require_loop(&self, name: &str, span: Span) {
             }
         }
     }
+
+    fn emit_unlabled_cf_in_while_condition(&mut self, span: Span, cf_type: &str) {
+        struct_span_err!(self.sess, span, E0590,
+                         "`break` or `continue` with no label in the condition of a `while` loop")
+            .span_label(span,
+                        &format!("unlabeled `{}` in the condition of a `while` loop", cf_type))
+            .emit();
+    }
 }
index 33b7089c38214543759808153fc3f52520bef57e..ce02cb0e8364374e06c9a7105aad2050f6018d86 100644 (file)
@@ -19,7 +19,7 @@
 use rustc::mir::{Lvalue, LvalueElem, LvalueProjection};
 use rustc::mir::{Mir, Operand, ProjectionElem};
 use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind};
-use rustc::mir::{Terminator, TerminatorKind, TypedConstVal, VisibilityScope, VisibilityScopeData};
+use rustc::mir::{Terminator, TerminatorKind, VisibilityScope, VisibilityScopeData};
 use rustc::mir::visit as mir_visit;
 use rustc::mir::visit::Visitor;
 use rustc::ty::{ClosureSubsts, TyCtxt};
@@ -44,7 +44,7 @@ pub fn print_mir_stats<'tcx, 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, title: &str) {
     // For debugging instrumentation like this, we don't need to worry
     // about maintaining the dep graph.
     let _ignore = tcx.dep_graph.in_ignore();
-    let mir_map = tcx.mir_map.borrow();
+    let mir_map = tcx.maps.mir.borrow();
     for def_id in mir_map.keys() {
         let mir = mir_map.get(&def_id).unwrap();
         collector.visit_mir(&mir.borrow());
@@ -191,7 +191,7 @@ fn visit_rvalue(&mut self,
                 // AggregateKind is not distinguished by visit API, so
                 // record it. (`super_rvalue` handles `_operands`.)
                 self.record(match *kind {
-                    AggregateKind::Array => "AggregateKind::Array",
+                    AggregateKind::Array(_) => "AggregateKind::Array",
                     AggregateKind::Tuple => "AggregateKind::Tuple",
                     AggregateKind::Adt(..) => "AggregateKind::Adt",
                     AggregateKind::Closure(..) => "AggregateKind::Closure",
@@ -297,13 +297,6 @@ fn visit_const_usize(&mut self,
         self.super_const_usize(const_usize);
     }
 
-    fn visit_typed_const_val(&mut self,
-                             val: &TypedConstVal<'tcx>,
-                             location: Location) {
-        self.record("TypedConstVal", val);
-        self.super_typed_const_val(val, location);
-    }
-
     fn visit_local_decl(&mut self,
                         local_decl: &LocalDecl<'tcx>) {
         self.record("LocalDecl", local_decl);
index 9de5ff541a52c98d6bfb799493644aacfca67028..c367e71fcd24619417dd41e20e2077739503b535 100644 (file)
@@ -38,7 +38,7 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
 
     fn visit_nested_body(&mut self, body_id: hir::BodyId) {
         let body = self.tcx.hir.body(body_id);
-        self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
+        self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
             let mut delegate = RvalueContextDelegate {
                 tcx: infcx.tcx,
                 param_env: &infcx.parameter_environment
index 1ef8a5b0080f3ca2451bf714f27a0db582b67774..fc05471ead30b02040f85d148369f7b2f5169d9e 100644 (file)
@@ -18,7 +18,6 @@
 use rustc::util::nodemap::{NodeMap, NodeSet};
 
 use syntax::ast;
-use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax_pos::Span;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir;
@@ -43,7 +42,7 @@ fn visit_item(&mut self, it: &'hir hir::Item) {
         match it.node {
             hir::ItemStatic(..) |
             hir::ItemConst(..) => {
-                let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &it.span);
+                let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
                 recursion_visitor.visit_item(it);
             }
             hir::ItemEnum(ref enum_def, ref generics) => {
@@ -52,8 +51,7 @@ fn visit_item(&mut self, it: &'hir hir::Item) {
                 // less redundant output.
                 for variant in &enum_def.variants {
                     if let Some(_) = variant.node.disr_expr {
-                        let mut recursion_visitor = CheckItemRecursionVisitor::new(self,
-                                                                                   &variant.span);
+                        let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
                         recursion_visitor.populate_enum_discriminants(enum_def);
                         recursion_visitor.visit_variant(variant, generics, it.id);
                     }
@@ -68,7 +66,7 @@ fn visit_trait_item(&mut self, ti: &'hir hir::TraitItem) {
         match ti.node {
             hir::TraitItemKind::Const(_, ref default) => {
                 if let Some(_) = *default {
-                    let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &ti.span);
+                    let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
                     recursion_visitor.visit_trait_item(ti);
                 }
             }
@@ -80,7 +78,7 @@ fn visit_trait_item(&mut self, ti: &'hir hir::TraitItem) {
     fn visit_impl_item(&mut self, ii: &'hir hir::ImplItem) {
         match ii.node {
             hir::ImplItemKind::Const(..) => {
-                let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &ii.span);
+                let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
                 recursion_visitor.visit_impl_item(ii);
             }
             _ => {}
@@ -105,7 +103,6 @@ pub fn check_crate<'hir>(sess: &Session, hir_map: &hir_map::Map<'hir>) -> Compil
 }
 
 struct CheckItemRecursionVisitor<'a, 'b: 'a, 'hir: 'b> {
-    root_span: &'b Span,
     sess: &'b Session,
     hir_map: &'b hir_map::Map<'hir>,
     discriminant_map: &'a mut NodeMap<Option<hir::BodyId>>,
@@ -114,9 +111,8 @@ struct CheckItemRecursionVisitor<'a, 'b: 'a, 'hir: 'b> {
 }
 
 impl<'a, 'b: 'a, 'hir: 'b> CheckItemRecursionVisitor<'a, 'b, 'hir> {
-    fn new(v: &'a mut CheckCrateVisitor<'b, 'hir>, span: &'b Span) -> Self {
+    fn new(v: &'a mut CheckCrateVisitor<'b, 'hir>) -> Self {
         CheckItemRecursionVisitor {
-            root_span: span,
             sess: v.sess,
             hir_map: v.hir_map,
             discriminant_map: &mut v.discriminant_map,
@@ -143,15 +139,7 @@ fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F, span: Span)
                     false
                 }
             });
-            if any_static {
-                if !self.sess.features.borrow().static_recursion {
-                    emit_feature_err(&self.sess.parse_sess,
-                                     "static_recursion",
-                                     *self.root_span,
-                                     GateIssue::Language,
-                                     "recursive static");
-                }
-            } else {
+            if !any_static {
                 struct_span_err!(self.sess, span, E0265, "recursive constant")
                     .span_label(span, &format!("recursion not allowed in constant"))
                     .emit();
index 9dc94745cff7b72fc64b4c8f142605e058502e40..72347f1616eb69e045f145d87b8d1eac4b8af40f 100644 (file)
@@ -334,7 +334,11 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
 
 impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
     fn generics(&mut self) -> &mut Self {
-        self.ev.tcx.item_generics(self.item_def_id).visit_with(self);
+        for def in &self.ev.tcx.item_generics(self.item_def_id).types {
+            if def.has_default {
+                self.ev.tcx.item_type(def.def_id).visit_with(self);
+            }
+        }
         self
     }
 
@@ -892,7 +896,11 @@ struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
     fn generics(&mut self) -> &mut Self {
-        self.tcx.item_generics(self.item_def_id).visit_with(self);
+        for def in &self.tcx.item_generics(self.item_def_id).types {
+            if def.has_default {
+                self.tcx.item_type(def.def_id).visit_with(self);
+            }
+        }
         self
     }
 
index 4679b6be88b6f0835a06e410c37af1082423455a..89cff39c59e31317f3af47fe0fa81921c7962925 100644 (file)
@@ -462,8 +462,8 @@ fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'a>, chi
                     self.define(module, ident, ns, (child.def, ty::Visibility::Public,
                                                     DUMMY_SP, Mark::root()));
 
-                    let has_self = self.session.cstore.associated_item(child.def.def_id())
-                                       .map_or(false, |item| item.method_has_self_argument);
+                    let has_self = self.session.cstore.associated_item_cloned(child.def.def_id())
+                                       .method_has_self_argument;
                     self.trait_item_map.insert((def_id, child.name, ns), (child.def, has_self));
                 }
                 module.populated.set(true);
@@ -495,7 +495,7 @@ fn get_extern_crate_root(&mut self, cnum: CrateNum) -> Module<'a> {
 
     pub fn get_macro(&mut self, def: Def) -> Rc<SyntaxExtension> {
         let def_id = match def {
-            Def::Macro(def_id) => def_id,
+            Def::Macro(def_id, ..) => def_id,
             _ => panic!("Expected Def::Macro(..)"),
         };
         if let Some(ext) = self.macro_map.get(&def_id) {
@@ -537,7 +537,6 @@ fn legacy_import_macro(&mut self,
                            binding: &'a NameBinding<'a>,
                            span: Span,
                            allow_shadowing: bool) {
-        self.macro_names.insert(name);
         if self.builtin_macros.insert(name, binding).is_some() && !allow_shadowing {
             let msg = format!("`{}` is already in scope", name);
             let note =
index 2fada8a9ec212f0e051129115a002eb27d71c34b..8f6b1b8971e5b9ffb1967dbb72629227735966fe 100644 (file)
 // use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
 register_long_diagnostics! {
 
+E0128: r##"
+Type parameter defaults can only use parameters that occur before them.
+Erroneous code example:
+
+```compile_fail,E0128
+struct Foo<T=U, U=()> {
+    field1: T,
+    filed2: U,
+}
+// error: type parameters with a default cannot use forward declared
+// identifiers
+```
+
+Since type parameters are evaluated in-order, you may be able to fix this issue
+by doing:
+
+```
+struct Foo<U=(), T=U> {
+    field1: T,
+    filed2: U,
+}
+```
+
+Please also verify that this wasn't because of a name-clash and rename the type
+parameter if so.
+"##,
+
 E0154: r##"
 ## Note: this error code is no longer emitted by the compiler.
 
index c9e870188aaeccb36199b4d13a3d4178ff4961da..0565db28ec5c98412e9a3709247edd24664b315b 100644 (file)
@@ -136,6 +136,8 @@ enum ResolutionError<'a> {
     AttemptToUseNonConstantValueInConstant,
     /// error E0530: X bindings cannot shadow Ys
     BindingShadowsSomethingUnacceptable(&'a str, Name, &'a NameBinding<'a>),
+    /// error E0128: type parameters with a default cannot use forward declared identifiers
+    ForwardDeclaredTyParam,
 }
 
 fn resolve_error<'sess, 'a>(resolver: &'sess Resolver,
@@ -322,6 +324,14 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
             err.span_label(binding.span, msg);
             err
         }
+        ResolutionError::ForwardDeclaredTyParam => {
+            let mut err = struct_span_err!(resolver.session, span, E0128,
+                                           "type parameters with a default cannot use \
+                                            forward declared identifiers");
+            err.span_label(span, &format!("defaulted type parameters \
+                                           cannot be forward declared"));
+            err
+        }
     }
 }
 
@@ -674,6 +684,32 @@ fn visit_fn(&mut self,
         self.label_ribs.pop();
         self.ribs[ValueNS].pop();
     }
+    fn visit_generics(&mut self, generics: &'tcx Generics) {
+        // For type parameter defaults, we have to ban access
+        // to following type parameters, as the Substs can only
+        // provide previous type parameters as they're built.
+        let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind);
+        default_ban_rib.bindings.extend(generics.ty_params.iter()
+            .skip_while(|p| p.default.is_none())
+            .map(|p| (Ident::with_empty_ctxt(p.ident.name), Def::Err)));
+
+        for param in &generics.ty_params {
+            for bound in &param.bounds {
+                self.visit_ty_param_bound(bound);
+            }
+
+            if let Some(ref ty) = param.default {
+                self.ribs[TypeNS].push(default_ban_rib);
+                self.visit_ty(ty);
+                default_ban_rib = self.ribs[TypeNS].pop().unwrap();
+            }
+
+            // Allow all following defaults to refer to this type parameter.
+            default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name));
+        }
+        for lt in &generics.lifetimes { self.visit_lifetime_def(lt); }
+        for p in &generics.where_clause.predicates { self.visit_where_predicate(p); }
+    }
 }
 
 pub type ErrorMessage = Option<(Span, String)>;
@@ -718,6 +754,11 @@ enum RibKind<'a> {
 
     // We passed through a `macro_rules!` statement with the given expansion
     MacroDefinition(Mark),
+
+    // All bindings in this rib are type parameters that can't be used
+    // from the default of a type parameter because they're not declared
+    // before said type parameter. Also see the `visit_generics` override.
+    ForwardTyParamBanRibKind,
 }
 
 /// One local scope.
@@ -736,13 +777,6 @@ fn new(kind: RibKind<'a>) -> Rib<'a> {
     }
 }
 
-/// A definition along with the index of the rib it was found on
-#[derive(Copy, Clone, Debug)]
-struct LocalDef {
-    ribs: Option<(Namespace, usize)>,
-    def: Def,
-}
-
 enum LexicalScopeBinding<'a> {
     Item(&'a NameBinding<'a>),
     Def(Def),
@@ -1265,7 +1299,7 @@ pub fn new(session: &'a Session,
             ribs: PerNS {
                 value_ns: vec![Rib::new(ModuleRibKind(graph_root))],
                 type_ns: vec![Rib::new(ModuleRibKind(graph_root))],
-                macro_ns: None,
+                macro_ns: Some(vec![Rib::new(ModuleRibKind(graph_root))]),
             },
             label_ribs: Vec::new(),
 
@@ -1428,7 +1462,7 @@ fn resolve_ident_in_lexical_scope(&mut self,
             if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() {
                 // The ident resolves to a type parameter or local variable.
                 return Some(LexicalScopeBinding::Def(
-                    self.adjust_local_def(LocalDef { ribs: Some((ns, i)), def: def }, record_used)
+                    self.adjust_local_def(ns, i, def, record_used)
                 ));
             }
 
@@ -2328,10 +2362,13 @@ fn resolve_qpath_anywhere(&mut self,
                 };
             }
         }
-        if primary_ns != MacroNS && path.len() == 1 &&
-                self.macro_names.contains(&path[0].name) {
+        let is_builtin = self.builtin_macros.get(&path[0].name).cloned()
+            .map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false);
+        if primary_ns != MacroNS && (is_builtin || self.macro_names.contains(&path[0].name)) {
             // Return some dummy definition, it's enough for error reporting.
-            return Some(PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX))));
+            return Some(
+                PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang))
+            );
         }
         fin_res
     }
@@ -2524,12 +2561,23 @@ fn resolve_path(&mut self,
     }
 
     // Resolve a local definition, potentially adjusting for closures.
-    fn adjust_local_def(&mut self, local_def: LocalDef, record_used: Option<Span>) -> Def {
-        let ribs = match local_def.ribs {
-            Some((ns, i)) => &self.ribs[ns][i + 1..],
-            None => &[] as &[_],
-        };
-        let mut def = local_def.def;
+    fn adjust_local_def(&mut self,
+                        ns: Namespace,
+                        rib_index: usize,
+                        mut def: Def,
+                        record_used: Option<Span>) -> Def {
+        let ribs = &self.ribs[ns][rib_index + 1..];
+
+        // An invalid forward use of a type parameter from a previous default.
+        if let ForwardTyParamBanRibKind = self.ribs[ns][rib_index].kind {
+            if let Some(span) = record_used {
+                resolve_error(self, span,
+                        ResolutionError::ForwardDeclaredTyParam);
+            }
+            assert_eq!(def, Def::Err);
+            return Def::Err;
+        }
+
         match def {
             Def::Upvar(..) => {
                 span_bug!(record_used.unwrap_or(DUMMY_SP), "unexpected {:?} in bindings", def)
@@ -2537,7 +2585,8 @@ fn adjust_local_def(&mut self, local_def: LocalDef, record_used: Option<Span>) -
             Def::Local(def_id) => {
                 for rib in ribs {
                     match rib.kind {
-                        NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) => {
+                        NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) |
+                        ForwardTyParamBanRibKind => {
                             // Nothing to do. Continue.
                         }
                         ClosureRibKind(function_id) => {
@@ -2590,7 +2639,7 @@ fn adjust_local_def(&mut self, local_def: LocalDef, record_used: Option<Span>) -
                 for rib in ribs {
                     match rib.kind {
                         NormalRibKind | MethodRibKind(_) | ClosureRibKind(..) |
-                        ModuleRibKind(..) | MacroDefinition(..) => {
+                        ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind => {
                             // Nothing to do. Continue.
                         }
                         ItemRibKind => {
@@ -2768,18 +2817,24 @@ fn lookup_typo_candidate<FilterFn>(&mut self,
         }
     }
 
-    fn resolve_labeled_block(&mut self, label: Option<SpannedIdent>, id: NodeId, block: &Block) {
+    fn with_resolved_label<F>(&mut self, label: Option<SpannedIdent>, id: NodeId, f: F)
+        where F: FnOnce(&mut Resolver)
+    {
         if let Some(label) = label {
             let def = Def::Label(id);
             self.with_label_rib(|this| {
                 this.label_ribs.last_mut().unwrap().bindings.insert(label.node, def);
-                this.visit_block(block);
+                f(this);
             });
         } else {
-            self.visit_block(block);
+            f(self);
         }
     }
 
+    fn resolve_labeled_block(&mut self, label: Option<SpannedIdent>, id: NodeId, block: &Block) {
+        self.with_resolved_label(label, id, |this| this.visit_block(block));
+    }
+
     fn resolve_expr(&mut self, expr: &Expr, parent: Option<&ExprKind>) {
         // First, record candidate traits for this expression if it could
         // result in the invocation of a method call.
@@ -2833,18 +2888,18 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&ExprKind>) {
             ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block),
 
             ExprKind::While(ref subexpression, ref block, label) => {
-                self.visit_expr(subexpression);
-                self.resolve_labeled_block(label, expr.id, &block);
+                self.with_resolved_label(label, expr.id, |this| {
+                    this.visit_expr(subexpression);
+                    this.visit_block(block);
+                });
             }
 
             ExprKind::WhileLet(ref pattern, ref subexpression, ref block, label) => {
-                self.visit_expr(subexpression);
-                self.ribs[ValueNS].push(Rib::new(NormalRibKind));
-                self.resolve_pattern(pattern, PatternSource::WhileLet, &mut FxHashMap());
-
-                self.resolve_labeled_block(label, expr.id, block);
-
-                self.ribs[ValueNS].pop();
+                self.with_resolved_label(label, expr.id, |this| {
+                    this.visit_expr(subexpression);
+                    this.resolve_pattern(pattern, PatternSource::WhileLet, &mut FxHashMap());
+                    this.visit_block(block);
+                });
             }
 
             ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => {
index aba2de6b3a2b6106b78b04dff80223ecf5edb236..b7068f4b09f5fcca3359b955d6e1d279736755c7 100644 (file)
@@ -23,7 +23,7 @@
 use syntax::attr;
 use syntax::errors::DiagnosticBuilder;
 use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator};
-use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension};
+use syntax::ext::base::{Resolver as SyntaxResolver, SyntaxExtension};
 use syntax::ext::base::MacroKind;
 use syntax::ext::expand::{Expansion, mark_tts};
 use syntax::ext::hygiene::Mark;
@@ -152,16 +152,14 @@ fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[Mark
     }
 
     fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
-        if let NormalTT(..) = *ext {
-            self.macro_names.insert(ident.name);
-        }
         let def_id = DefId {
             krate: BUILTIN_MACROS_CRATE,
             index: DefIndex::new(self.macro_map.len()),
         };
+        let kind = ext.kind();
         self.macro_map.insert(def_id, ext);
         let binding = self.arenas.alloc_name_binding(NameBinding {
-            kind: NameBindingKind::Def(Def::Macro(def_id)),
+            kind: NameBindingKind::Def(Def::Macro(def_id, kind)),
             span: DUMMY_SP,
             vis: ty::Visibility::Invisible,
             expansion: Mark::root(),
@@ -470,24 +468,40 @@ pub fn finalize_current_module_macro_resolutions(&mut self) {
 
     fn suggest_macro_name(&mut self, name: &str, kind: MacroKind,
                           err: &mut DiagnosticBuilder<'a>) {
-        let suggestion = match kind {
-            MacroKind::Bang =>
-                find_best_match_for_name(self.macro_names.iter(), name, None),
-            MacroKind::Attr |
-            MacroKind::Derive => {
-                // Find a suggestion from the legacy namespace.
-                // FIXME: get_macro needs an &mut Resolver, can we do it without cloning?
-                let builtin_macros = self.builtin_macros.clone();
-                let names = builtin_macros.iter().filter_map(|(name, binding)| {
-                    if binding.get_macro(self).kind() == kind {
-                        Some(name)
-                    } else {
-                        None
-                    }
-                });
-                find_best_match_for_name(names, name, None)
+        // First check if this is a locally-defined bang macro.
+        let suggestion = if let MacroKind::Bang = kind {
+            find_best_match_for_name(self.macro_names.iter(), name, None)
+        } else {
+            None
+        // Then check builtin macros.
+        }.or_else(|| {
+            // FIXME: get_macro needs an &mut Resolver, can we do it without cloning?
+            let builtin_macros = self.builtin_macros.clone();
+            let names = builtin_macros.iter().filter_map(|(name, binding)| {
+                if binding.get_macro(self).kind() == kind {
+                    Some(name)
+                } else {
+                    None
+                }
+            });
+            find_best_match_for_name(names, name, None)
+        // Then check modules.
+        }).or_else(|| {
+            if !self.use_extern_macros {
+                return None;
             }
-        };
+            let is_macro = |def| {
+                if let Def::Macro(_, def_kind) = def {
+                    def_kind == kind
+                } else {
+                    false
+                }
+            };
+            let ident = Ident::from_str(name);
+            self.lookup_typo_candidate(&vec![ident], MacroNS, is_macro)
+                .as_ref().map(|s| Symbol::intern(s))
+        });
+
         if let Some(suggestion) = suggestion {
             if suggestion != name {
                 if let MacroKind::Bang = kind {
@@ -566,7 +580,7 @@ pub fn define_macro(&mut self, item: &ast::Item, legacy_scope: &mut LegacyScope<
             });
             self.macro_exports.push(Export {
                 name: def.ident.name,
-                def: Def::Macro(self.definitions.local_def_id(def.id)),
+                def: Def::Macro(self.definitions.local_def_id(def.id), MacroKind::Bang),
             });
             self.exported_macros.push(def);
         }
index 292f1eb13663b9b36a330a614b4e0fabc111b006..3c275e0996dac0c3877c693f5bad6a7763cf0274 100644 (file)
@@ -112,7 +112,7 @@ fn nest_tables<F>(&mut self, item_id: NodeId, f: F)
         where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>)
     {
         let item_def_id = self.tcx.hir.local_def_id(item_id);
-        match self.tcx.tables.borrow().get(&item_def_id) {
+        match self.tcx.maps.typeck_tables.borrow().get(&item_def_id) {
             Some(tables) => {
                 let old_tables = self.save_ctxt.tables;
                 self.save_ctxt.tables = tables;
@@ -336,7 +336,7 @@ fn process_def_kind(&mut self,
             Def::AssociatedTy(..) |
             Def::AssociatedConst(..) |
             Def::PrimTy(_) |
-            Def::Macro(_) |
+            Def::Macro(..) |
             Def::Err => {
                span_bug!(span,
                          "process_def_kind for unexpected item: {:?}",
index ddc60fe5f81d85bfd054e2b94c2dfbe9914e1074..b1e435dcc751c40b1bdff58ed027eb1f212f1a84 100644 (file)
@@ -85,7 +85,7 @@ pub enum Row {
 pub struct SaveContext<'l, 'tcx: 'l> {
     tcx: TyCtxt<'l, 'tcx, 'tcx>,
     tables: &'l ty::TypeckTables<'tcx>,
-    analysis: &'l ty::CrateAnalysis<'tcx>,
+    analysis: &'l ty::CrateAnalysis,
     span_utils: SpanUtils<'tcx>,
 }
 
@@ -550,7 +550,7 @@ pub fn get_path_def(&self, id: NodeId) -> Def {
                 match *qpath {
                     hir::QPath::Resolved(_, ref path) => path.def,
                     hir::QPath::TypeRelative(..) => {
-                        if let Some(ty) = self.analysis.hir_ty_to_ty.get(&id) {
+                        if let Some(ty) = self.tcx.ast_ty_to_ty_cache.borrow().get(&id) {
                             if let ty::TyProjection(proj) = ty.sty {
                                 for item in self.tcx.associated_items(proj.trait_ref.def_id) {
                                     if item.kind == ty::AssociatedKind::Type {
@@ -854,7 +854,7 @@ fn extension(&self) -> &'static str {
 
 pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>,
                                krate: &ast::Crate,
-                               analysis: &'l ty::CrateAnalysis<'tcx>,
+                               analysis: &'l ty::CrateAnalysis,
                                cratename: &str,
                                odir: Option<&Path>,
                                format: Format) {
index 89525b27ed36af7d5f50d4e1b1b6c152a3fd7c2b..6c93744f014a3c2b678be69ef78b351c56e8bc2f 100644 (file)
@@ -17,7 +17,6 @@
 use std::path::Path;
 
 use syntax::ast;
-use syntax::parse::filemap_to_tts;
 use syntax::parse::lexer::{self, StringReader};
 use syntax::parse::token::{self, Token};
 use syntax::symbol::keywords;
@@ -49,23 +48,6 @@ pub fn make_path_string(file_name: &str) -> String {
         }
     }
 
-    // sub_span starts at span.lo, so we need to adjust the positions etc.
-    // If sub_span is None, we don't need to adjust.
-    pub fn make_sub_span(&self, span: Span, sub_span: Option<Span>) -> Option<Span> {
-        match sub_span {
-            None => None,
-            Some(sub) => {
-                let FileMapAndBytePos {fm, pos} = self.sess.codemap().lookup_byte_offset(span.lo);
-                let base = pos + fm.start_pos;
-                Some(Span {
-                    lo: base + self.sess.codemap().lookup_byte_offset(sub.lo).pos,
-                    hi: base + self.sess.codemap().lookup_byte_offset(sub.hi).pos,
-                    expn_id: span.expn_id,
-                })
-            }
-        }
-    }
-
     pub fn snippet(&self, span: Span) -> String {
         match self.sess.codemap().span_to_snippet(span) {
             Ok(s) => s,
@@ -74,24 +56,7 @@ pub fn snippet(&self, span: Span) -> String {
     }
 
     pub fn retokenise_span(&self, span: Span) -> StringReader<'a> {
-        // sadness - we don't have spans for sub-expressions nor access to the tokens
-        // so in order to get extents for the function name itself (which dxr expects)
-        // we need to re-tokenise the fn definition
-
-        // Note: this is a bit awful - it adds the contents of span to the end of
-        // the codemap as a new filemap. This is mostly OK, but means we should
-        // not iterate over the codemap. Also, any spans over the new filemap
-        // are incompatible with spans over other filemaps.
-        let filemap = self.sess
-                          .codemap()
-                          .new_filemap(String::from("<anon-dxr>"), None, self.snippet(span));
-        lexer::StringReader::new(&self.sess.parse_sess, filemap)
-    }
-
-    fn span_to_tts(&self, span: Span) -> Vec<TokenTree> {
-        let filename = String::from("<anon-dxr>");
-        let filemap = self.sess.codemap().new_filemap(filename, None, self.snippet(span));
-        filemap_to_tts(&self.sess.parse_sess, filemap)
+        lexer::StringReader::retokenize(&self.sess.parse_sess, span)
     }
 
     // Re-parses a path and returns the span for the last identifier in the path
@@ -103,7 +68,7 @@ pub fn span_for_last_ident(&self, span: Span) -> Option<Span> {
         loop {
             let ts = toks.real_token();
             if ts.tok == token::Eof {
-                return self.make_sub_span(span, result)
+                return result
             }
             if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) {
                 result = Some(ts.sp);
@@ -128,7 +93,7 @@ pub fn span_for_first_ident(&self, span: Span) -> Option<Span> {
                 return None;
             }
             if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) {
-                return self.make_sub_span(span, Some(ts.sp));
+                return Some(ts.sp);
             }
 
             bracket_count += match ts.tok {
@@ -178,10 +143,7 @@ pub fn sub_span_for_meth_name(&self, span: Span) -> Option<Span> {
             }
             prev = next;
         }
-        if result.is_none() && prev_span.is_some() {
-            return self.make_sub_span(span, prev_span);
-        }
-        return self.make_sub_span(span, result);
+        result.or(prev_span)
     }
 
     // Return the span for the last ident before a `<` and outside any
@@ -241,9 +203,9 @@ pub fn sub_span_for_type_name(&self, span: Span) -> Option<Span> {
                       loc.line);
         }
         if result.is_none() && prev.tok.is_ident() && angle_count == 0 {
-            return self.make_sub_span(span, Some(prev.sp));
+            return Some(prev.sp);
         }
-        self.make_sub_span(span, result)
+        result
     }
 
     // Reparse span and return an owned vector of sub spans of the first limit
@@ -310,7 +272,7 @@ pub fn spans_with_brackets(&self, span: Span, nesting: isize, limit: isize) -> V
                 angle_count += 1;
             }
             if ts.tok.is_ident() && angle_count == nesting {
-                result.push(self.make_sub_span(span, Some(ts.sp)).unwrap());
+                result.push(ts.sp);
             }
         }
     }
@@ -320,9 +282,12 @@ pub fn spans_with_brackets(&self, span: Span, nesting: isize, limit: isize) -> V
     /// end of the 'signature' part, that is up to, but not including an opening
     /// brace or semicolon.
     pub fn signature_string_for_span(&self, span: Span) -> String {
-        let mut toks = self.span_to_tts(span).into_iter();
+        let mut toks = self.retokenise_span(span);
+        toks.real_token();
+        let mut toks = toks.parse_all_token_trees().unwrap().into_iter();
         let mut prev = toks.next().unwrap();
-        let first_span = prev.get_span();
+
+        let first_span = prev.span();
         let mut angle_count = 0;
         for tok in toks {
             if let TokenTree::Token(_, ref tok) = prev {
@@ -340,10 +305,10 @@ pub fn signature_string_for_span(&self, span: Span) -> String {
                 continue;
             }
             if let TokenTree::Token(_, token::Semi) = tok {
-                return self.snippet(mk_sp(first_span.lo, prev.get_span().hi));
+                return self.snippet(mk_sp(first_span.lo, prev.span().hi));
             } else if let TokenTree::Delimited(_, ref d) = tok {
                 if d.delim == token::Brace {
-                    return self.snippet(mk_sp(first_span.lo, prev.get_span().hi));
+                    return self.snippet(mk_sp(first_span.lo, prev.span().hi));
                 }
             }
             prev = tok;
@@ -360,7 +325,7 @@ pub fn sub_span_before_token(&self, span: Span, tok: Token) -> Option<Span> {
             }
             let next = toks.real_token();
             if next.tok == tok {
-                return self.make_sub_span(span, Some(prev.sp));
+                return Some(prev.sp);
             }
             prev = next;
         }
@@ -374,7 +339,7 @@ pub fn sub_span_of_token(&self, span: Span, tok: Token) -> Option<Span> {
                 return None;
             }
             if next.tok == tok {
-                return self.make_sub_span(span, Some(next.sp));
+                return Some(next.sp);
             }
         }
     }
@@ -399,7 +364,7 @@ fn sub_span_after<F: Fn(Token) -> bool>(&self, span: Span, f: F) -> Option<Span>
                 if ts.tok == token::Eof {
                     return None
                 } else {
-                    return self.make_sub_span(span, Some(ts.sp));
+                    return Some(ts.sp);
                 }
             }
         }
@@ -444,7 +409,7 @@ pub fn span_for_macro_def_name(&self, span: Span) -> Option<Span> {
             if ts.tok == token::Not {
                 let ts = toks.real_token();
                 if ts.tok.is_ident() {
-                    return self.make_sub_span(span, Some(ts.sp));
+                    return Some(ts.sp);
                 } else {
                     return None;
                 }
@@ -463,7 +428,7 @@ pub fn span_for_macro_use_name(&self, span:Span) -> Option<Span> {
             let ts = toks.real_token();
             if ts.tok == token::Not {
                 if prev.tok.is_ident() {
-                    return self.make_sub_span(span, Some(prev.sp));
+                    return Some(prev.sp);
                 } else {
                     return None;
                 }
index a476b1d29e5fb823ef8ffb9a605c2ab474210ba5..0bbe981f2f72c816bd50b38695693d25101450fb 100644 (file)
@@ -327,20 +327,18 @@ pub struct FnType {
 
 impl FnType {
     pub fn new<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                         abi: Abi,
-                         sig: &ty::FnSig<'tcx>,
+                         sig: ty::FnSig<'tcx>,
                          extra_args: &[Ty<'tcx>]) -> FnType {
-        let mut fn_ty = FnType::unadjusted(ccx, abi, sig, extra_args);
-        fn_ty.adjust_for_abi(ccx, abi, sig);
+        let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
+        fn_ty.adjust_for_abi(ccx, sig);
         fn_ty
     }
 
     pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                abi: Abi,
-                                sig: &ty::FnSig<'tcx>,
+                                sig: ty::FnSig<'tcx>,
                                 extra_args: &[Ty<'tcx>]) -> FnType {
         use self::Abi::*;
-        let cconv = match ccx.sess().target.target.adjust_abi(abi) {
+        let cconv = match ccx.sess().target.target.adjust_abi(sig.abi) {
             RustIntrinsic | PlatformIntrinsic |
             Rust | RustCall => llvm::CCallConv,
 
@@ -357,13 +355,14 @@ pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             Aapcs => llvm::ArmAapcsCallConv,
             PtxKernel => llvm::PtxKernel,
             Msp430Interrupt => llvm::Msp430Intr,
+            X86Interrupt => llvm::X86_Intr,
 
             // These API constants ought to be more specific...
             Cdecl => llvm::CCallConv,
         };
 
         let mut inputs = sig.inputs();
-        let extra_args = if abi == RustCall {
+        let extra_args = if sig.abi == RustCall {
             assert!(!sig.variadic && extra_args.is_empty());
 
             match sig.inputs().last().unwrap().sty {
@@ -388,7 +387,7 @@ pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         let linux_s390x = target.target_os == "linux"
                        && target.arch == "s390x"
                        && target.target_env == "gnu";
-        let rust_abi = match abi {
+        let rust_abi = match sig.abi {
             RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
             _ => false
         };
@@ -506,7 +505,11 @@ pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                 if let Some(inner) = rust_ptr_attrs(ty, &mut data) {
                     data.attrs.set(ArgAttribute::NonNull);
                     if ccx.tcx().struct_tail(inner).is_trait() {
+                        // vtables can be safely marked non-null, readonly
+                        // and noalias.
                         info.attrs.set(ArgAttribute::NonNull);
+                        info.attrs.set(ArgAttribute::ReadOnly);
+                        info.attrs.set(ArgAttribute::NoAlias);
                     }
                 }
                 args.push(data);
@@ -531,8 +534,8 @@ pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     pub fn adjust_for_abi<'a, 'tcx>(&mut self,
                                     ccx: &CrateContext<'a, 'tcx>,
-                                    abi: Abi,
-                                    sig: &ty::FnSig<'tcx>) {
+                                    sig: ty::FnSig<'tcx>) {
+        let abi = sig.abi;
         if abi == Abi::Unadjusted { return }
 
         if abi == Abi::Rust || abi == Abi::RustCall ||
index 41c0eaa52a77d1bc1a2f1d6cec13bc84a850a496..8125f432ff5ae963feb0db9e3aefbb087064ecb2 100644 (file)
@@ -47,7 +47,7 @@
 use session::config::{self, NoDebugInfo};
 use rustc_incremental::IncrementalHashesMap;
 use session::{self, DataTypeKind, Session};
-use abi::{self, Abi, FnType};
+use abi::{self, FnType};
 use mir::lvalue::LvalueRef;
 use adt;
 use attributes;
@@ -472,8 +472,15 @@ pub fn load_fat_ptr<'a, 'tcx>(
         b.load(ptr, alignment.to_align())
     };
 
-    // FIXME: emit metadata on `meta`.
-    let meta = b.load(get_meta(b, src), alignment.to_align());
+    let meta = get_meta(b, src);
+    let meta_ty = val_ty(meta);
+    // If the 'meta' field is a pointer, it's a vtable, so use load_nonnull
+    // instead
+    let meta = if meta_ty.element_type().kind() == llvm::TypeKind::Pointer {
+        b.load_nonnull(meta, None)
+    } else {
+        b.load(meta, None)
+    };
 
     (ptr, meta)
 }
@@ -593,8 +600,8 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
     let fn_ty = ccx.tcx().erase_regions(&fn_ty);
     let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);
 
-    let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_ty);
-    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig);
+    let sig = common::ty_fn_sig(ccx, fn_ty);
+    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
 
     let lldecl = match ccx.instances().borrow().get(&instance) {
         Some(&val) => val,
@@ -607,10 +614,8 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
         attributes::emit_uwtable(lldecl, true);
     }
 
-    let fn_ty = FnType::new(ccx, abi, &sig, &[]);
-
     let mir = ccx.tcx().item_mir(instance.def);
-    mir::trans_mir(ccx, lldecl, fn_ty, &mir, instance, &sig, abi);
+    mir::trans_mir(ccx, lldecl, &mir, instance, sig);
 }
 
 pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
@@ -625,7 +630,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty);
 
     let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&ctor_ty.fn_sig());
-    let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
+    let fn_ty = FnType::new(ccx, sig, &[]);
 
     let bcx = Builder::new_block(ccx, llfn, "entry-block");
     if !fn_ty.ret.is_ignore() {
@@ -1132,11 +1137,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let ty::CrateAnalysis { export_map, reachable, name, .. } = analysis;
     let exported_symbols = find_exported_symbols(tcx, reachable);
 
-    let check_overflow = if let Some(v) = tcx.sess.opts.debugging_opts.force_overflow_checks {
-        v
-    } else {
-        tcx.sess.opts.debug_assertions
-    };
+    let check_overflow = tcx.sess.overflow_checks();
 
     let link_meta = link::build_link_meta(incremental_hashes_map, &name);
 
index f64e581c1773ee2a81e42a68c55f8526abb06c2b..a62f07042a7035749ba970c1d685e2ca6957fed1 100644 (file)
@@ -1149,6 +1149,13 @@ pub fn add_incoming_to_phi(&self, phi: ValueRef, val: ValueRef, bb: BasicBlockRe
         }
     }
 
+    pub fn set_invariant_load(&self, load: ValueRef) {
+        unsafe {
+            llvm::LLVMSetMetadata(load, llvm::MD_invariant_load as c_uint,
+                                  llvm::LLVMMDNodeInContext(self.ccx.llcx(), ptr::null(), 0));
+        }
+    }
+
     /// Returns the ptr value that should be used for storing `val`.
     fn check_store<'b>(&self,
                        val: ValueRef,
@@ -1181,7 +1188,7 @@ fn check_call<'b>(&self,
         }
 
         assert!(fn_ty.kind() == llvm::TypeKind::Function,
-                "builder::{} not passed a function", typ);
+                "builder::{} not passed a function, but {:?}", typ, fn_ty);
 
         let param_tys = fn_ty.func_params();
 
index 4a8658dd2e308a86d2bec71d3c0a890102c6979a..4925c9d547e9d19ac45108ae6479dcedc2b3b2b0 100644 (file)
@@ -18,7 +18,7 @@
 
 use llvm::{self, ValueRef, get_params};
 use rustc::hir::def_id::DefId;
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Substs, Subst};
 use rustc::traits;
 use abi::{Abi, FnType};
 use attributes;
@@ -83,7 +83,7 @@ pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs
 
         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 {
+            if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
                 return Callee {
                     data: Intrinsic,
                     ty: fn_ty
@@ -93,9 +93,9 @@ pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx 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) {
+            if let Some(i) = adt_def.variants.iter().position(|v| def_id == v.did) {
                 return Callee {
-                    data: NamedTupleConstructor(Disr::from(v.disr_val)),
+                    data: NamedTupleConstructor(Disr::for_variant(tcx, adt_def, i)),
                     ty: fn_ty
                 };
             }
@@ -169,14 +169,13 @@ pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>,
     /// The extra argument types are for variadic (extern "C") functions.
     pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
                               extra_args: &[Ty<'tcx>]) -> FnType {
-        let abi = self.ty.fn_abi();
-        let sig = ccx.tcx().erase_late_bound_regions_and_normalize(self.ty.fn_sig());
-        let mut fn_ty = FnType::unadjusted(ccx, abi, &sig, extra_args);
+        let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&self.ty.fn_sig());
+        let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
         if let Virtual(_) = self.data {
             // Don't pass the vtable, it's not an argument of the virtual fn.
             fn_ty.args[1].ignore();
         }
-        fn_ty.adjust_for_abi(ccx, abi, &sig);
+        fn_ty.adjust_for_abi(ccx, sig);
         fn_ty
     }
 
@@ -307,38 +306,32 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty);
 
     // Make a version with the type of by-ref closure.
-    let ty::ClosureTy { unsafety, abi, mut sig } = tcx.closure_type(def_id, substs);
-    sig.0 = tcx.mk_fn_sig(
-        iter::once(ref_closure_ty).chain(sig.0.inputs().iter().cloned()),
-        sig.0.output(),
-        sig.0.variadic
-    );
-    let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-        unsafety: unsafety,
-        abi: abi,
-        sig: sig.clone()
-    }));
+    let sig = tcx.closure_type(def_id).subst(tcx, substs.substs);
+    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
+    assert_eq!(sig.abi, Abi::RustCall);
+    let llref_fn_ty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig(
+        iter::once(ref_closure_ty).chain(sig.inputs().iter().cloned()),
+        sig.output(),
+        sig.variadic,
+        sig.unsafety,
+        Abi::RustCall
+    )));
     debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
            llref_fn_ty);
 
 
     // Make a version of the closure type with the same arguments, but
     // with argument #0 being by value.
-    assert_eq!(abi, Abi::RustCall);
-    sig.0 = tcx.mk_fn_sig(
-        iter::once(closure_ty).chain(sig.0.inputs().iter().skip(1).cloned()),
-        sig.0.output(),
-        sig.0.variadic
+    let sig = tcx.mk_fn_sig(
+        iter::once(closure_ty).chain(sig.inputs().iter().cloned()),
+        sig.output(),
+        sig.variadic,
+        sig.unsafety,
+        Abi::RustCall
     );
 
-    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
-    let fn_ty = FnType::new(ccx, abi, &sig, &[]);
-
-    let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-        unsafety: unsafety,
-        abi: abi,
-        sig: ty::Binder(sig)
-    }));
+    let fn_ty = FnType::new(ccx, sig, &[]);
+    let llonce_fn_ty = tcx.mk_fn_ptr(ty::Binder(sig));
 
     // Create the by-value helper.
     let function_name = method_instance.symbol_name(ccx.shared());
@@ -470,33 +463,20 @@ fn trans_fn_pointer_shim<'a, 'tcx>(
 
     // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
     // which is the fn pointer, and `args`, which is the arguments tuple.
-    let sig = match bare_fn_ty.sty {
-        ty::TyFnDef(..,
-                    &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
-                                    abi: Abi::Rust,
-                                    ref sig }) |
-        ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal,
-                                    abi: Abi::Rust,
-                                    ref sig }) => sig,
-
-        _ => {
-            bug!("trans_fn_pointer_shim invoked on invalid type: {}",
-                 bare_fn_ty);
-        }
-    };
-    let sig = tcx.erase_late_bound_regions_and_normalize(sig);
+    let sig = bare_fn_ty.fn_sig();
+    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
+    assert_eq!(sig.unsafety, hir::Unsafety::Normal);
+    assert_eq!(sig.abi, Abi::Rust);
     let tuple_input_ty = tcx.intern_tup(sig.inputs(), false);
     let sig = tcx.mk_fn_sig(
         [bare_fn_ty_maybe_ref, tuple_input_ty].iter().cloned(),
         sig.output(),
-        false
+        false,
+        hir::Unsafety::Normal,
+        Abi::RustCall
     );
-    let fn_ty = FnType::new(ccx, Abi::RustCall, &sig, &[]);
-    let tuple_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-        unsafety: hir::Unsafety::Normal,
-        abi: Abi::RustCall,
-        sig: ty::Binder(sig)
-    }));
+    let fn_ty = FnType::new(ccx, sig, &[]);
+    let tuple_fn_ty = tcx.mk_fn_ptr(ty::Binder(sig));
     debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
 
     //
@@ -600,7 +580,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // other weird situations. Annoying.
 
     // Create a fn pointer with the substituted signature.
-    let fn_ptr_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(common::ty_fn_ty(ccx, fn_ty).into_owned()));
+    let fn_ptr_ty = tcx.mk_fn_ptr(common::ty_fn_sig(ccx, fn_ty));
     let llptrty = type_of::type_of(ccx, fn_ptr_ty);
 
     let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
index b5f948442b774d486aa95075981eab3ec1b827e1..b12c1220b2b4de797a9c9f4be568a02839fd35eb 100644 (file)
@@ -489,6 +489,20 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
                                                           self.output);
                 }
             }
+            mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => {
+                let source_ty = operand.ty(self.mir, self.scx.tcx());
+                match source_ty.sty {
+                    ty::TyClosure(def_id, substs) => {
+                        let closure_trans_item =
+                            create_fn_trans_item(self.scx,
+                                                 def_id,
+                                                 substs.substs,
+                                                 self.param_substs);
+                        self.output.push(closure_trans_item);
+                    }
+                    _ => bug!(),
+                }
+            }
             mir::Rvalue::Box(..) => {
                 let exchange_malloc_fn_def_id =
                     self.scx
@@ -615,19 +629,13 @@ fn can_result_in_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                               def_id: DefId)
                                               -> bool {
             match tcx.item_type(def_id).sty {
-                ty::TyFnDef(def_id, _, f) => {
+                ty::TyFnDef(def_id, _, _) => {
                     // Some constructors also have type TyFnDef but they are
                     // always instantiated inline and don't result in a
                     // translation item. Same for FFI functions.
                     if let Some(hir_map::NodeForeignItem(_)) = tcx.hir.get_if_local(def_id) {
                         return false;
                     }
-
-                    if let Some(adt_def) = f.sig.output().skip_binder().ty_adt_def() {
-                        if adt_def.variants.iter().any(|v| def_id == v.did) {
-                            return false;
-                        }
-                    }
                 }
                 ty::TyClosure(..) => {}
                 _ => return false
@@ -674,10 +682,10 @@ fn visit_terminator_kind(&mut self,
 
         fn is_drop_in_place_intrinsic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 def_id: DefId,
-                                                bare_fn_ty: &ty::BareFnTy<'tcx>)
+                                                bare_fn_ty: ty::PolyFnSig<'tcx>)
                                                 -> bool {
-            (bare_fn_ty.abi == Abi::RustIntrinsic ||
-             bare_fn_ty.abi == Abi::PlatformIntrinsic) &&
+            (bare_fn_ty.abi() == Abi::RustIntrinsic ||
+             bare_fn_ty.abi() == Abi::PlatformIntrinsic) &&
             tcx.item_name(def_id) == "drop_in_place"
         }
     }
@@ -689,6 +697,16 @@ fn is_drop_in_place_intrinsic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   def_id: DefId)
                                   -> bool {
+    if let ty::TyFnDef(_, _, sig) = tcx.item_type(def_id).sty {
+        if let Some(adt_def) = sig.output().skip_binder().ty_adt_def() {
+            if adt_def.variants.iter().any(|v| def_id == v.did) {
+                // HACK: ADT constructors are translated in-place and
+                // do not have a trans-item.
+                return false;
+            }
+        }
+    }
+
     if def_id.is_local() {
         true
     } else {
@@ -736,7 +754,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
     // If the type implements Drop, also add a translation item for the
     // monomorphized Drop::drop() implementation.
     let destructor_did = match ty.sty {
-        ty::TyAdt(def, _) => def.destructor(),
+        ty::TyAdt(def, _) => def.destructor(scx.tcx()),
         _ => None
     };
 
index 64100ed4191cc3645b94337814865e0c186bc5a4..1032da7ef75bb4ff9f66d87f67388b01afc14eb9 100644 (file)
 use value::Value;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::layout::Layout;
+use rustc::ty::subst::Subst;
 use rustc::traits::{self, SelectionContext, Reveal};
 use rustc::hir;
 
 use libc::{c_uint, c_char};
-use std::borrow::Cow;
 use std::iter;
 
 use syntax::ast;
@@ -570,17 +570,17 @@ pub fn shift_mask_val<'a, 'tcx>(
     }
 }
 
-pub fn ty_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                          ty: Ty<'tcx>)
-                          -> Cow<'tcx, ty::BareFnTy<'tcx>>
+pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                           ty: Ty<'tcx>)
+                           -> ty::PolyFnSig<'tcx>
 {
     match ty.sty {
-        ty::TyFnDef(_, _, fty) => Cow::Borrowed(fty),
+        ty::TyFnDef(_, _, sig) => sig,
         // Shims currently have type TyFnPtr. Not sure this should remain.
-        ty::TyFnPtr(fty) => Cow::Borrowed(fty),
+        ty::TyFnPtr(sig) => sig,
         ty::TyClosure(def_id, substs) => {
             let tcx = ccx.tcx();
-            let ty::ClosureTy { unsafety, abi, sig } = tcx.closure_type(def_id, substs);
+            let sig = tcx.closure_type(def_id).subst(tcx, substs.substs);
 
             let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv);
             let env_ty = match tcx.closure_kind(def_id) {
@@ -589,12 +589,13 @@ pub fn ty_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                 ty::ClosureKind::FnOnce => ty,
             };
 
-            let sig = sig.map_bound(|sig| tcx.mk_fn_sig(
+            sig.map_bound(|sig| tcx.mk_fn_sig(
                 iter::once(env_ty).chain(sig.inputs().iter().cloned()),
                 sig.output(),
-                sig.variadic
-            ));
-            Cow::Owned(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: sig })
+                sig.variadic,
+                sig.unsafety,
+                sig.abi
+            ))
         }
         _ => bug!("unexpected type {:?} to ty_fn_sig", ty)
     }
index b68de7b46c82e9b7a0ded83ce76ec76989107115..011f7748f2c98764ae4f86cba39d0afcb68001e3 100644 (file)
@@ -213,11 +213,11 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
     g
 }
 
-pub fn trans_static(ccx: &CrateContext,
-                    m: hir::Mutability,
-                    id: ast::NodeId,
-                    attrs: &[ast::Attribute])
-                    -> Result<ValueRef, ConstEvalErr> {
+pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                              m: hir::Mutability,
+                              id: ast::NodeId,
+                              attrs: &[ast::Attribute])
+                              -> Result<ValueRef, ConstEvalErr<'tcx>> {
     unsafe {
         let def_id = ccx.tcx().hir.local_def_id(id);
         let g = get_static(ccx, def_id);
index 799f502aadbfa97cd4f844eb6e596a22119e4d40..d5f7549ece07b21134587e71f1c9fd10a55084be 100644 (file)
@@ -959,15 +959,13 @@ pub fn eh_unwind_resume(&self) -> ValueRef {
             return llfn;
         }
 
-        let ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-            unsafety: hir::Unsafety::Unsafe,
-            abi: Abi::C,
-            sig: ty::Binder(tcx.mk_fn_sig(
-                iter::once(tcx.mk_mut_ptr(tcx.types.u8)),
-                tcx.types.never,
-                false
-            )),
-        }));
+        let ty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig(
+            iter::once(tcx.mk_mut_ptr(tcx.types.u8)),
+            tcx.types.never,
+            false,
+            hir::Unsafety::Unsafe,
+            Abi::C
+        )));
 
         let llfn = declare::declare_fn(self, "rust_eh_unwind_resume", ty);
         attributes::unwind(llfn, true);
index 11c0bf852f727ac829d734d6e13db7f0ed7f97cf..f6cdd883850cc5dc04b6062c2afd0902bbbfed02 100644 (file)
@@ -373,11 +373,11 @@ fn slice_layout_is_correct<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
 fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                       unique_type_id: UniqueTypeId,
-                                      signature: &ty::PolyFnSig<'tcx>,
+                                      signature: ty::PolyFnSig<'tcx>,
                                       span: Span)
                                       -> MetadataCreationResult
 {
-    let signature = cx.tcx().erase_late_bound_regions(signature);
+    let signature = cx.tcx().erase_late_bound_regions(&signature);
 
     let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs().len() + 1);
 
@@ -558,10 +558,10 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 Err(metadata) => return metadata,
             }
         }
-        ty::TyFnDef(.., ref barefnty) | ty::TyFnPtr(ref barefnty) => {
+        ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => {
             let fn_metadata = subroutine_type_metadata(cx,
                                                        unique_type_id,
-                                                       &barefnty.sig,
+                                                       sig,
                                                        usage_site_span).metadata;
             match debug_context(cx).type_map
                                    .borrow()
@@ -1465,10 +1465,10 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     // <unknown>
     let file_metadata = unknown_file_metadata(cx);
 
-    let variants = &enum_type.ty_adt_def().unwrap().variants;
-    let enumerators_metadata: Vec<DIDescriptor> = variants
-        .iter()
-        .map(|v| {
+    let def = enum_type.ty_adt_def().unwrap();
+    let enumerators_metadata: Vec<DIDescriptor> = def.discriminants(cx.tcx())
+        .zip(&def.variants)
+        .map(|(discr, v)| {
             let token = v.name.as_str();
             let name = CString::new(token.as_bytes()).unwrap();
             unsafe {
@@ -1476,7 +1476,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                     DIB(cx),
                     name.as_ptr(),
                     // FIXME: what if enumeration has i128 discriminant?
-                    v.disr_val as u64)
+                    discr.to_u128_unchecked() as u64)
             }
         })
         .collect();
index e9b592ec8fd79814ef6f5061b6aa08d3771749f8..d5f04542d0255d5b52bfb058e6f735d9e4b80db4 100644 (file)
@@ -198,8 +198,7 @@ pub fn finalize(cx: &CrateContext) {
 /// for the function.
 pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                                instance: Instance<'tcx>,
-                                               sig: &ty::FnSig<'tcx>,
-                                               abi: Abi,
+                                               sig: ty::FnSig<'tcx>,
                                                llfn: ValueRef,
                                                mir: &mir::Mir) -> FunctionDebugContext {
     if cx.sess().opts.debuginfo == NoDebugInfo {
@@ -225,7 +224,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path);
 
     let function_type_metadata = unsafe {
-        let fn_signature = get_function_signature(cx, sig, abi);
+        let fn_signature = get_function_signature(cx, sig);
         llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
     };
 
@@ -295,8 +294,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     return FunctionDebugContext::RegularContext(fn_debug_context);
 
     fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                                        sig: &ty::FnSig<'tcx>,
-                                        abi: Abi) -> DIArray {
+                                        sig: ty::FnSig<'tcx>) -> DIArray {
         if cx.sess().opts.debuginfo == LimitedDebugInfo {
             return create_DIArray(DIB(cx), &[]);
         }
@@ -309,7 +307,7 @@ fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             _ => type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP)
         });
 
-        let inputs = if abi == Abi::RustCall {
+        let inputs = if sig.abi == Abi::RustCall {
             &sig.inputs()[..sig.inputs().len() - 1]
         } else {
             sig.inputs()
@@ -320,7 +318,7 @@ fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP));
         }
 
-        if abi == Abi::RustCall && !sig.inputs().is_empty() {
+        if sig.abi == Abi::RustCall && !sig.inputs().is_empty() {
             if let ty::TyTuple(args, _) = sig.inputs()[sig.inputs().len() - 1].sty {
                 for &argument_type in args {
                     signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP));
@@ -332,7 +330,7 @@ fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     }
 
     fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                                         generics: &ty::Generics<'tcx>,
+                                         generics: &ty::Generics,
                                          substs: &Substs<'tcx>,
                                          file_metadata: DIFile,
                                          name_to_append_suffix_to: &mut String)
@@ -382,9 +380,7 @@ fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         return create_DIArray(DIB(cx), &template_params[..]);
     }
 
-    fn get_type_parameter_names<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                                          generics: &ty::Generics<'tcx>)
-                                          -> Vec<ast::Name> {
+    fn get_type_parameter_names(cx: &CrateContext, generics: &ty::Generics) -> Vec<ast::Name> {
         let mut names = generics.parent.map_or(vec![], |def_id| {
             get_type_parameter_names(cx, cx.tcx().item_generics(def_id))
         });
index 018bbb6e97d345167e46c9edfec272fa803f58f4..13ff6646e666256f40772cb96a7d8934e6cb52d7 100644 (file)
@@ -96,12 +96,13 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 push_type_params(cx, principal.substs, output);
             }
         },
-        ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
-        ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
-            if unsafety == hir::Unsafety::Unsafe {
+        ty::TyFnDef(.., sig) |
+        ty::TyFnPtr(sig) => {
+            if sig.unsafety() == hir::Unsafety::Unsafe {
                 output.push_str("unsafe ");
             }
 
+            let abi = sig.abi();
             if abi != ::abi::Abi::Rust {
                 output.push_str("extern \"");
                 output.push_str(abi.name());
@@ -110,7 +111,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
             output.push_str("fn(");
 
-            let sig = cx.tcx().erase_late_bound_regions_and_normalize(sig);
+            let sig = cx.tcx().erase_late_bound_regions_and_normalize(&sig);
             if !sig.inputs().is_empty() {
                 for &parameter_type in sig.inputs() {
                     push_debuginfo_type_name(cx, parameter_type, true, output);
index 15a1c990aadc6aa674f83abde74b3cd8da235673..ceff96a39b2c982a04bc8233028aa67357506961 100644 (file)
@@ -14,6 +14,7 @@
 use super::namespace::item_namespace;
 
 use rustc::hir::def_id::DefId;
+use rustc::ty::DefIdTree;
 
 use llvm;
 use llvm::debuginfo::{DIScope, DIBuilderRef, DIDescriptor, DIArray};
@@ -74,11 +75,8 @@ pub fn DIB(cx: &CrateContext) -> DIBuilderRef {
 
 pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: DefId)
                                    -> (DIScope, Span) {
-    let containing_scope = item_namespace(cx, DefId {
-        krate: def_id.krate,
-        index: cx.tcx().def_key(def_id).parent
-                 .expect("get_namespace_and_span_for_item: missing parent?")
-    });
+    let containing_scope = item_namespace(cx, cx.tcx().parent(def_id)
+        .expect("get_namespace_and_span_for_item: missing parent?"));
 
     // Try to get some span information, if we have an inlined item.
     let definition_span = cx.tcx().def_span(def_id);
index 7ac482459ee39f5846a3dd4ec807bbde27cb8405..2787812f9622ccc48d1d8ce4df268dc24c454d8b 100644 (file)
@@ -132,11 +132,11 @@ pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type) -> ValueRef {
 pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
                             fn_type: ty::Ty<'tcx>) -> ValueRef {
     debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
-    let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_type);
-    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig);
+    let sig = common::ty_fn_sig(ccx, fn_type);
+    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
     debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
 
-    let fty = FnType::new(ccx, abi, &sig, &[]);
+    let fty = FnType::new(ccx, sig, &[]);
     let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.llvm_type(ccx));
 
     // FIXME(canndrew): This is_never should really be an is_uninhabited
@@ -144,7 +144,7 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
         llvm::Attribute::NoReturn.apply_llfn(Function, llfn);
     }
 
-    if abi != Abi::Rust && abi != Abi::RustCall {
+    if sig.abi != Abi::Rust && sig.abi != Abi::RustCall {
         attributes::unwind(llfn, false);
     }
 
index f3a62bc85b8d93252c441c43ca62f63e9ab0e24e..a940faac8387735a7288f915564ea3b1dc0f88a0 100644 (file)
@@ -8,10 +8,42 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use rustc::middle::const_val::ConstVal;
+use rustc::ty::{self, TyCtxt};
+use rustc_const_math::ConstInt;
+
 #[derive(Debug, Eq, PartialEq, Copy, Clone)]
 pub struct Disr(pub u64);
 
 impl Disr {
+    pub fn for_variant(tcx: TyCtxt,
+                       def: &ty::AdtDef,
+                       variant_index: usize) -> Self {
+        let mut explicit_index = variant_index;
+        let mut explicit_value = Disr(0);
+        loop {
+            match def.variants[explicit_index].discr {
+                ty::VariantDiscr::Relative(0) => break,
+                ty::VariantDiscr::Relative(distance) => {
+                    explicit_index -= distance;
+                }
+                ty::VariantDiscr::Explicit(expr_did) => {
+                    match tcx.maps.monomorphic_const_eval.borrow()[&expr_did] {
+                        Ok(ConstVal::Integral(v)) => {
+                            explicit_value = Disr::from(v);
+                            break;
+                        }
+                        _ => {
+                            explicit_index -= 1;
+                        }
+                    }
+                }
+            }
+        }
+        let distance = variant_index - explicit_index;
+        explicit_value.wrapping_add(Disr::from(distance))
+    }
+
     pub fn wrapping_add(self, other: Self) -> Self {
         Disr(self.0.wrapping_add(other.0))
     }
@@ -24,10 +56,10 @@ fn bitand(self, other: Self) -> Self {
     }
 }
 
-impl From<::rustc::ty::Disr> for Disr {
-    fn from(i: ::rustc::ty::Disr) -> Disr {
+impl From<ConstInt> for Disr {
+    fn from(i: ConstInt) -> Disr {
         // FIXME: what if discr has 128 bit discr?
-        Disr(i as u64)
+        Disr(i.to_u128_unchecked() as u64)
     }
 }
 
index d66ea4d650f7b4638c226adc826d2316a086c9be..32fc3d5af24451f21d97a2a39d6c176329f1dd26 100644 (file)
@@ -237,7 +237,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
             bcx.call(dtor, &[ptr.llval], None);
             bcx
         }
-        ty::TyAdt(def, ..) if def.has_dtor() && !skip_dtor => {
+        ty::TyAdt(def, ..) if def.has_dtor(bcx.tcx()) && !skip_dtor => {
             let shallow_drop = def.is_union();
             let tcx = bcx.tcx();
 
@@ -265,7 +265,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
                 traits::VtableImpl(data) => data,
                 _ => bug!("dtor for {:?} is not an impl???", t)
             };
-            let dtor_did = def.destructor().unwrap();
+            let dtor_did = def.destructor(tcx).unwrap();
             let callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs);
             let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
             let llret;
@@ -386,7 +386,15 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
             let info = bcx.pointercast(info, Type::int(bcx.ccx).ptr_to());
             let size_ptr = bcx.gepi(info, &[1]);
             let align_ptr = bcx.gepi(info, &[2]);
-            (bcx.load(size_ptr, None), bcx.load(align_ptr, None))
+
+            let size = bcx.load(size_ptr, None);
+            let align = bcx.load(align_ptr, None);
+
+            // Vtable loads are invariant
+            bcx.set_invariant_load(size);
+            bcx.set_invariant_load(align);
+
+            (size, align)
         }
         ty::TySlice(_) | ty::TyStr => {
             let unit_ty = t.sequence_element_type(bcx.tcx());
@@ -513,11 +521,10 @@ fn iter_variant_fields<'a, 'tcx>(
                         let llswitch = cx.switch(lldiscrim_a, ret_void_cx.llbb(), n_variants);
                         let next_cx = cx.build_sibling_block("enum-iter-next");
 
-                        for (i, variant) in adt.variants.iter().enumerate() {
-                            let variant_cx_name = format!("enum-iter-variant-{}",
-                                &variant.disr_val.to_string());
+                        for (i, discr) in adt.discriminants(cx.tcx()).enumerate() {
+                            let variant_cx_name = format!("enum-iter-variant-{}", i);
                             let variant_cx = cx.build_sibling_block(&variant_cx_name);
-                            let case_val = adt::trans_case(&cx, t, Disr::from(variant.disr_val));
+                            let case_val = adt::trans_case(&cx, t, Disr::from(discr));
                             variant_cx.add_case(llswitch, case_val, variant_cx.llbb());
                             ptr.ty = LvalueTy::Downcast {
                                 adt_def: adt,
index 333a0802ee6ff664c75ebdb4d3a4f8d4ae57c735..b7aedb742db02e676e7ccb9d1bbb4563fa8652e6 100644 (file)
@@ -97,12 +97,12 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
     let ccx = bcx.ccx;
     let tcx = ccx.tcx();
 
-    let (def_id, substs, fty) = match callee_ty.sty {
-        ty::TyFnDef(def_id, substs, ref fty) => (def_id, substs, fty),
+    let (def_id, substs, sig) = match callee_ty.sty {
+        ty::TyFnDef(def_id, substs, sig) => (def_id, substs, sig),
         _ => bug!("expected fn item type, found {}", callee_ty)
     };
 
-    let sig = tcx.erase_late_bound_regions_and_normalize(&fty.sig);
+    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
     let arg_tys = sig.inputs();
     let ret_ty = sig.output();
     let name = &*tcx.item_name(def_id).as_str();
@@ -878,13 +878,13 @@ fn gen_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                     output: Ty<'tcx>,
                     trans: &mut for<'b> FnMut(Builder<'b, 'tcx>))
                     -> ValueRef {
-    let sig = ccx.tcx().mk_fn_sig(inputs.into_iter(), output, false);
-
-    let rust_fn_ty = ccx.tcx().mk_fn_ptr(ccx.tcx().mk_bare_fn(ty::BareFnTy {
-        unsafety: hir::Unsafety::Unsafe,
-        abi: Abi::Rust,
-        sig: ty::Binder(sig)
-    }));
+    let rust_fn_ty = ccx.tcx().mk_fn_ptr(ty::Binder(ccx.tcx().mk_fn_sig(
+        inputs.into_iter(),
+        output,
+        false,
+        hir::Unsafety::Unsafe,
+        Abi::Rust
+    )));
     let llfn = declare::define_internal_fn(ccx, name, rust_fn_ty);
     let bcx = Builder::new_block(ccx, llfn, "entry-block");
     trans(bcx);
@@ -905,11 +905,13 @@ fn get_rust_try_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // Define the type up front for the signature of the rust_try function.
     let tcx = ccx.tcx();
     let i8p = tcx.mk_mut_ptr(tcx.types.i8);
-    let fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
-        unsafety: hir::Unsafety::Unsafe,
-        abi: Abi::Rust,
-        sig: ty::Binder(tcx.mk_fn_sig(iter::once(i8p), tcx.mk_nil(), false)),
-    }));
+    let fn_ty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig(
+        iter::once(i8p),
+        tcx.mk_nil(),
+        false,
+        hir::Unsafety::Unsafe,
+        Abi::Rust
+    )));
     let output = tcx.types.i32;
     let rust_try = gen_fn(ccx, "__rust_try", vec![fn_ty, i8p, i8p], output, trans);
     ccx.rust_try_fn().set(Some(rust_try));
@@ -959,7 +961,7 @@ macro_rules! require_simd {
 
 
     let tcx = bcx.tcx();
-    let sig = tcx.erase_late_bound_regions_and_normalize(callee_ty.fn_sig());
+    let sig = tcx.erase_late_bound_regions_and_normalize(&callee_ty.fn_sig());
     let arg_tys = sig.inputs();
 
     // every intrinsic takes a SIMD vector as its first argument
index 3033ae61d20c80ded2e4101210084e57e825e862..a3f4168e96f2a0c5e2bdc13d824a0846e34c7a5b 100644 (file)
 /// Extracts a method from a trait object's vtable, at the specified index.
 pub fn get_virtual_method<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
                                     llvtable: ValueRef,
-                                    vtable_index: usize)
-                                    -> ValueRef {
+                                    vtable_index: usize) -> ValueRef {
     // Load the data pointer from the object.
     debug!("get_virtual_method(vtable_index={}, llvtable={:?})",
            vtable_index, Value(llvtable));
 
-    bcx.load(bcx.gepi(llvtable, &[vtable_index + VTABLE_OFFSET]), None)
+    let ptr = bcx.load_nonnull(bcx.gepi(llvtable, &[vtable_index + VTABLE_OFFSET]), None);
+    // Vtable loads are invariant
+    bcx.set_invariant_load(ptr);
+    ptr
 }
 
 /// Generate a shim function that allows an object type like `SomeTrait` to
index 651d0066b12dd3d9f944eb21a4d00e631524bcd0..34d8c6500b9263d325bb3251cff8202a9904caf4 100644 (file)
@@ -21,7 +21,7 @@
 use common::{self, Funclet};
 use common::{C_bool, C_str_slice, C_struct, C_u32, C_undef};
 use consts;
-use machine::{llalign_of_min, llbitsize_of_real};
+use machine::llalign_of_min;
 use meth;
 use type_of::{self, align_of};
 use glue;
@@ -139,7 +139,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                 if switch_ty == bcx.tcx().types.bool {
                     let lltrue = llblock(self, targets[0]);
                     let llfalse = llblock(self, targets[1]);
-                    if let [ConstInt::Infer(0)] = values[..] {
+                    if let [ConstInt::U8(0)] = values[..] {
                         bcx.cond_br(discr.immediate(), llfalse, lltrue);
                     } else {
                         bcx.cond_br(discr.immediate(), lltrue, llfalse);
@@ -365,20 +365,21 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock,
                 // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
                 let callee = self.trans_operand(&bcx, func);
 
-                let (mut callee, abi, sig) = match callee.ty.sty {
-                    ty::TyFnDef(def_id, substs, f) => {
-                        (Callee::def(bcx.ccx, def_id, substs), f.abi, &f.sig)
+                let (mut callee, sig) = match callee.ty.sty {
+                    ty::TyFnDef(def_id, substs, sig) => {
+                        (Callee::def(bcx.ccx, def_id, substs), sig)
                     }
-                    ty::TyFnPtr(f) => {
+                    ty::TyFnPtr(sig) => {
                         (Callee {
                             data: Fn(callee.immediate()),
                             ty: callee.ty
-                        }, f.abi, &f.sig)
+                        }, sig)
                     }
                     _ => bug!("{} is not callable", callee.ty)
                 };
 
-                let sig = bcx.tcx().erase_late_bound_regions_and_normalize(sig);
+                let sig = bcx.tcx().erase_late_bound_regions_and_normalize(&sig);
+                let abi = sig.abi;
 
                 // Handle intrinsics old trans wants Expr's for, ourselves.
                 let intrinsic = match (&callee.ty.sty, &callee.data) {
@@ -868,24 +869,7 @@ fn trans_transmute(&mut self, bcx: &Builder<'a, 'tcx>,
     fn trans_transmute_into(&mut self, bcx: &Builder<'a, 'tcx>,
                             src: &mir::Operand<'tcx>,
                             dst: &LvalueRef<'tcx>) {
-        let mut val = self.trans_operand(bcx, src);
-        if let ty::TyFnDef(def_id, substs, _) = val.ty.sty {
-            let llouttype = type_of::type_of(bcx.ccx, dst.ty.to_ty(bcx.tcx()));
-            let out_type_size = llbitsize_of_real(bcx.ccx, llouttype);
-            if out_type_size != 0 {
-                // FIXME #19925 Remove this hack after a release cycle.
-                let f = Callee::def(bcx.ccx, def_id, substs);
-                let ty = match f.ty.sty {
-                    ty::TyFnDef(.., f) => bcx.tcx().mk_fn_ptr(f),
-                    _ => f.ty
-                };
-                val = OperandRef {
-                    val: Immediate(f.reify(bcx.ccx)),
-                    ty: ty
-                };
-            }
-        }
-
+        let val = self.trans_operand(bcx, src);
         let llty = type_of::type_of(bcx.ccx, val.ty);
         let cast_ptr = bcx.pointercast(dst.llval, llty.ptr_to());
         let in_type = val.ty;
index 7e17ae5f1d389ceeb15bd713976391c2b87b9c21..c524d8351e003c2d47fceee185aa9d5501f3929a 100644 (file)
@@ -20,7 +20,7 @@
 use rustc::mir::tcx::LvalueTy;
 use rustc::ty::{self, layout, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::cast::{CastTy, IntTy};
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Kind, Substs, Subst};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use {abi, adt, base, Disr, machine};
 use callee::Callee;
@@ -83,7 +83,6 @@ pub fn from_constint<'a>(ccx: &CrateContext<'a, 'tcx>, ci: &ConstInt)
                 let u = v.as_u64(ccx.tcx().sess.target.uint_type);
                 (C_integral(Type::int(ccx), u, false), tcx.types.usize)
             },
-            Infer(_) | InferSigned(_) => bug!("MIR must not use `{:?}`", ci),
         };
         Const { llval: llval, ty: ty }
     }
@@ -97,14 +96,13 @@ pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
         let val = match cv {
             ConstVal::Float(F32(v)) => C_floating_f64(v as f64, llty),
             ConstVal::Float(F64(v)) => C_floating_f64(v, llty),
-            ConstVal::Float(FInfer {..}) => bug!("MIR must not use `{:?}`", cv),
             ConstVal::Bool(v) => C_bool(ccx, v),
             ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
             ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
             ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
             ConstVal::Struct(_) | ConstVal::Tuple(_) |
             ConstVal::Array(..) | ConstVal::Repeat(..) |
-            ConstVal::Function(_) => {
+            ConstVal::Function(..) => {
                 bug!("MIR must not use `{:?}` (which refers to a local ID)", cv)
             }
             ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
@@ -249,7 +247,7 @@ fn new(ccx: &'a CrateContext<'a, 'tcx>,
     fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
                  instance: Instance<'tcx>,
                  args: IndexVec<mir::Local, Const<'tcx>>)
-                 -> Result<Const<'tcx>, ConstEvalErr> {
+                 -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
         let instance = instance.resolve_const(ccx.shared());
         let mir = ccx.tcx().item_mir(instance.def);
         MirConstContext::new(ccx, &mir, instance.substs, args).trans()
@@ -263,7 +261,7 @@ fn monomorphize<T>(&self, value: &T) -> T
                                          value)
     }
 
-    fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr> {
+    fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
         let tcx = self.ccx.tcx();
         let mut bb = mir::START_BLOCK;
 
@@ -325,7 +323,7 @@ fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr> {
                         };
 
                         let err = ConstEvalErr{ span: span, kind: err };
-                        report_const_eval_err(tcx, &err, span, "expression").emit();
+                        report_const_eval_err(tcx, &err, span, "expression");
                         failure = Err(err);
                     }
                     target
@@ -373,7 +371,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>, ConstEvalErr> {
+                    -> Result<ConstLvalue<'tcx>, ConstEvalErr<'tcx>> {
         let tcx = self.ccx.tcx();
 
         if let mir::Lvalue::Local(index) = *lvalue {
@@ -468,7 +466,7 @@ fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
     }
 
     fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span)
-                     -> Result<Const<'tcx>, ConstEvalErr> {
+                     -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
         debug!("const_operand({:?} @ {:?})", operand, span);
         let result = match *operand {
             mir::Operand::Consume(ref lvalue) => {
@@ -523,7 +521,7 @@ fn const_array(&self, array_ty: Ty<'tcx>, fields: &[ValueRef])
 
     fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
                     dest_ty: Ty<'tcx>, span: Span)
-                    -> Result<Const<'tcx>, ConstEvalErr> {
+                    -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
         let tcx = self.ccx.tcx();
         debug!("const_rvalue({:?}: {:?} @ {:?})", rvalue, dest_ty, span);
         let val = match *rvalue {
@@ -531,7 +529,7 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
 
             mir::Rvalue::Repeat(ref elem, ref count) => {
                 let elem = self.const_operand(elem, span)?;
-                let size = count.value.as_u64(tcx.sess.target.uint_type);
+                let size = count.as_u64(tcx.sess.target.uint_type);
                 let fields = vec![elem.llval; size as usize];
                 self.const_array(dest_ty, &fields)
             }
@@ -550,7 +548,7 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
                 failure?;
 
                 match *kind {
-                    mir::AggregateKind::Array => {
+                    mir::AggregateKind::Array(_) => {
                         self.const_array(dest_ty, &fields)
                     }
                     mir::AggregateKind::Adt(..) |
@@ -578,6 +576,28 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
                             }
                         }
                     }
+                    mir::CastKind::ClosureFnPointer => {
+                        match operand.ty.sty {
+                            ty::TyClosure(def_id, substs) => {
+                                // Get the def_id for FnOnce::call_once
+                                let fn_once = tcx.lang_items.fn_once_trait().unwrap();
+                                let call_once = tcx
+                                    .global_tcx().associated_items(fn_once)
+                                    .find(|it| it.kind == ty::AssociatedKind::Method)
+                                    .unwrap().def_id;
+                                // Now create its substs [Closure, Tuple]
+                                let input = tcx.closure_type(def_id)
+                                    .subst(tcx, substs.substs).input(0);
+                                let substs = tcx.mk_substs([operand.ty, input.skip_binder()]
+                                    .iter().cloned().map(Kind::from));
+                                Callee::def(self.ccx, call_once, substs)
+                                    .reify(self.ccx)
+                            }
+                            _ => {
+                                bug!("{} cannot be cast to a fn ptr", operand.ty)
+                            }
+                        }
+                    }
                     mir::CastKind::UnsafeFnPointer => {
                         // this is a no-op at the LLVM level
                         operand.llval
@@ -939,8 +959,11 @@ pub fn trans_constant(&mut self,
 }
 
 
-pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
-                                -> Result<ValueRef, ConstEvalErr> {
+pub fn trans_static_initializer<'a, 'tcx>(
+    ccx: &CrateContext<'a, 'tcx>,
+    def_id: DefId)
+    -> Result<ValueRef, ConstEvalErr<'tcx>>
+{
     let instance = Instance::mono(ccx.shared(), def_id);
     MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval)
 }
@@ -980,7 +1003,7 @@ fn trans_const<'a, 'tcx>(
         layout::CEnum { discr: d, min, max, .. } => {
             let discr = match *kind {
                 mir::AggregateKind::Adt(adt_def, _, _, _) => {
-                    Disr::from(adt_def.variants[variant_index].disr_val)
+                    Disr::for_variant(ccx.tcx(), adt_def, variant_index)
                 },
                 _ => Disr(0),
             };
index 9714fc4e4bdf02c11302a64dbf1ce00245daf862..6419f41f86b6d3d93174ee41f412c6c89ebca9ee 100644 (file)
@@ -28,7 +28,6 @@
 
 use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span};
 use syntax::symbol::keywords;
-use syntax::abi::Abi;
 
 use std::iter;
 
@@ -205,15 +204,14 @@ fn new_operand<'a>(ccx: &CrateContext<'a, 'tcx>,
 pub fn trans_mir<'a, 'tcx: 'a>(
     ccx: &'a CrateContext<'a, 'tcx>,
     llfn: ValueRef,
-    fn_ty: FnType,
     mir: &'a Mir<'tcx>,
     instance: Instance<'tcx>,
-    sig: &ty::FnSig<'tcx>,
-    abi: Abi,
+    sig: ty::FnSig<'tcx>,
 ) {
+    let fn_ty = FnType::new(ccx, sig, &[]);
     debug!("fn_ty: {:?}", fn_ty);
     let debug_context =
-        debuginfo::create_function_debug_context(ccx, instance, sig, abi, llfn, mir);
+        debuginfo::create_function_debug_context(ccx, instance, sig, llfn, mir);
     let bcx = Builder::new_block(ccx, llfn, "entry-block");
 
     let cleanup_kinds = analyze::cleanup_kinds(&mir);
index 7d4f542addbb1aa4494b5e3342deead7c262e6fe..b6af4e52e820b9062fe1641fdcb1ea4aa5220f3e 100644 (file)
@@ -12,6 +12,7 @@
 use rustc::ty::{self, Ty};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::layout::Layout;
+use rustc::ty::subst::{Kind, Subst};
 use rustc::mir::tcx::LvalueTy;
 use rustc::mir;
 use middle::lang_items::ExchangeMallocFnLangItem;
@@ -94,7 +95,7 @@ pub fn trans_rvalue(&mut self,
 
             mir::Rvalue::Repeat(ref elem, ref count) => {
                 let tr_elem = self.trans_operand(&bcx, elem);
-                let size = count.value.as_u64(bcx.tcx().sess.target.uint_type);
+                let size = count.as_u64(bcx.tcx().sess.target.uint_type);
                 let size = C_uint(bcx.ccx, size);
                 let base = base::get_dataptr(&bcx, dest.llval);
                 tvec::slice_for_each(&bcx, base, tr_elem.ty, size, |bcx, llslot| {
@@ -105,9 +106,9 @@ pub fn trans_rvalue(&mut self,
             mir::Rvalue::Aggregate(ref kind, ref operands) => {
                 match *kind {
                     mir::AggregateKind::Adt(adt_def, variant_index, substs, active_field_index) => {
-                        let disr = Disr::from(adt_def.variants[variant_index].disr_val);
+                        let disr = Disr::for_variant(bcx.tcx(), adt_def, variant_index);
                         let dest_ty = dest.ty.to_ty(bcx.tcx());
-                        adt::trans_set_discr(&bcx, dest_ty, dest.llval, Disr::from(disr));
+                        adt::trans_set_discr(&bcx, dest_ty, dest.llval, disr);
                         for (i, operand) in operands.iter().enumerate() {
                             let op = self.trans_operand(&bcx, operand);
                             // Do not generate stores and GEPis for zero-sized fields.
@@ -118,7 +119,7 @@ pub fn trans_rvalue(&mut self,
                                 val.ty = LvalueTy::Downcast {
                                     adt_def: adt_def,
                                     substs: self.monomorphize(&substs),
-                                    variant_index: disr.0 as usize,
+                                    variant_index: variant_index,
                                 };
                                 let (lldest_i, align) = val.trans_field_ptr(&bcx, field_index);
                                 self.store_operand(&bcx, lldest_i, align.to_align(), op);
@@ -190,6 +191,29 @@ pub fn trans_rvalue_operand(&mut self,
                             }
                         }
                     }
+                    mir::CastKind::ClosureFnPointer => {
+                        match operand.ty.sty {
+                            ty::TyClosure(def_id, substs) => {
+                                // Get the def_id for FnOnce::call_once
+                                let fn_once = bcx.tcx().lang_items.fn_once_trait().unwrap();
+                                let call_once = bcx.tcx()
+                                    .global_tcx().associated_items(fn_once)
+                                    .find(|it| it.kind == ty::AssociatedKind::Method)
+                                    .unwrap().def_id;
+                                // Now create its substs [Closure, Tuple]
+                                let input = bcx.tcx().closure_type(def_id)
+                                    .subst(bcx.tcx(), substs.substs).input(0);
+                                let substs = bcx.tcx().mk_substs([operand.ty, input.skip_binder()]
+                                    .iter().cloned().map(Kind::from));
+                                OperandValue::Immediate(
+                                    Callee::def(bcx.ccx, call_once, substs)
+                                        .reify(bcx.ccx))
+                            }
+                            _ => {
+                                bug!("{} cannot be cast to a fn ptr", operand.ty)
+                            }
+                        }
+                    }
                     mir::CastKind::UnsafeFnPointer => {
                         // this is a no-op at the LLVM level
                         operand.val
@@ -411,7 +435,7 @@ pub fn trans_rvalue_operand(&mut self,
             mir::Rvalue::Discriminant(ref lvalue) => {
                 let discr_lvalue = self.trans_lvalue(&bcx, lvalue);
                 let enum_ty = discr_lvalue.ty.to_ty(bcx.tcx());
-                let discr_ty = rvalue.ty(&*self.mir, bcx.tcx()).unwrap();
+                let discr_ty = rvalue.ty(&*self.mir, bcx.tcx());
                 let discr_type = type_of::immediate_type_of(bcx.ccx, discr_ty);
                 let discr = adt::trans_get_discr(&bcx, enum_ty, discr_lvalue.llval,
                                                   discr_lvalue.alignment, Some(discr_type), true);
index 04a6cb27501b3eab4000d02358d4d2103ca67948..d691fa6aadf2ed3d1579dededff68533508ab3e0 100644 (file)
@@ -199,11 +199,17 @@ fn predefine_drop_glue(ccx: &CrateContext<'a, 'tcx>,
         assert_eq!(dg.ty(), glue::get_drop_glue_type(ccx.shared(), dg.ty()));
         let t = dg.ty();
 
-        let sig = tcx.mk_fn_sig(iter::once(tcx.mk_mut_ptr(t)), tcx.mk_nil(), false);
+        let sig = tcx.mk_fn_sig(
+            iter::once(tcx.mk_mut_ptr(t)),
+            tcx.mk_nil(),
+            false,
+            hir::Unsafety::Normal,
+            Abi::Rust
+        );
 
         debug!("predefine_drop_glue: sig={}", sig);
 
-        let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
+        let fn_ty = FnType::new(ccx, sig, &[]);
         let llfnty = fn_ty.llvm_type(ccx);
 
         assert!(declare::get_defined_value(ccx, symbol_name).is_none());
@@ -457,12 +463,13 @@ pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String) {
                         output);
                 }
             },
-            ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
-            ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
-                if unsafety == hir::Unsafety::Unsafe {
+            ty::TyFnDef(.., sig) |
+            ty::TyFnPtr(sig) => {
+                if sig.unsafety() == hir::Unsafety::Unsafe {
                     output.push_str("unsafe ");
                 }
 
+                let abi = sig.abi();
                 if abi != ::abi::Abi::Rust {
                     output.push_str("extern \"");
                     output.push_str(abi.name());
@@ -471,7 +478,7 @@ pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String) {
 
                 output.push_str("fn(");
 
-                let sig = self.tcx.erase_late_bound_regions_and_normalize(sig);
+                let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig);
 
                 if !sig.inputs().is_empty() {
                     for &parameter_type in sig.inputs() {
index 87af3b6c5e1535bc4748624e367d36b73deb446b..a5722e6e520d0140df8f482b768f55517aa31fcb 100644 (file)
@@ -272,9 +272,9 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
       ty::TyStr | ty::TyDynamic(..) => Type::i8(cx),
 
       ty::TyFnDef(..) => Type::nil(cx),
-      ty::TyFnPtr(f) => {
-        let sig = cx.tcx().erase_late_bound_regions_and_normalize(&f.sig);
-        FnType::new(cx, f.abi, &sig, &[]).llvm_type(cx).ptr_to()
+      ty::TyFnPtr(sig) => {
+        let sig = cx.tcx().erase_late_bound_regions_and_normalize(&sig);
+        FnType::new(cx, sig, &[]).llvm_type(cx).ptr_to()
       }
       ty::TyTuple(ref tys, _) if tys.is_empty() => Type::nil(cx),
       ty::TyTuple(..) => {
index ab1897101eb6ffe683c7b1d69f4be3a956d8b147..577fe31eab02abff192e3125157610e9a95d5352 100644 (file)
 //! Conversion from AST representation of types to the ty.rs
 //! representation.  The main routine here is `ast_ty_to_ty()`: each use
 //! is parameterized by an instance of `AstConv`.
-//!
-//! The parameterization of `ast_ty_to_ty()` is because it behaves
-//! somewhat differently during the collect and check phases,
-//! particularly with respect to looking up the types of top-level
-//! items.  In the collect phase, the crate context is used as the
-//! `AstConv` instance; in this phase, the `get_item_type()`
-//! function triggers a recursive call to `type_of_item()`
-//! (note that `ast_ty_to_ty()` will detect recursive types and report
-//! an error).  In the check phase, when the FnCtxt is used as the
-//! `AstConv`, `get_item_type()` just looks up the item type in
-//! `tcx.types` (using `TyCtxt::item_type`).
 
 use rustc_const_eval::eval_length;
 use rustc_data_structures::accumulate_vec::AccumulateVec;
@@ -42,7 +31,7 @@
 use std::iter;
 use syntax::{abi, ast};
 use syntax::feature_gate::{GateIssue, emit_feature_err};
-use syntax::symbol::{Symbol, keywords};
+use syntax::symbol::Symbol;
 use syntax_pos::Span;
 
 pub trait AstConv<'gcx, 'tcx> {
@@ -51,28 +40,10 @@ pub trait AstConv<'gcx, 'tcx> {
     /// A cache used for the result of `ast_ty_to_ty_cache`
     fn ast_ty_to_ty_cache(&self) -> &RefCell<NodeMap<Ty<'tcx>>>;
 
-    /// Returns the generic type and lifetime parameters for an item.
-    fn get_generics(&self, span: Span, id: DefId)
-                    -> Result<&'tcx ty::Generics<'tcx>, ErrorReported>;
-
-    /// Identify the type for an item, like a type alias, fn, or struct.
-    fn get_item_type(&self, span: Span, id: DefId) -> Result<Ty<'tcx>, ErrorReported>;
-
-    /// Returns the `TraitDef` for a given trait. This allows you to
-    /// figure out the set of type parameters defined on the trait.
-    fn get_trait_def(&self, span: Span, id: DefId)
-                     -> Result<&'tcx ty::TraitDef, ErrorReported>;
-
-    /// Ensure that the super-predicates for the trait with the given
-    /// id are available and also for the transitive set of
-    /// super-predicates.
-    fn ensure_super_predicates(&self, span: Span, id: DefId)
-                               -> Result<(), ErrorReported>;
-
     /// Returns the set of bounds in scope for the type parameter with
     /// the given id.
-    fn get_type_parameter_bounds(&self, span: Span, def_id: ast::NodeId)
-                                 -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>;
+    fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
+                                 -> ty::GenericPredicates<'tcx>;
 
     /// Return an (optional) substitution to convert bound type parameters that
     /// are in scope into free ones. This function should only return Some
@@ -89,7 +60,7 @@ fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>)
 
     /// Same as ty_infer, but with a known type parameter definition.
     fn ty_infer_for_def(&self,
-                        _def: &ty::TypeParameterDef<'tcx>,
+                        _def: &ty::TypeParameterDef,
                         _substs: &[Kind<'tcx>],
                         span: Span) -> Ty<'tcx> {
         self.ty_infer(span)
@@ -218,7 +189,7 @@ pub fn ast_path_substs_for_ty(&self,
                                             &item_segment.parameters,
                                             None);
 
-        assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span));
+        assoc_bindings.first().map(|b| self.prohibit_projection(b.span));
 
         substs
     }
@@ -251,14 +222,7 @@ fn create_substs_for_ast_path(&self,
         // If the type is parameterized by this region, then replace this
         // region with the current anon region binding (in other words,
         // whatever & would get replaced with).
-        let decl_generics = match self.get_generics(span, def_id) {
-            Ok(generics) => generics,
-            Err(ErrorReported) => {
-                // No convenient way to recover from a cycle here. Just bail. Sorry!
-                self.tcx().sess.abort_if_errors();
-                bug!("ErrorReported returned, but no errors reports?")
-            }
-        };
+        let decl_generics = tcx.item_generics(def_id);
         let expected_num_region_params = decl_generics.regions.len();
         let supplied_num_region_params = lifetimes.len();
         if expected_num_region_params != supplied_num_region_params {
@@ -277,9 +241,9 @@ fn create_substs_for_ast_path(&self,
         }
 
         let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF);
-        let default_needs_object_self = |p: &ty::TypeParameterDef<'tcx>| {
-            if let Some(ref default) = p.default {
-                if is_object && default.has_self_ty() {
+        let default_needs_object_self = |p: &ty::TypeParameterDef| {
+            if is_object && p.has_default {
+                if ty::queries::ty::get(tcx, span, p.def_id).has_self_ty() {
                     // There is no suitable inference default for a type parameter
                     // that references self, in an object type.
                     return true;
@@ -327,7 +291,7 @@ fn create_substs_for_ast_path(&self,
                     self.ty_infer(span)
                 };
                 ty_var
-            } else if let Some(default) = def.default {
+            } else if def.has_default {
                 // No type parameter provided, but a default exists.
 
                 // If we are converting an object type, then the
@@ -346,7 +310,8 @@ fn create_substs_for_ast_path(&self,
                     tcx.types.err
                 } else {
                     // This is a default type parameter.
-                    default.subst_spanned(tcx, substs, Some(span))
+                    ty::queries::ty::get(tcx, span, def.def_id)
+                        .subst_spanned(tcx, substs, Some(span))
                 }
             } else {
                 // We've already errored above about the mismatch.
@@ -481,7 +446,7 @@ fn ast_path_to_mono_trait_ref(&self,
                                                  trait_def_id,
                                                  self_ty,
                                                  trait_segment);
-        assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span));
+        assoc_bindings.first().map(|b| self.prohibit_projection(b.span));
         ty::TraitRef::new(trait_def_id, substs)
     }
 
@@ -495,14 +460,7 @@ fn create_substs_for_ast_trait_ref(&self,
         debug!("create_substs_for_ast_trait_ref(trait_segment={:?})",
                trait_segment);
 
-        let trait_def = match self.get_trait_def(span, trait_def_id) {
-            Ok(trait_def) => trait_def,
-            Err(ErrorReported) => {
-                // No convenient way to recover from a cycle here. Just bail. Sorry!
-                self.tcx().sess.abort_if_errors();
-                bug!("ErrorReported returned, but no errors reports?")
-            }
-        };
+        let trait_def = self.tcx().lookup_trait_def(trait_def_id);
 
         match trait_segment.parameters {
             hir::AngleBracketedParameters(_) => {
@@ -615,8 +573,6 @@ fn ast_type_binding_to_poly_projection_predicate(
 
         // Otherwise, we have to walk through the supertraits to find
         // those that do.
-        self.ensure_super_predicates(binding.span, trait_ref.def_id())?;
-
         let candidates =
             traits::supertraits(tcx, trait_ref.clone())
             .filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name));
@@ -643,16 +599,8 @@ fn ast_path_to_ty(&self,
         item_segment: &hir::PathSegment)
         -> Ty<'tcx>
     {
-        let tcx = self.tcx();
-        let decl_ty = match self.get_item_type(span, did) {
-            Ok(ty) => ty,
-            Err(ErrorReported) => {
-                return tcx.types.err;
-            }
-        };
-
         let substs = self.ast_path_substs_for_ty(span, did, item_segment);
-        decl_ty.subst(self.tcx(), substs)
+        ty::queries::ty::get(self.tcx(), span, did).subst(self.tcx(), substs)
     }
 
     /// Transform a PolyTraitRef into a PolyExistentialTraitRef by
@@ -709,11 +657,6 @@ fn conv_object_ty_poly_trait_ref(&self,
             })
         });
 
-        // ensure the super predicates and stop if we encountered an error
-        if self.ensure_super_predicates(span, principal.def_id()).is_err() {
-            return tcx.types.err;
-        }
-
         // check that there are no gross object safety violations,
         // most importantly, that the supertraits don't contain Self,
         // to avoid ICE-s.
@@ -798,30 +741,19 @@ fn report_ambiguous_associated_type(&self,
     }
 
     // Search for a bound on a type parameter which includes the associated item
-    // given by assoc_name. ty_param_node_id is the node id for the type parameter
-    // (which might be `Self`, but only if it is the `Self` of a trait, not an
-    // impl). This function will fail if there are no suitable bounds or there is
+    // given by `assoc_name`. `ty_param_def_id` is the `DefId` for the type parameter
+    // This function will fail if there are no suitable bounds or there is
     // any ambiguity.
     fn find_bound_for_assoc_item(&self,
-                                 ty_param_node_id: ast::NodeId,
-                                 ty_param_name: ast::Name,
+                                 ty_param_def_id: DefId,
                                  assoc_name: ast::Name,
                                  span: Span)
                                  -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
     {
         let tcx = self.tcx();
 
-        let bounds = match self.get_type_parameter_bounds(span, ty_param_node_id) {
-            Ok(v) => v,
-            Err(ErrorReported) => {
-                return Err(ErrorReported);
-            }
-        };
-
-        // Ensure the super predicates and stop if we encountered an error.
-        if bounds.iter().any(|b| self.ensure_super_predicates(span, b.def_id()).is_err()) {
-            return Err(ErrorReported);
-        }
+        let bounds: Vec<_> = self.get_type_parameter_bounds(span, ty_param_def_id)
+            .predicates.into_iter().filter_map(|p| p.to_opt_poly_trait_ref()).collect();
 
         // Check that there is exactly one way to find an associated type with the
         // correct name.
@@ -829,8 +761,10 @@ fn find_bound_for_assoc_item(&self,
             traits::transitive_bounds(tcx, &bounds)
             .filter(|b| self.trait_defines_associated_type_named(b.def_id(), assoc_name));
 
+        let param_node_id = tcx.hir.as_local_node_id(ty_param_def_id).unwrap();
+        let param_name = tcx.hir.ty_param_name(param_node_id);
         self.one_bound_for_assoc_type(suitable_bounds,
-                                      &ty_param_name.as_str(),
+                                      &param_name.as_str(),
                                       &assoc_name.as_str(),
                                       span)
     }
@@ -910,7 +844,7 @@ pub fn associated_path_def_to_ty(&self,
 
         debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name);
 
-        tcx.prohibit_type_params(slice::ref_slice(item_segment));
+        self.prohibit_type_params(slice::ref_slice(item_segment));
 
         // Find the type of the associated item, and the trait where the associated
         // item is declared.
@@ -918,29 +852,20 @@ pub fn associated_path_def_to_ty(&self,
             (_, Def::SelfTy(Some(_), Some(impl_def_id))) => {
                 // `Self` in an impl of a trait - we have a concrete self type and a
                 // trait reference.
-                // FIXME: Self type is not always computed when we are here because type parameter
-                // bounds may affect Self type and have to be converted before it.
-                let trait_ref = if impl_def_id.is_local() {
-                    tcx.impl_trait_refs.borrow().get(&impl_def_id).cloned().and_then(|x| x)
-                } else {
-                    tcx.impl_trait_ref(impl_def_id)
-                };
-                let trait_ref = if let Some(trait_ref) = trait_ref {
-                    trait_ref
-                } else {
-                    tcx.sess.span_err(span, "`Self` type is used before it's determined");
-                    return (tcx.types.err, Def::Err);
+                let trait_ref = match tcx.impl_trait_ref(impl_def_id) {
+                    Some(trait_ref) => trait_ref,
+                    None => {
+                        // A cycle error occurred, most likely.
+                        return (tcx.types.err, Def::Err);
+                    }
                 };
+
                 let trait_ref = if let Some(free_substs) = self.get_free_substs() {
                     trait_ref.subst(tcx, free_substs)
                 } else {
                     trait_ref
                 };
 
-                if self.ensure_super_predicates(span, trait_ref.def_id).is_err() {
-                    return (tcx.types.err, Def::Err);
-                }
-
                 let candidates =
                     traits::supertraits(tcx, ty::Binder(trait_ref))
                     .filter(|r| self.trait_defines_associated_type_named(r.def_id(),
@@ -954,23 +879,9 @@ pub fn associated_path_def_to_ty(&self,
                     Err(ErrorReported) => return (tcx.types.err, Def::Err),
                 }
             }
-            (&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) => {
-                let trait_node_id = tcx.hir.as_local_node_id(trait_did).unwrap();
-                match self.find_bound_for_assoc_item(trait_node_id,
-                                                     keywords::SelfType.name(),
-                                                     assoc_name,
-                                                     span) {
-                    Ok(bound) => bound,
-                    Err(ErrorReported) => return (tcx.types.err, Def::Err),
-                }
-            }
+            (&ty::TyParam(_), Def::SelfTy(Some(param_did), None)) |
             (&ty::TyParam(_), Def::TyParam(param_did)) => {
-                let param_node_id = tcx.hir.as_local_node_id(param_did).unwrap();
-                let param_name = tcx.type_parameter_def(param_node_id).name;
-                match self.find_bound_for_assoc_item(param_node_id,
-                                                     param_name,
-                                                     assoc_name,
-                                                     span) {
+                match self.find_bound_for_assoc_item(param_did, assoc_name, span) {
                     Ok(bound) => bound,
                     Err(ErrorReported) => return (tcx.types.err, Def::Err),
                 }
@@ -1006,7 +917,7 @@ fn qpath_to_ty(&self,
     {
         let tcx = self.tcx();
 
-        tcx.prohibit_type_params(slice::ref_slice(item_segment));
+        self.prohibit_type_params(slice::ref_slice(item_segment));
 
         let self_ty = if let Some(ty) = opt_self_ty {
             ty
@@ -1031,6 +942,36 @@ fn qpath_to_ty(&self,
         self.projected_ty(span, trait_ref, item_segment.name)
     }
 
+    pub fn prohibit_type_params(&self, segments: &[hir::PathSegment]) {
+        for segment in segments {
+            for typ in segment.parameters.types() {
+                struct_span_err!(self.tcx().sess, typ.span, E0109,
+                                 "type parameters are not allowed on this type")
+                    .span_label(typ.span, &format!("type parameter not allowed"))
+                    .emit();
+                break;
+            }
+            for lifetime in segment.parameters.lifetimes() {
+                struct_span_err!(self.tcx().sess, lifetime.span, E0110,
+                                 "lifetime parameters are not allowed on this type")
+                    .span_label(lifetime.span,
+                                &format!("lifetime parameter not allowed on this type"))
+                    .emit();
+                break;
+            }
+            for binding in segment.parameters.bindings() {
+                self.prohibit_projection(binding.span);
+                break;
+            }
+        }
+    }
+
+    pub fn prohibit_projection(&self, span: Span) {
+        let mut err = struct_span_err!(self.tcx().sess, span, E0229,
+                                       "associated type bindings are not allowed here");
+        err.span_label(span, &format!("associate type not allowed here")).emit();
+    }
+
     // Check a type Path and convert it to a Ty.
     pub fn def_to_ty(&self,
                      opt_self_ty: Option<Ty<'tcx>>,
@@ -1046,71 +987,50 @@ pub fn def_to_ty(&self,
         match path.def {
             Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => {
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
+                self.prohibit_type_params(path.segments.split_last().unwrap().1);
                 self.ast_path_to_ty(span, did, path.segments.last().unwrap())
             }
             Def::Variant(did) if permit_variants => {
                 // Convert "variant type" as if it were a real type.
                 // The resulting `Ty` is type of the variant's enum for now.
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
+                self.prohibit_type_params(path.segments.split_last().unwrap().1);
                 self.ast_path_to_ty(span,
                                     tcx.parent_def_id(did).unwrap(),
                                     path.segments.last().unwrap())
             }
             Def::TyParam(did) => {
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(&path.segments);
+                self.prohibit_type_params(&path.segments);
 
                 let node_id = tcx.hir.as_local_node_id(did).unwrap();
-                let param = tcx.ty_param_defs.borrow().get(&node_id)
-                               .map(ty::ParamTy::for_def);
-                if let Some(p) = param {
-                    p.to_ty(tcx)
-                } else {
-                    // Only while computing defaults of earlier type
-                    // parameters can a type parameter be missing its def.
-                    struct_span_err!(tcx.sess, span, E0128,
-                                     "type parameters with a default cannot use \
-                                      forward declared identifiers")
-                        .span_label(span, &format!("defaulted type parameters \
-                                                    cannot be forward declared"))
-                        .emit();
-                    tcx.types.err
-                }
+                let item_id = tcx.hir.get_parent_node(node_id);
+                let item_def_id = tcx.hir.local_def_id(item_id);
+                let generics = tcx.item_generics(item_def_id);
+                let index = generics.type_param_to_index[&tcx.hir.local_def_id(node_id).index];
+                tcx.mk_param(index, tcx.hir.name(node_id))
             }
             Def::SelfTy(_, Some(def_id)) => {
                 // Self in impl (we know the concrete type).
 
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(&path.segments);
+                self.prohibit_type_params(&path.segments);
 
-                // FIXME: Self type is not always computed when we are here because type parameter
-                // bounds may affect Self type and have to be converted before it.
-                let ty = if def_id.is_local() {
-                    tcx.item_types.borrow().get(&def_id).cloned()
+                let ty = ty::queries::ty::get(tcx, span, def_id);
+                if let Some(free_substs) = self.get_free_substs() {
+                    ty.subst(tcx, free_substs)
                 } else {
-                    Some(tcx.item_type(def_id))
-                };
-                if let Some(ty) = ty {
-                    if let Some(free_substs) = self.get_free_substs() {
-                        ty.subst(tcx, free_substs)
-                    } else {
-                        ty
-                    }
-                } else {
-                    tcx.sess.span_err(span, "`Self` type is used before it's determined");
-                    tcx.types.err
+                    ty
                 }
             }
             Def::SelfTy(Some(_), None) => {
                 // Self in trait.
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(&path.segments);
+                self.prohibit_type_params(&path.segments);
                 tcx.mk_self_type()
             }
             Def::AssociatedTy(def_id) => {
-                tcx.prohibit_type_params(&path.segments[..path.segments.len()-2]);
+                self.prohibit_type_params(&path.segments[..path.segments.len()-2]);
                 let trait_did = tcx.parent_def_id(def_id).unwrap();
                 self.qpath_to_ty(span,
                                  opt_self_ty,
@@ -1120,7 +1040,15 @@ pub fn def_to_ty(&self,
             }
             Def::PrimTy(prim_ty) => {
                 assert_eq!(opt_self_ty, None);
-                tcx.prim_ty_to_ty(&path.segments, prim_ty)
+                self.prohibit_type_params(&path.segments);
+                match prim_ty {
+                    hir::TyBool => tcx.types.bool,
+                    hir::TyChar => tcx.types.char,
+                    hir::TyInt(it) => tcx.mk_mach_int(it),
+                    hir::TyUint(uit) => tcx.mk_mach_uint(uit),
+                    hir::TyFloat(ft) => tcx.mk_mach_float(ft),
+                    hir::TyStr => tcx.mk_str()
+                }
             }
             Def::Err => {
                 self.set_tainted_by_errors();
@@ -1183,10 +1111,10 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
                 // warning then. (Once we fix #32330, the regions we are
                 // checking for here would be considered early bound
                 // anyway.)
-                let inputs = bare_fn_ty.sig.inputs();
+                let inputs = bare_fn_ty.inputs();
                 let late_bound_in_args = tcx.collect_constrained_late_bound_regions(
                     &inputs.map_bound(|i| i.to_owned()));
-                let output = bare_fn_ty.sig.output();
+                let output = bare_fn_ty.output();
                 let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output);
                 for br in late_bound_in_ret.difference(&late_bound_in_args) {
                     let br_name = match *br {
@@ -1211,9 +1139,7 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
             hir::TyTraitObject(ref bounds, ref lifetime) => {
                 self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
             }
-            hir::TyImplTrait(ref bounds) => {
-                use collect::{compute_bounds, SizedByDefault};
-
+            hir::TyImplTrait(_) => {
                 // Figure out if we can allow an `impl Trait` here, by walking up
                 // to a `fn` or inherent `impl` method, going only through `Ty`
                 // or `TraitRef` nodes (as nothing else should be in types) and
@@ -1253,24 +1179,7 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
                 // Create the anonymized type.
                 if allow {
                     let def_id = tcx.hir.local_def_id(ast_ty.id);
-                    if let Err(ErrorReported) = self.get_generics(ast_ty.span, def_id) {
-                        return tcx.types.err;
-                    }
-                    let substs = Substs::identity_for_item(tcx, def_id);
-                    let ty = tcx.mk_anon(tcx.hir.local_def_id(ast_ty.id), substs);
-
-                    // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
-                    let bounds = compute_bounds(self, ty, bounds,
-                                                SizedByDefault::Yes,
-                                                ast_ty.span);
-                    let predicates = bounds.predicates(tcx, ty);
-                    let predicates = tcx.lift_to_global(&predicates).unwrap();
-                    tcx.predicates.borrow_mut().insert(def_id, ty::GenericPredicates {
-                        parent: None,
-                        predicates: predicates
-                    });
-
-                    ty
+                    tcx.mk_anon(def_id, Substs::identity_for_item(tcx, def_id))
                 } else {
                     span_err!(tcx.sess, ast_ty.span, E0562,
                               "`impl Trait` not allowed outside of function \
@@ -1341,7 +1250,7 @@ pub fn ty_of_fn(&self,
                     unsafety: hir::Unsafety,
                     abi: abi::Abi,
                     decl: &hir::FnDecl)
-                    -> &'tcx ty::BareFnTy<'tcx> {
+                    -> ty::PolyFnSig<'tcx> {
         debug!("ty_of_fn");
 
         let input_tys: Vec<Ty> =
@@ -1354,15 +1263,13 @@ pub fn ty_of_fn(&self,
 
         debug!("ty_of_fn: output_ty={:?}", output_ty);
 
-        self.tcx().mk_bare_fn(ty::BareFnTy {
-            unsafety: unsafety,
-            abi: abi,
-            sig: ty::Binder(self.tcx().mk_fn_sig(
-                input_tys.into_iter(),
-                output_ty,
-                decl.variadic
-            )),
-        })
+        ty::Binder(self.tcx().mk_fn_sig(
+            input_tys.into_iter(),
+            output_ty,
+            decl.variadic,
+            unsafety,
+            abi
+        ))
     }
 
     pub fn ty_of_closure(&self,
@@ -1370,7 +1277,7 @@ pub fn ty_of_closure(&self,
         decl: &hir::FnDecl,
         abi: abi::Abi,
         expected_sig: Option<ty::FnSig<'tcx>>)
-        -> ty::ClosureTy<'tcx>
+        -> ty::PolyFnSig<'tcx>
     {
         debug!("ty_of_closure(expected_sig={:?})",
                expected_sig);
@@ -1407,11 +1314,13 @@ pub fn ty_of_closure(&self,
 
         debug!("ty_of_closure: output_ty={:?}", output_ty);
 
-        ty::ClosureTy {
-            unsafety: unsafety,
-            abi: abi,
-            sig: ty::Binder(self.tcx().mk_fn_sig(input_tys, output_ty, decl.variadic)),
-        }
+        ty::Binder(self.tcx().mk_fn_sig(
+            input_tys,
+            output_ty,
+            decl.variadic,
+            unsafety,
+            abi
+        ))
     }
 
     /// Given the bounds on an object, determines what single region bound (if any) we can
@@ -1429,12 +1338,6 @@ fn compute_object_lifetime_bound(&self,
         debug!("compute_opt_region_bound(existential_predicates={:?})",
                existential_predicates);
 
-        if let Some(principal) = existential_predicates.principal() {
-            if let Err(ErrorReported) = self.ensure_super_predicates(span, principal.def_id()) {
-                return Some(tcx.mk_region(ty::ReStatic));
-            }
-        }
-
         // No explicit region bound specified. Therefore, examine trait
         // bounds and see if we can derive region bounds from those.
         let derived_region_bounds =
@@ -1510,7 +1413,7 @@ fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize,
                              ty_param_defs: &[ty::TypeParameterDef]) {
     let accepted = ty_param_defs.len();
-    let required = ty_param_defs.iter().take_while(|x| x.default.is_none()) .count();
+    let required = ty_param_defs.iter().take_while(|x| !x.has_default).count();
     if supplied < required {
         let expected = if required < accepted {
             "expected at least"
index 3a980c8e7642bae14c380ddad7e1f0f1bf1bb540..4b88f5acf42da2415ea3442fec3c06440ef307b2 100644 (file)
 
 use super::{DeferredCallResolution, Expectation, FnCtxt, TupleArgumentsFlag};
 
-use CrateCtxt;
 use hir::def::Def;
 use hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::{infer, traits};
-use rustc::ty::{self, LvaluePreference, Ty};
+use rustc::ty::{self, TyCtxt, LvaluePreference, Ty};
+use rustc::ty::subst::Subst;
+use syntax::abi;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
 
 /// Check that it is legal to call methods of the trait corresponding
 /// to `trait_id` (this only cares about the trait, not the specific
 /// method that is called)
-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")
+pub fn check_legal_trait_for_method_call(tcx: TyCtxt, span: Span, trait_id: DefId) {
+    if tcx.lang_items.drop_trait() == Some(trait_id) {
+        struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method")
             .span_label(span, &format!("explicit destructor calls not allowed"))
             .emit();
     }
@@ -113,10 +111,10 @@ fn try_overloaded_call_step(&self,
                 // haven't yet decided on whether the closure is fn vs
                 // fnmut vs fnonce. If so, we have to defer further processing.
                 if self.closure_kind(def_id).is_none() {
-                    let closure_ty = self.closure_type(def_idsubsts);
+                    let closure_ty = self.closure_type(def_id).subst(self.tcx, substs.substs);
                     let fn_sig = self.replace_late_bound_regions_with_fresh_var(call_expr.span,
                                                                    infer::FnCall,
-                                                                   &closure_ty.sig)
+                                                                   &closure_ty)
                         .0;
                     self.record_deferred_call_resolution(def_id,
                                                          Box::new(CallResolution {
@@ -190,13 +188,11 @@ fn confirm_builtin_call(&self,
                             arg_exprs: &'gcx [hir::Expr],
                             expected: Expectation<'tcx>)
                             -> Ty<'tcx> {
-        let error_fn_sig;
-
         let (fn_sig, def_span) = match callee_ty.sty {
-            ty::TyFnDef(def_id, .., &ty::BareFnTy {ref sig, ..}) => {
+            ty::TyFnDef(def_id, .., sig) => {
                 (sig, self.tcx.hir.span_if_local(def_id))
             }
-            ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => (sig, None),
+            ty::TyFnPtr(sig) => (sig, None),
             ref t => {
                 let mut unit_variant = None;
                 if let &ty::TyAdt(adt_def, ..) = t {
@@ -236,13 +232,13 @@ fn confirm_builtin_call(&self,
                 // This is the "default" function signature, used in case of error.
                 // In that case, we check each argument against "error" in order to
                 // set up all the node type bindings.
-                error_fn_sig = ty::Binder(self.tcx.mk_fn_sig(
+                (ty::Binder(self.tcx.mk_fn_sig(
                     self.err_args(arg_exprs.len()).into_iter(),
                     self.tcx.types.err,
                     false,
-                ));
-
-                (&error_fn_sig, None)
+                    hir::Unsafety::Normal,
+                    abi::Abi::Rust
+                )), None)
             }
         };
 
@@ -252,7 +248,7 @@ fn confirm_builtin_call(&self,
         // previously appeared within a `Binder<>` and hence would not
         // have been normalized before.
         let fn_sig =
-            self.replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, fn_sig)
+            self.replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, &fn_sig)
                 .0;
         let fn_sig = self.normalize_associated_types_in(call_expr.span, &fn_sig);
 
@@ -359,7 +355,7 @@ fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
                 // (This always bites me, should find a way to
                 // refactor it.)
                 let method_sig = fcx.tcx
-                    .no_late_bound_regions(method_callee.ty.fn_sig())
+                    .no_late_bound_regions(&method_callee.ty.fn_sig())
                     .unwrap();
 
                 debug!("attempt_resolution: method_callee={:?}", method_callee);
index 7979edbf5e27a1c7c78536a1e8272b6662680db0..51fbc5aab6cd1510a87654b0f349967df668e050 100644 (file)
@@ -55,11 +55,11 @@ fn check_closure(&self,
                expected_sig);
 
         let expr_def_id = self.tcx.hir.local_def_id(expr.id);
-        let mut fn_ty = AstConv::ty_of_closure(self,
-                                               hir::Unsafety::Normal,
-                                               decl,
-                                               Abi::RustCall,
-                                               expected_sig);
+        let sig = AstConv::ty_of_closure(self,
+                                         hir::Unsafety::Normal,
+                                         decl,
+                                         Abi::RustCall,
+                                         expected_sig);
 
         // Create type variables (for now) to represent the transformed
         // types of upvars. These will be unified during the upvar
@@ -74,32 +74,28 @@ fn check_closure(&self,
         debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);
 
         let extent = self.tcx.region_maps.call_site_extent(expr.id, body.value.id);
-        let fn_sig = self.tcx.liberate_late_bound_regions(extent, &fn_ty.sig);
+        let fn_sig = self.tcx.liberate_late_bound_regions(extent, &sig);
         let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
                                                             body.value.id, &fn_sig);
 
-        check_fn(self,
-                 hir::Unsafety::Normal,
-                 expr.id,
-                 &fn_sig,
-                 decl,
-                 expr.id,
-                 body);
+        check_fn(self, fn_sig, decl, expr.id, body);
 
         // Tuple up the arguments and insert the resulting function type into
         // the `closures` table.
-        fn_ty.sig.0 = self.tcx.mk_fn_sig(
-            iter::once(self.tcx.intern_tup(fn_ty.sig.skip_binder().inputs(), false)),
-            fn_ty.sig.skip_binder().output(),
-            fn_ty.sig.variadic()
-        );
+        let sig = sig.map_bound(|sig| self.tcx.mk_fn_sig(
+            iter::once(self.tcx.intern_tup(sig.inputs(), false)),
+            sig.output(),
+            sig.variadic,
+            sig.unsafety,
+            sig.abi
+        ));
 
         debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
                expr_def_id,
-               fn_ty.sig,
+               sig,
                opt_kind);
 
-        self.tables.borrow_mut().closure_tys.insert(expr.id, fn_ty);
+        self.tables.borrow_mut().closure_tys.insert(expr.id, sig);
         match opt_kind {
             Some(kind) => {
                 self.tables.borrow_mut().closure_kinds.insert(expr.id, kind);
@@ -228,7 +224,13 @@ fn deduce_sig_from_projection(&self,
         let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
         debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);
 
-        let fn_sig = self.tcx.mk_fn_sig(input_tys.cloned(), ret_param_ty, false);
+        let fn_sig = self.tcx.mk_fn_sig(
+            input_tys.cloned(),
+            ret_param_ty,
+            false,
+            hir::Unsafety::Normal,
+            Abi::Rust
+        );
         debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
 
         Some(fn_sig)
index 718c273785ae91f84c94d7e1a035d5a25db9cec8..53759cc115d1cb69039a9473cdb2fc04c5b1446b 100644 (file)
 use check::FnCtxt;
 
 use rustc::hir;
+use rustc::hir::def_id::DefId;
 use rustc::infer::{Coercion, InferOk, TypeTrace};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
-use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty};
+use rustc::ty::{self, LvaluePreference, TypeAndMut,
+                Ty, ClosureSubsts};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::error::TypeError;
 use rustc::ty::relate::RelateResult;
+use rustc::ty::subst::Subst;
+use syntax::abi;
+use syntax::feature_gate;
 use util::common::indent;
 
 use std::cell::RefCell;
@@ -196,6 +201,11 @@ fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<
                 // unsafe qualifier.
                 self.coerce_from_fn_pointer(a, a_f, b)
             }
+            ty::TyClosure(def_id_a, substs_a) => {
+                // Non-capturing closures are coercible to
+                // function pointers
+                self.coerce_closure_to_fn(a, def_id_a, substs_a, b)
+            }
             _ => {
                 // Otherwise, just use unification rules.
                 self.unify_and_identity(a, b)
@@ -498,11 +508,11 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc
 
     fn coerce_from_safe_fn(&self,
                            a: Ty<'tcx>,
-                           fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
+                           fn_ty_a: ty::PolyFnSig<'tcx>,
                            b: Ty<'tcx>)
                            -> CoerceResult<'tcx> {
         if let ty::TyFnPtr(fn_ty_b) = b.sty {
-            match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
+            match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) {
                 (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
                     let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
                     return self.unify_and_identity(unsafe_a, b)
@@ -516,7 +526,7 @@ fn coerce_from_safe_fn(&self,
 
     fn coerce_from_fn_pointer(&self,
                               a: Ty<'tcx>,
-                              fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
+                              fn_ty_a: ty::PolyFnSig<'tcx>,
                               b: Ty<'tcx>)
                               -> CoerceResult<'tcx> {
         //! Attempts to coerce from the type of a Rust function item
@@ -531,7 +541,7 @@ fn coerce_from_fn_pointer(&self,
 
     fn coerce_from_fn_item(&self,
                            a: Ty<'tcx>,
-                           fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
+                           fn_ty_a: ty::PolyFnSig<'tcx>,
                            b: Ty<'tcx>)
                            -> CoerceResult<'tcx> {
         //! Attempts to coerce from the type of a Rust function item
@@ -551,6 +561,59 @@ fn coerce_from_fn_item(&self,
         }
     }
 
+    fn coerce_closure_to_fn(&self,
+                           a: Ty<'tcx>,
+                           def_id_a: DefId,
+                           substs_a: ClosureSubsts<'tcx>,
+                           b: Ty<'tcx>)
+                           -> CoerceResult<'tcx> {
+        //! Attempts to coerce from the type of a non-capturing closure
+        //! into a function pointer.
+        //!
+
+        let b = self.shallow_resolve(b);
+
+        let node_id_a = self.tcx.hir.as_local_node_id(def_id_a).unwrap();
+        match b.sty {
+            ty::TyFnPtr(_) if self.tcx.with_freevars(node_id_a, |v| v.is_empty()) => {
+                if !self.tcx.sess.features.borrow().closure_to_fn_coercion {
+                    feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
+                                                   "closure_to_fn_coercion",
+                                                   self.cause.span,
+                                                   feature_gate::GateIssue::Language,
+                                                   feature_gate::CLOSURE_TO_FN_COERCION);
+                    return self.unify_and_identity(a, b);
+                }
+                // We coerce the closure, which has fn type
+                //     `extern "rust-call" fn((arg0,arg1,...)) -> _`
+                // to
+                //     `fn(arg0,arg1,...) -> _`
+                let sig = self.closure_type(def_id_a).subst(self.tcx, substs_a.substs);
+                let converted_sig = sig.map_bound(|s| {
+                    let params_iter = match s.inputs()[0].sty {
+                        ty::TyTuple(params, _) => {
+                            params.into_iter().cloned()
+                        }
+                        _ => bug!(),
+                    };
+                    self.tcx.mk_fn_sig(
+                        params_iter,
+                        s.output(),
+                        s.variadic,
+                        hir::Unsafety::Normal,
+                        abi::Abi::Rust
+                    )
+                });
+                let pointer_ty = self.tcx.mk_fn_ptr(converted_sig);
+                debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})",
+                       a, b, pointer_ty);
+                self.unify_and_identity(pointer_ty, b)
+                    .map(|(ty, _)| (ty, Adjust::ClosureFnPointer))
+            }
+            _ => self.unify_and_identity(a, b),
+        }
+    }
+
     fn coerce_unsafe_ptr(&self,
                          a: Ty<'tcx>,
                          b: Ty<'tcx>,
index d110c16cf331396e133e95315cc154a8722564a8..0e9abaf1cf955e86c272e91acc882fcccbfcedb6 100644 (file)
@@ -11,7 +11,7 @@
 use rustc::hir::{self, ImplItemKind, TraitItemKind};
 use rustc::infer::{self, InferOk};
 use rustc::middle::free_region::FreeRegionMap;
-use rustc::ty;
+use rustc::ty::{self, TyCtxt};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc::ty::error::{ExpectedFound, TypeError};
 use rustc::ty::subst::{Subst, Substs};
@@ -20,7 +20,6 @@
 use syntax::ast;
 use syntax_pos::Span;
 
-use CrateCtxt;
 use super::assoc;
 use super::{Inherited, FnCtxt};
 use astconv::ExplicitSelf;
@@ -36,7 +35,7 @@
 /// - trait_m: the method in the trait
 /// - impl_trait_ref: the TraitRef corresponding to the trait implementation
 
-pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                      impl_m: &ty::AssociatedItem,
                                      impl_m_span: Span,
                                      impl_m_body_id: ast::NodeId,
@@ -47,7 +46,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     debug!("compare_impl_method(impl_trait_ref={:?})",
            impl_trait_ref);
 
-    if let Err(ErrorReported) = compare_self_type(ccx,
+    if let Err(ErrorReported) = compare_self_type(tcx,
                                                   impl_m,
                                                   impl_m_span,
                                                   trait_m,
@@ -55,7 +54,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         return;
     }
 
-    if let Err(ErrorReported) = compare_number_of_generics(ccx,
+    if let Err(ErrorReported) = compare_number_of_generics(tcx,
                                                            impl_m,
                                                            impl_m_span,
                                                            trait_m,
@@ -63,7 +62,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         return;
     }
 
-    if let Err(ErrorReported) = compare_number_of_method_arguments(ccx,
+    if let Err(ErrorReported) = compare_number_of_method_arguments(tcx,
                                                                    impl_m,
                                                                    impl_m_span,
                                                                    trait_m,
@@ -71,7 +70,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         return;
     }
 
-    if let Err(ErrorReported) = compare_predicate_entailment(ccx,
+    if let Err(ErrorReported) = compare_predicate_entailment(tcx,
                                                              impl_m,
                                                              impl_m_span,
                                                              impl_m_body_id,
@@ -82,7 +81,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                           impl_m: &ty::AssociatedItem,
                                           impl_m_span: Span,
                                           impl_m_body_id: ast::NodeId,
@@ -90,8 +89,6 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                           impl_trait_ref: ty::TraitRef<'tcx>,
                                           old_broken_mode: bool)
                                           -> Result<(), ErrorReported> {
-    let tcx = ccx.tcx;
-
     let trait_to_impl_substs = impl_trait_ref.substs;
 
     let cause = ObligationCause {
@@ -190,7 +187,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let trait_m_predicates = tcx.item_predicates(trait_m.def_id);
 
     // Check region bounds.
-    check_region_bounds_on_impl_method(ccx,
+    check_region_bounds_on_impl_method(tcx,
                                        impl_m_span,
                                        impl_m,
                                        &trait_m_generics,
@@ -227,8 +224,8 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                                trait_param_env,
                                                                normalize_cause.clone());
 
-    tcx.infer_ctxt(trait_param_env, Reveal::NotSpecializable).enter(|infcx| {
-        let inh = Inherited::new(ccx, infcx);
+    tcx.infer_ctxt(trait_param_env, Reveal::UserFacing).enter(|infcx| {
+        let inh = Inherited::new(infcx);
         let infcx = &inh.infcx;
         let fulfillment_cx = &inh.fulfillment_cx;
 
@@ -266,19 +263,17 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         // Compute skolemized form of impl and trait method tys.
         let tcx = infcx.tcx;
 
-        let m_fty = |method: &ty::AssociatedItem| {
+        let m_sig = |method: &ty::AssociatedItem| {
             match tcx.item_type(method.def_id).sty {
                 ty::TyFnDef(_, _, f) => f,
                 _ => bug!()
             }
         };
-        let impl_m_fty = m_fty(impl_m);
-        let trait_m_fty = m_fty(trait_m);
 
         let (impl_sig, _) =
             infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
                                                             infer::HigherRankedType,
-                                                            &impl_m_fty.sig);
+                                                            &m_sig(impl_m));
         let impl_sig =
             impl_sig.subst(tcx, impl_to_skol_substs);
         let impl_sig =
@@ -287,16 +282,12 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                  impl_m_span,
                                                  impl_m_body_id,
                                                  &impl_sig);
-        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.clone()),
-        }));
+        let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig));
         debug!("compare_impl_method: impl_fty={:?}", impl_fty);
 
         let trait_sig = tcx.liberate_late_bound_regions(
             infcx.parameter_environment.free_id_outlive,
-            &trait_m_fty.sig);
+            &m_sig(trait_m));
         let trait_sig =
             trait_sig.subst(tcx, trait_to_skol_substs);
         let trait_sig =
@@ -305,11 +296,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                  impl_m_span,
                                                  impl_m_body_id,
                                                  &trait_sig);
-        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.clone()),
-        }));
+        let trait_fty = tcx.mk_fn_ptr(ty::Binder(trait_sig));
 
         debug!("compare_impl_method: trait_fty={:?}", trait_fty);
 
@@ -383,11 +370,11 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     })
 }
 
-fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 span: Span,
                                                 impl_m: &ty::AssociatedItem,
-                                                trait_generics: &ty::Generics<'tcx>,
-                                                impl_generics: &ty::Generics<'tcx>,
+                                                trait_generics: &ty::Generics,
+                                                impl_generics: &ty::Generics,
                                                 trait_to_skol_substs: &Substs<'tcx>,
                                                 impl_to_skol_substs: &Substs<'tcx>)
                                                 -> Result<(), ErrorReported> {
@@ -414,7 +401,7 @@ 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() {
-        struct_span_err!(ccx.tcx.sess,
+        struct_span_err!(tcx.sess,
                          span,
                          E0195,
                          "lifetime parameters or bounds on method `{}` do not match the \
@@ -510,14 +497,13 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
     }
 }
 
-fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                impl_m: &ty::AssociatedItem,
                                impl_m_span: Span,
                                trait_m: &ty::AssociatedItem,
                                impl_trait_ref: ty::TraitRef<'tcx>)
                                -> Result<(), ErrorReported>
 {
-    let tcx = ccx.tcx;
     // Try to give more informative error messages about self typing
     // mismatches.  Note that any mismatch will also be detected
     // below, where we construct a canonical function type that
@@ -583,13 +569,12 @@ fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     Ok(())
 }
 
-fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn compare_number_of_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         impl_m: &ty::AssociatedItem,
                                         impl_m_span: Span,
                                         trait_m: &ty::AssociatedItem,
                                         trait_item_span: Option<Span>)
                                         -> Result<(), ErrorReported> {
-    let tcx = ccx.tcx;
     let impl_m_generics = tcx.item_generics(impl_m.def_id);
     let trait_m_generics = tcx.item_generics(trait_m.def_id);
     let num_impl_m_type_params = impl_m_generics.types.len();
@@ -653,13 +638,12 @@ fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     Ok(())
 }
 
-fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 impl_m: &ty::AssociatedItem,
                                                 impl_m_span: Span,
                                                 trait_m: &ty::AssociatedItem,
                                                 trait_item_span: Option<Span>)
                                                 -> Result<(), ErrorReported> {
-    let tcx = ccx.tcx;
     let m_fty = |method: &ty::AssociatedItem| {
         match tcx.item_type(method.def_id).sty {
             ty::TyFnDef(_, _, f) => f,
@@ -668,8 +652,8 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     };
     let impl_m_fty = m_fty(impl_m);
     let trait_m_fty = m_fty(trait_m);
-    let trait_number_args = trait_m_fty.sig.inputs().skip_binder().len();
-    let impl_number_args = impl_m_fty.sig.inputs().skip_binder().len();
+    let trait_number_args = trait_m_fty.inputs().skip_binder().len();
+    let impl_number_args = impl_m_fty.inputs().skip_binder().len();
     if trait_number_args != impl_number_args {
         let trait_m_node_id = tcx.hir.as_local_node_id(trait_m.def_id);
         let trait_span = if let Some(trait_id) = trait_m_node_id {
@@ -739,15 +723,14 @@ trait `{}` has {}",
     Ok(())
 }
 
-pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     impl_c: &ty::AssociatedItem,
                                     impl_c_span: Span,
                                     trait_c: &ty::AssociatedItem,
                                     impl_trait_ref: ty::TraitRef<'tcx>) {
     debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
 
-    let tcx = ccx.tcx;
-    tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
+    tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
         let mut fulfillment_cx = traits::FulfillmentContext::new();
 
         // The below is for the most part highly similar to the procedure
index a77887cd221deb52e48b2e5f601365d01d00522c..232c4c4db7c97d41133e19b229797cd4a047afe4 100644 (file)
@@ -123,8 +123,8 @@ fn has_no_input_arg(&self, method: &AssociatedItem) -> bool {
         match method.def() {
             Def::Method(def_id) => {
                 match self.tcx.item_type(def_id).sty {
-                    ty::TypeVariants::TyFnDef(_, _, fty) => {
-                        fty.sig.skip_binder().inputs().len() == 1
+                    ty::TypeVariants::TyFnDef(_, _, sig) => {
+                        sig.inputs().skip_binder().len() == 1
                     }
                     _ => false,
                 }
index f701bc3220848d452b0b51aa913751d676ab9137..07cc35ed67bbb76ab86bf82bd3e446544cd0f7e1 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use CrateCtxt;
 use check::regionck::RegionCtxt;
 
 use hir::def_id::DefId;
 ///    struct/enum definition for the nominal type itself (i.e.
 ///    cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
 ///
-pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()> {
-    let dtor_self_type = ccx.tcx.item_type(drop_impl_did);
-    let dtor_predicates = ccx.tcx.item_predicates(drop_impl_did);
+pub fn check_drop_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                 drop_impl_did: DefId) -> Result<(), ()> {
+    let dtor_self_type = tcx.item_type(drop_impl_did);
+    let dtor_predicates = tcx.item_predicates(drop_impl_did);
     match dtor_self_type.sty {
         ty::TyAdt(adt_def, self_to_impl_substs) => {
-            ensure_drop_params_and_item_params_correspond(ccx,
+            ensure_drop_params_and_item_params_correspond(tcx,
                                                           drop_impl_did,
                                                           dtor_self_type,
                                                           adt_def.did)?;
 
-            ensure_drop_predicates_are_implied_by_item_defn(ccx,
+            ensure_drop_predicates_are_implied_by_item_defn(tcx,
                                                             drop_impl_did,
                                                             &dtor_predicates,
                                                             adt_def.did,
@@ -59,7 +59,7 @@ pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()>
         _ => {
             // Destructors only work on nominal types.  This was
             // already checked by coherence, so we can panic here.
-            let span = ccx.tcx.def_span(drop_impl_did);
+            let span = tcx.def_span(drop_impl_did);
             span_bug!(span,
                       "should have been rejected by coherence check: {}",
                       dtor_self_type);
@@ -68,20 +68,19 @@ pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()>
 }
 
 fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
-    ccx: &CrateCtxt<'a, 'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     drop_impl_did: DefId,
     drop_impl_ty: Ty<'tcx>,
     self_type_did: DefId)
     -> Result<(), ()>
 {
-    let tcx = ccx.tcx;
     let drop_impl_node_id = tcx.hir.as_local_node_id(drop_impl_did).unwrap();
     let self_type_node_id = tcx.hir.as_local_node_id(self_type_did).unwrap();
 
     // check that the impl type can be made to match the trait type.
 
     let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id);
-    tcx.infer_ctxt(impl_param_env, Reveal::NotSpecializable).enter(|infcx| {
+    tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|infcx| {
         let tcx = infcx.tcx;
         let mut fulfillment_cx = traits::FulfillmentContext::new();
 
@@ -126,7 +125,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
 /// Confirms that every predicate imposed by dtor_predicates is
 /// implied by assuming the predicates attached to self_type_did.
 fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
-    ccx: &CrateCtxt<'a, 'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     drop_impl_did: DefId,
     dtor_predicates: &ty::GenericPredicates<'tcx>,
     self_type_did: DefId,
@@ -169,8 +168,6 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
     // absent. So we report an error that the Drop impl injected a
     // predicate that is not present on the struct definition.
 
-    let tcx = ccx.tcx;
-
     let self_type_node_id = tcx.hir.as_local_node_id(self_type_did).unwrap();
 
     let drop_impl_span = tcx.def_span(drop_impl_did);
@@ -557,7 +554,7 @@ fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 
             // Find the `impl<..> Drop for _` to inspect any
             // attributes attached to the impl's generics.
-            let dtor_method = adt_def.destructor()
+            let dtor_method = adt_def.destructor(tcx)
                 .expect("dtorck type without destructor impossible");
             let method = tcx.associated_item(dtor_method);
             let impl_def_id = method.container.id();
index cb4e85e842c2a8f3727cfad82a312fcfb7a3aecf..28996b40cfdfec0f2fa7d76df348e78311f00525 100644 (file)
@@ -14,9 +14,9 @@
 use intrinsics;
 use rustc::traits::{ObligationCause, ObligationCauseCode};
 use rustc::ty::subst::Substs;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, TyCtxt, Ty};
 use rustc::util::nodemap::FxHashMap;
-use {CrateCtxt, require_same_types};
+use require_same_types;
 
 use syntax::abi::Abi;
 use syntax::ast;
 
 use std::iter;
 
-fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                    it: &hir::ForeignItem,
                                    n_tps: usize,
                                    abi: Abi,
                                    inputs: Vec<Ty<'tcx>>,
                                    output: Ty<'tcx>) {
-    let tcx = ccx.tcx;
     let def_id = tcx.hir.local_def_id(it.id);
 
     let substs = Substs::for_item(tcx, def_id,
                                   |_, _| 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 {
-        unsafety: hir::Unsafety::Unsafe,
-        abi: abi,
-        sig: ty::Binder(tcx.mk_fn_sig(inputs.into_iter(), output, false)),
-    }));
+    let fty = tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig(
+        inputs.into_iter(),
+        output,
+        false,
+        hir::Unsafety::Unsafe,
+        abi
+    )));
     let i_n_tps = tcx.item_generics(def_id).types.len();
     if i_n_tps != n_tps {
         let span = match it.node {
@@ -59,7 +60,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             .span_label(span, &format!("expected {} type parameter", n_tps))
             .emit();
     } else {
-        require_same_types(ccx,
+        require_same_types(tcx,
                            &ObligationCause::new(it.span,
                                                  it.id,
                                                  ObligationCauseCode::IntrinsicType),
@@ -70,13 +71,9 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
 /// Remember to add all intrinsics here, in librustc_trans/trans/intrinsic.rs,
 /// and in libcore/intrinsics.rs
-pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
-    fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
-        let name = Symbol::intern(&format!("P{}", n));
-        ccx.tcx.mk_param(n, name)
-    }
-
-    let tcx = ccx.tcx;
+pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                      it: &hir::ForeignItem) {
+    let param = |n| tcx.mk_param(n, Symbol::intern(&format!("P{}", n)));
     let name = it.name.as_str();
     let (n_tps, inputs, output) = if name.starts_with("atomic_") {
         let split : Vec<&str> = name.split('_').collect();
@@ -84,19 +81,19 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
 
         //We only care about the operation here
         let (n_tps, inputs, output) = match split[1] {
-            "cxchg" | "cxchgweak" => (1, vec![tcx.mk_mut_ptr(param(ccx, 0)),
-                                              param(ccx, 0),
-                                              param(ccx, 0)],
-                                      tcx.intern_tup(&[param(ccx, 0), tcx.types.bool], false)),
-            "load" => (1, vec![tcx.mk_imm_ptr(param(ccx, 0))],
-                       param(ccx, 0)),
-            "store" => (1, vec![tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)],
+            "cxchg" | "cxchgweak" => (1, vec![tcx.mk_mut_ptr(param(0)),
+                                              param(0),
+                                              param(0)],
+                                      tcx.intern_tup(&[param(0), tcx.types.bool], false)),
+            "load" => (1, vec![tcx.mk_imm_ptr(param(0))],
+                       param(0)),
+            "store" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)],
                         tcx.mk_nil()),
 
             "xchg" | "xadd" | "xsub" | "and"  | "nand" | "or" | "xor" | "max" |
             "min"  | "umax" | "umin" => {
-                (1, vec![tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)],
-                 param(ccx, 0))
+                (1, vec![tcx.mk_mut_ptr(param(0)), param(0)],
+                 param(0))
             }
             "fence" | "singlethreadfence" => {
                 (0, Vec::new(), tcx.mk_nil())
@@ -116,45 +113,45 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
         let (n_tps, inputs, output) = match &name[..] {
             "breakpoint" => (0, Vec::new(), tcx.mk_nil()),
             "size_of" |
-            "pref_align_of" | "min_align_of" => (1, Vec::new(), ccx.tcx.types.usize),
+            "pref_align_of" | "min_align_of" => (1, Vec::new(), tcx.types.usize),
             "size_of_val" |  "min_align_of_val" => {
                 (1, vec![
                     tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1),
                                                                   ty::BrAnon(0))),
-                                    param(ccx, 0))
-                 ], ccx.tcx.types.usize)
+                                    param(0))
+                 ], tcx.types.usize)
             }
-            "rustc_peek" => (1, vec![param(ccx, 0)], 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)),
+            "rustc_peek" => (1, vec![param(0)], param(0)),
+            "init" => (1, Vec::new(), param(0)),
+            "uninit" => (1, Vec::new(), param(0)),
+            "forget" => (1, vec![ param(0) ], tcx.mk_nil()),
+            "transmute" => (2, vec![ param(0) ], param(1)),
             "move_val_init" => {
                 (1,
                  vec![
-                    tcx.mk_mut_ptr(param(ccx, 0)),
-                    param(ccx, 0)
+                    tcx.mk_mut_ptr(param(0)),
+                    param(0)
                   ],
                tcx.mk_nil())
             }
             "drop_in_place" => {
-                (1, vec![tcx.mk_mut_ptr(param(ccx, 0))], tcx.mk_nil())
+                (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_nil())
             }
-            "needs_drop" => (1, Vec::new(), ccx.tcx.types.bool),
+            "needs_drop" => (1, Vec::new(), tcx.types.bool),
 
             "type_name" => (1, Vec::new(), tcx.mk_static_str()),
-            "type_id" => (1, Vec::new(), ccx.tcx.types.u64),
+            "type_id" => (1, Vec::new(), tcx.types.u64),
             "offset" | "arith_offset" => {
               (1,
                vec![
                   tcx.mk_ptr(ty::TypeAndMut {
-                      ty: param(ccx, 0),
+                      ty: param(0),
                       mutbl: hir::MutImmutable
                   }),
-                  ccx.tcx.types.isize
+                  tcx.types.isize
                ],
                tcx.mk_ptr(ty::TypeAndMut {
-                   ty: param(ccx, 0),
+                   ty: param(0),
                    mutbl: hir::MutImmutable
                }))
             }
@@ -162,11 +159,11 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
               (1,
                vec![
                   tcx.mk_ptr(ty::TypeAndMut {
-                      ty: param(ccx, 0),
+                      ty: param(0),
                       mutbl: hir::MutImmutable
                   }),
                   tcx.mk_ptr(ty::TypeAndMut {
-                      ty: param(ccx, 0),
+                      ty: param(0),
                       mutbl: hir::MutMutable
                   }),
                   tcx.types.usize,
@@ -177,11 +174,11 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
               (1,
                vec![
                   tcx.mk_ptr(ty::TypeAndMut {
-                      ty: param(ccx, 0),
+                      ty: param(0),
                       mutbl: hir::MutMutable
                   }),
                   tcx.mk_ptr(ty::TypeAndMut {
-                      ty: param(ccx, 0),
+                      ty: param(0),
                       mutbl: hir::MutImmutable
                   }),
                   tcx.types.usize,
@@ -192,7 +189,7 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
               (1,
                vec![
                   tcx.mk_ptr(ty::TypeAndMut {
-                      ty: param(ccx, 0),
+                      ty: param(0),
                       mutbl: hir::MutMutable
                   }),
                   tcx.types.u8,
@@ -264,23 +261,23 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
             "roundf64"     => (0, vec![ tcx.types.f64 ], tcx.types.f64),
 
             "volatile_load" =>
-                (1, vec![ tcx.mk_imm_ptr(param(ccx, 0)) ], param(ccx, 0)),
+                (1, vec![ tcx.mk_imm_ptr(param(0)) ], param(0)),
             "volatile_store" =>
-                (1, vec![ tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0) ], tcx.mk_nil()),
+                (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil()),
 
-            "ctpop" | "ctlz" | "cttz" | "bswap" => (1, vec![param(ccx, 0)], param(ccx, 0)),
+            "ctpop" | "ctlz" | "cttz" | "bswap" => (1, vec![param(0)], param(0)),
 
             "add_with_overflow" | "sub_with_overflow"  | "mul_with_overflow" =>
-                (1, vec![param(ccx, 0), param(ccx, 0)],
-                tcx.intern_tup(&[param(ccx, 0), tcx.types.bool], false)),
+                (1, vec![param(0), param(0)],
+                tcx.intern_tup(&[param(0), tcx.types.bool], false)),
 
             "unchecked_div" | "unchecked_rem" =>
-                (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)),
+                (1, vec![param(0), param(0)], param(0)),
 
             "overflowing_add" | "overflowing_sub" | "overflowing_mul" =>
-                (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)),
+                (1, vec![param(0), param(0)], param(0)),
             "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" =>
-                (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)),
+                (1, vec![param(0), param(0)], param(0)),
 
             "assume" => (0, vec![tcx.types.bool], tcx.mk_nil()),
             "likely" => (0, vec![tcx.types.bool], tcx.types.bool),
@@ -289,15 +286,17 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
             "discriminant_value" => (1, vec![
                     tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1),
                                                                   ty::BrAnon(0))),
-                                   param(ccx, 0))], tcx.types.u64),
+                                   param(0))], tcx.types.u64),
 
             "try" => {
                 let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
-                let fn_ty = tcx.mk_bare_fn(ty::BareFnTy {
-                    unsafety: hir::Unsafety::Normal,
-                    abi: Abi::Rust,
-                    sig: ty::Binder(tcx.mk_fn_sig(iter::once(mut_u8), tcx.mk_nil(), false)),
-                });
+                let fn_ty = ty::Binder(tcx.mk_fn_sig(
+                    iter::once(mut_u8),
+                    tcx.mk_nil(),
+                    false,
+                    hir::Unsafety::Normal,
+                    Abi::Rust,
+                ));
                 (0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32)
             }
 
@@ -312,18 +311,17 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
         };
         (n_tps, inputs, output)
     };
-    equate_intrinsic_type(ccx, it, n_tps, Abi::RustIntrinsic, inputs, output)
+    equate_intrinsic_type(tcx, it, n_tps, Abi::RustIntrinsic, inputs, output)
 }
 
 /// Type-check `extern "platform-intrinsic" { ... }` functions.
-pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
-                                     it: &hir::ForeignItem) {
+pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                               it: &hir::ForeignItem) {
     let param = |n| {
         let name = Symbol::intern(&format!("P{}", n));
-        ccx.tcx.mk_param(n, name)
+        tcx.mk_param(n, name)
     };
 
-    let tcx = ccx.tcx;
     let def_id = tcx.hir.local_def_id(it.id);
     let i_n_tps = tcx.item_generics(def_id).types.len();
     let name = it.name.as_str();
@@ -369,7 +367,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
                     let mut structural_to_nomimal = FxHashMap();
 
                     let sig = tcx.item_type(def_id).fn_sig();
-                    let sig = tcx.no_late_bound_regions(sig).unwrap();
+                    let sig = tcx.no_late_bound_regions(&sig).unwrap();
                     if intr.inputs.len() != sig.inputs().len() {
                         span_err!(tcx.sess, it.span, E0444,
                                   "platform-specific intrinsic has invalid number of \
@@ -379,10 +377,10 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
                     }
                     let input_pairs = intr.inputs.iter().zip(sig.inputs());
                     for (i, (expected_arg, arg)) in input_pairs.enumerate() {
-                        match_intrinsic_type_to_type(ccx, &format!("argument {}", i + 1), it.span,
+                        match_intrinsic_type_to_type(tcx, &format!("argument {}", i + 1), it.span,
                                                      &mut structural_to_nomimal, expected_arg, arg);
                     }
-                    match_intrinsic_type_to_type(ccx, "return value", it.span,
+                    match_intrinsic_type_to_type(tcx, "return value", it.span,
                                                  &mut structural_to_nomimal,
                                                  &intr.output, sig.output());
                     return
@@ -396,15 +394,15 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
         }
     };
 
-    equate_intrinsic_type(ccx, it, n_tps, Abi::PlatformIntrinsic,
+    equate_intrinsic_type(tcx, it, n_tps, Abi::PlatformIntrinsic,
                           inputs, output)
 }
 
 // walk the expected type and the actual type in lock step, checking they're
 // the same, in a kinda-structural way, i.e. `Vector`s have to be simd structs with
 // exactly the right element type
-fn match_intrinsic_type_to_type<'tcx, 'a>(
-        ccx: &CrateCtxt<'a, 'tcx>,
+fn match_intrinsic_type_to_type<'a, 'tcx>(
+        tcx: TyCtxt<'a, 'tcx, 'tcx>,
         position: &str,
         span: Span,
         structural_to_nominal: &mut FxHashMap<&'a intrinsics::Type, ty::Ty<'tcx>>,
@@ -413,7 +411,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
     use intrinsics::Type::*;
 
     let simple_error = |real: &str, expected: &str| {
-        span_err!(ccx.tcx.sess, span, E0442,
+        span_err!(tcx.sess, span, E0442,
                   "intrinsic {} has wrong type: found {}, expected {}",
                   position, real, expected)
     };
@@ -453,7 +451,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
                         simple_error(&format!("`{}`", t),
                                      if const_ {"const pointer"} else {"mut pointer"})
                     }
-                    match_intrinsic_type_to_type(ccx, position, span, structural_to_nominal,
+                    match_intrinsic_type_to_type(tcx, position, span, structural_to_nominal,
                                                  inner_expected, ty)
                 }
                 _ => simple_error(&format!("`{}`", t), "raw pointer"),
@@ -464,19 +462,19 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
                 simple_error(&format!("non-simd type `{}`", t), "simd type");
                 return;
             }
-            let t_len = t.simd_size(ccx.tcx);
+            let t_len = t.simd_size(tcx);
             if len as usize != t_len {
                 simple_error(&format!("vector with length {}", t_len),
                              &format!("length {}", len));
                 return;
             }
-            let t_ty = t.simd_type(ccx.tcx);
+            let t_ty = t.simd_type(tcx);
             {
                 // check that a given structural type always has the same an intrinsic definition
                 let previous = structural_to_nominal.entry(expected).or_insert(t);
                 if *previous != t {
                     // this gets its own error code because it is non-trivial
-                    span_err!(ccx.tcx.sess, span, E0443,
+                    span_err!(tcx.sess, span, E0443,
                               "intrinsic {} has wrong type: found `{}`, expected `{}` which \
                                was used for this vector type previously in this signature",
                               position,
@@ -485,7 +483,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
                     return;
                 }
             }
-            match_intrinsic_type_to_type(ccx,
+            match_intrinsic_type_to_type(tcx,
                                          position,
                                          span,
                                          structural_to_nominal,
@@ -501,7 +499,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>(
                         return
                     }
                     for (e, c) in expected_contents.iter().zip(contents) {
-                        match_intrinsic_type_to_type(ccx, position, span, structural_to_nominal,
+                        match_intrinsic_type_to_type(tcx, position, span, structural_to_nominal,
                                                      e, c)
                     }
                 }
index 2d90394025d21ad909d2116e3d1a28dd923bea89..e6e4b577bd50d785825d3690041d740f3c9b4498 100644 (file)
@@ -365,10 +365,7 @@ fn instantiate_method_sig(&mut self,
 
         debug!("method_predicates after subst = {:?}", method_predicates);
 
-        let fty = match self.tcx.item_type(def_id).sty {
-            ty::TyFnDef(_, _, f) => f,
-            _ => bug!()
-        };
+        let sig = self.tcx.item_type(def_id).fn_sig();
 
         // Instantiate late-bound regions and substitute the trait
         // parameters into the method type to get the actual method type.
@@ -376,21 +373,15 @@ fn instantiate_method_sig(&mut self,
         // NB: Instantiate late-bound regions first so that
         // `instantiate_type_scheme` can normalize associated types that
         // may reference those regions.
-        let method_sig = self.replace_late_bound_regions_with_fresh_var(&fty.sig);
+        let method_sig = self.replace_late_bound_regions_with_fresh_var(&sig);
         debug!("late-bound lifetimes from method instantiated, method_sig={:?}",
                method_sig);
 
         let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig);
         debug!("type scheme substituted, method_sig={:?}", method_sig);
 
-        let method_ty = self.tcx.mk_fn_def(def_id, all_substs,
-                                           self.tcx.mk_bare_fn(ty::BareFnTy {
-            sig: ty::Binder(method_sig),
-            unsafety: fty.unsafety,
-            abi: fty.abi,
-        }));
-
-        (method_ty, method_predicates)
+        (self.tcx.mk_fn_def(def_id, all_substs, ty::Binder(method_sig)),
+         method_predicates)
     }
 
     fn add_obligations(&mut self,
@@ -566,7 +557,7 @@ fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) {
         // Disallow calls to the method `drop` defined in the `Drop` trait.
         match pick.item.container {
             ty::TraitContainer(trait_def_id) => {
-                callee::check_legal_trait_for_method_call(self.ccx, self.span, trait_def_id)
+                callee::check_legal_trait_for_method_call(self.tcx, self.span, trait_def_id)
             }
             ty::ImplContainer(..) => {}
         }
index eae8989bd342eec23106eb22252eb96f0cf0030f..4085a171bbef53801977e1efa5a026c107968e5f 100644 (file)
@@ -139,7 +139,7 @@ pub fn lookup_method(&self,
         if let Some(import_id) = pick.import_id {
             let import_def_id = self.tcx.hir.local_def_id(import_id);
             debug!("used_trait_import: {:?}", import_def_id);
-            self.used_trait_imports.borrow_mut().insert(import_def_id);
+            self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
         }
 
         self.tcx.check_stability(pick.item.def_id, call_expr.id, span);
@@ -244,21 +244,14 @@ pub fn lookup_method_in_trait_adjusted(&self,
         // `instantiate_type_scheme` can normalize associated types that
         // may reference those regions.
         let original_method_ty = tcx.item_type(def_id);
-        let fty = match original_method_ty.sty {
-            ty::TyFnDef(_, _, f) => f,
-            _ => bug!()
-        };
+        let fn_sig = original_method_ty.fn_sig();
         let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
                                                                     infer::FnCall,
-                                                                    &fty.sig).0;
+                                                                    &fn_sig).0;
         let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig);
         let transformed_self_ty = fn_sig.inputs()[0];
         let method_ty = tcx.mk_fn_def(def_id, trait_ref.substs,
-                                      tcx.mk_bare_fn(ty::BareFnTy {
-            sig: ty::Binder(fn_sig),
-            unsafety: fty.unsafety,
-            abi: fty.abi
-        }));
+                                     ty::Binder(fn_sig));
 
         debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
                method_ty,
@@ -340,7 +333,7 @@ pub fn resolve_ufcs(&self,
         if let Some(import_id) = pick.import_id {
             let import_def_id = self.tcx.hir.local_def_id(import_id);
             debug!("used_trait_import: {:?}", import_def_id);
-            self.used_trait_imports.borrow_mut().insert(import_def_id);
+            self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
         }
 
         let def = pick.item.def();
index fd29ff0be43b44910d5f7860cd1727bd169ec289..dfa7ababca0bbd8b97f143cbc9efcdca24d44ec6 100644 (file)
@@ -481,9 +481,9 @@ fn assemble_inherent_impl_for_primitive(&mut self, lang_def_id: Option<DefId>) {
     fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) {
         // Read the inherent implementation candidates for this type from the
         // metadata if necessary.
-        self.tcx.populate_inherent_implementations_for_type_if_necessary(def_id);
+        self.tcx.populate_inherent_implementations_for_type_if_necessary(self.span, def_id);
 
-        if let Some(impl_infos) = self.tcx.inherent_impls.borrow().get(&def_id) {
+        if let Some(impl_infos) = self.tcx.maps.inherent_impls.borrow().get(&def_id) {
             for &impl_def_id in impl_infos.iter() {
                 self.assemble_inherent_impl_probe(impl_def_id);
             }
@@ -653,7 +653,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 = FxHashSet();
-        for trait_info in suggest::all_traits(self.ccx) {
+        for trait_info in suggest::all_traits(self.tcx) {
             if duplicates.insert(trait_info.def_id) {
                 self.assemble_extension_candidates_for_trait(None, trait_info.def_id)?;
             }
index f6345e6e262db618192ee00d2719f77c48e5f42a..6ce50d91124d445002769b6dfb0ad775dbecd867 100644 (file)
 //! Give useful errors and suggestions to users when an item can't be
 //! found or is otherwise invalid.
 
-use CrateCtxt;
-
 use check::FnCtxt;
 use rustc::hir::map as hir_map;
-use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable};
+use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable};
 use hir::def::Def;
 use hir::def_id::{CRATE_DEF_INDEX, DefId};
 use middle::lang_items::FnOnceTraitLangItem;
@@ -343,7 +341,7 @@ fn suggest_traits_to_import(&self,
         // there's no implemented traits, so lets suggest some traits to
         // implement, by finding ones that have the item name, and are
         // legal to implement.
-        let mut candidates = all_traits(self.ccx)
+        let mut candidates = all_traits(self.tcx)
             .filter(|info| {
                 // we approximate the coherence rules to only suggest
                 // traits that are legal to implement by requiring that
@@ -423,7 +421,7 @@ fn is_local(ty: Ty) -> bool {
     }
 }
 
-pub type AllTraitsVec = Vec<TraitInfo>;
+pub type AllTraitsVec = Vec<DefId>;
 
 #[derive(Copy, Clone)]
 pub struct TraitInfo {
@@ -458,8 +456,8 @@ fn cmp(&self, other: &TraitInfo) -> Ordering {
 }
 
 /// Retrieve all traits in this crate and any dependent crates.
-pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
-    if ccx.all_traits.borrow().is_none() {
+pub fn all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> AllTraits<'a> {
+    if tcx.all_traits.borrow().is_none() {
         use rustc::hir::itemlikevisit;
 
         let mut traits = vec![];
@@ -476,7 +474,7 @@ fn visit_item(&mut self, i: &'v hir::Item) {
                 match i.node {
                     hir::ItemTrait(..) => {
                         let def_id = self.map.local_def_id(i.id);
-                        self.traits.push(TraitInfo::new(def_id));
+                        self.traits.push(def_id);
                     }
                     _ => {}
                 }
@@ -488,45 +486,45 @@ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
             fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
             }
         }
-        ccx.tcx.hir.krate().visit_all_item_likes(&mut Visitor {
-            map: &ccx.tcx.hir,
+        tcx.hir.krate().visit_all_item_likes(&mut Visitor {
+            map: &tcx.hir,
             traits: &mut traits,
         });
 
         // Cross-crate:
         let mut external_mods = FxHashSet();
-        fn handle_external_def(ccx: &CrateCtxt,
+        fn handle_external_def(tcx: TyCtxt,
                                traits: &mut AllTraitsVec,
                                external_mods: &mut FxHashSet<DefId>,
                                def: Def) {
             let def_id = def.def_id();
             match def {
                 Def::Trait(..) => {
-                    traits.push(TraitInfo::new(def_id));
+                    traits.push(def_id);
                 }
                 Def::Mod(..) => {
                     if !external_mods.insert(def_id) {
                         return;
                     }
-                    for child in ccx.tcx.sess.cstore.item_children(def_id) {
-                        handle_external_def(ccx, traits, external_mods, child.def)
+                    for child in tcx.sess.cstore.item_children(def_id) {
+                        handle_external_def(tcx, traits, external_mods, child.def)
                     }
                 }
                 _ => {}
             }
         }
-        for cnum in ccx.tcx.sess.cstore.crates() {
+        for cnum in tcx.sess.cstore.crates() {
             let def_id = DefId {
                 krate: cnum,
                 index: CRATE_DEF_INDEX,
             };
-            handle_external_def(ccx, &mut traits, &mut external_mods, Def::Mod(def_id));
+            handle_external_def(tcx, &mut traits, &mut external_mods, Def::Mod(def_id));
         }
 
-        *ccx.all_traits.borrow_mut() = Some(traits);
+        *tcx.all_traits.borrow_mut() = Some(traits);
     }
 
-    let borrow = ccx.all_traits.borrow();
+    let borrow = tcx.all_traits.borrow();
     assert!(borrow.is_some());
     AllTraits {
         borrow: borrow,
@@ -547,7 +545,7 @@ fn next(&mut self) -> Option<TraitInfo> {
         // ugh.
         borrow.as_ref().unwrap().get(*idx).map(|info| {
             *idx += 1;
-            *info
+            TraitInfo::new(*info)
         })
     }
 }
index fbea34c95a6d73bc064d009e1be01cbacbec9bd3..d21bb68d4c827d9204306e18c936cb5b149f21d0 100644 (file)
@@ -56,7 +56,7 @@
 may contain unresolved type variables.  After type checking is
 complete, the functions in the writeback module are used to take the
 types from this table, resolve them, and then write them into their
-permanent home in the type context `ccx.tcx`.
+permanent home in the type context `tcx`.
 
 This means that during inferencing you should use `fcx.write_ty()`
 and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc::ty::{ParamTy, ParameterEnvironment};
 use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
-use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility};
+use rustc::ty::{self, Ty, TyCtxt, Visibility};
 use rustc::ty::{MethodCall, MethodCallee};
 use rustc::ty::adjustment;
 use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
+use rustc::ty::maps::Providers;
 use rustc::ty::util::{Representability, IntTypeExt};
 use require_c_abi_if_variadic;
 use session::{Session, CompileResult};
-use CrateCtxt;
 use TypeAndSubsts;
 use lint;
 use util::common::{ErrorReported, indenter};
-use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, NodeMap};
+use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap};
 
 use std::cell::{Cell, RefCell};
 use std::cmp;
 use std::ops::{self, Deref};
 use syntax::abi::Abi;
 use syntax::ast;
-use syntax::attr;
 use syntax::codemap::{self, original_sp, Spanned};
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::ptr::P;
 use rustc::middle::lang_items;
 use rustc_back::slice;
 use rustc_const_eval::eval_length;
+use rustc_const_math::ConstInt;
 
 mod assoc;
 mod autoderef;
 /// `bar()` will each have their own `FnCtxt`, but they will
 /// share the inherited fields.
 pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    ccx: &'a CrateCtxt<'a, 'gcx>,
     infcx: InferCtxt<'a, 'gcx, 'tcx>,
+
     locals: RefCell<NodeMap<Ty<'tcx>>>,
 
     fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>,
@@ -174,16 +174,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // associated fresh inference variable. Writeback resolves these
     // variables to get the concrete type, which can be used to
     // deanonymize TyAnon, after typeck is done with all functions.
-    anon_types: RefCell<DefIdMap<Ty<'tcx>>>,
-
-    // Obligations which will have to be checked at the end of
-    // type-checking, after all functions have been inferred.
-    deferred_obligations: RefCell<Vec<traits::DeferredObligation<'tcx>>>,
-
-    // a set of trait import def-ids that we use during method
-    // resolution; during writeback, this is written into
-    // `tcx.used_trait_imports` for this item def-id
-    used_trait_imports: RefCell<FxHashSet<DefId>>,
+    anon_types: RefCell<NodeMap<Ty<'tcx>>>,
 }
 
 impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
@@ -425,15 +416,12 @@ pub struct EnclosingLoops<'gcx, 'tcx> {
 }
 
 impl<'gcx, 'tcx> EnclosingLoops<'gcx, 'tcx> {
-    fn find_loop(&mut self, id: Option<ast::NodeId>) -> Option<&mut LoopCtxt<'gcx, 'tcx>> {
-        if let Some(id) = id {
-            if let Some(ix) = self.by_id.get(&id).cloned() {
-                Some(&mut self.stack[ix])
-            } else {
-                None
-            }
+    fn find_loop(&mut self, id: hir::LoopIdResult) -> Option<&mut LoopCtxt<'gcx, 'tcx>> {
+        let id_res: Result<_,_> = id.into();
+        if let Some(ix) = id_res.ok().and_then(|id| self.by_id.get(&id).cloned()) {
+            Some(&mut self.stack[ix])
         } else {
-            self.stack.last_mut()
+            None
         }
     }
 }
@@ -444,10 +432,6 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
     body_id: ast::NodeId,
 
-    // This flag is set to true if, during the writeback phase, we encounter
-    // a type error in this function.
-    writeback_errors: Cell<bool>,
-
     // Number of errors that had been reported when we started
     // checking this function. On exit, if we find that *more* errors
     // have been reported, we will skip regionck and other work that
@@ -476,22 +460,20 @@ fn deref(&self) -> &Self::Target {
     }
 }
 
-/// Helper type of a temporary returned by ccx.inherited(...).
+/// Helper type of a temporary returned by Inherited::build(...).
 /// Necessary because we can't write the following bound:
 /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(Inherited<'b, 'gcx, 'tcx>).
 pub struct InheritedBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    ccx: &'a CrateCtxt<'a, 'gcx>,
     infcx: infer::InferCtxtBuilder<'a, 'gcx, 'tcx>
 }
 
-impl<'a, 'gcx, 'tcx> CrateCtxt<'a, 'gcx> {
-    pub fn inherited(&'a self, id: ast::NodeId)
-                     -> InheritedBuilder<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
+    pub fn build(tcx: TyCtxt<'a, 'gcx, 'gcx>, id: ast::NodeId)
+                 -> InheritedBuilder<'a, 'gcx, 'tcx> {
         let tables = ty::TypeckTables::empty();
-        let param_env = ParameterEnvironment::for_item(self.tcx, id);
+        let param_env = ParameterEnvironment::for_item(tcx, id);
         InheritedBuilder {
-            ccx: self,
-            infcx: self.tcx.infer_ctxt((tables, param_env), Reveal::NotSpecializable)
+            infcx: tcx.infer_ctxt((tables, param_env), Reveal::UserFacing)
         }
     }
 }
@@ -500,25 +482,19 @@ impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> {
     fn enter<F, R>(&'tcx mut self, f: F) -> R
         where F: for<'b> FnOnce(Inherited<'b, 'gcx, 'tcx>) -> R
     {
-        let ccx = self.ccx;
-        self.infcx.enter(|infcx| f(Inherited::new(ccx, infcx)))
+        self.infcx.enter(|infcx| f(Inherited::new(infcx)))
     }
 }
 
 impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
-    pub fn new(ccx: &'a CrateCtxt<'a, 'gcx>,
-               infcx: InferCtxt<'a, 'gcx, 'tcx>)
-               -> Self {
+    pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self {
         Inherited {
-            ccx: ccx,
             infcx: infcx,
             fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
             locals: RefCell::new(NodeMap()),
             deferred_call_resolutions: RefCell::new(DefIdMap()),
             deferred_cast_checks: RefCell::new(Vec::new()),
-            anon_types: RefCell::new(DefIdMap()),
-            deferred_obligations: RefCell::new(Vec::new()),
-            used_trait_imports: RefCell::new(DefIdSet()),
+            anon_types: RefCell::new(NodeMap()),
         }
     }
 
@@ -538,23 +514,23 @@ fn normalize_associated_types_in<T>(&self,
 
 }
 
-struct CheckItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
-struct CheckItemBodiesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
+struct CheckItemTypesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
+struct CheckItemBodiesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
 
 impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.ccx.tcx.hir)
+        NestedVisitorMap::OnlyBodies(&self.tcx.hir)
     }
 
     fn visit_item(&mut self, i: &'tcx hir::Item) {
-        check_item_type(self.ccx, i);
+        check_item_type(self.tcx, i);
         intravisit::walk_item(self, i);
     }
 
     fn visit_ty(&mut self, t: &'tcx hir::Ty) {
         match t.node {
             hir::TyArray(_, length) => {
-                check_const_with_type(self.ccx, length, self.ccx.tcx.types.usize, length.node_id);
+                self.tcx.item_tables(self.tcx.hir.local_def_id(length.node_id));
             }
             _ => {}
         }
@@ -565,7 +541,7 @@ fn visit_ty(&mut self, t: &'tcx hir::Ty) {
     fn visit_expr(&mut self, e: &'tcx hir::Expr) {
         match e.node {
             hir::ExprRepeat(_, count) => {
-                check_const_with_type(self.ccx, count, self.ccx.tcx.types.usize, count.node_id);
+                self.tcx.item_tables(self.tcx.hir.local_def_id(count.node_id));
             }
             _ => {}
         }
@@ -577,8 +553,8 @@ fn visit_expr(&mut self, e: &'tcx hir::Expr) {
 impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
-            hir::ItemFn(ref decl, .., body_id) => {
-                check_bare_fn(self.ccx, &decl, body_id, item.id, item.span);
+            hir::ItemFn(..) => {
+                self.tcx.item_tables(self.tcx.hir.local_def_id(item.id));
             }
             _ => { }
         }
@@ -586,11 +562,9 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
         match trait_item.node {
-            hir::TraitItemKind::Const(_, Some(expr)) => {
-                check_const(self.ccx, expr, trait_item.id)
-            }
-            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body_id)) => {
-                check_bare_fn(self.ccx, &sig.decl, body_id, trait_item.id, trait_item.span);
+            hir::TraitItemKind::Const(_, Some(_)) |
+            hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
+                self.tcx.item_tables(self.tcx.hir.local_def_id(trait_item.id));
             }
             hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
             hir::TraitItemKind::Const(_, None) |
@@ -602,11 +576,9 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
         match impl_item.node {
-            hir::ImplItemKind::Const(_, expr) => {
-                check_const(self.ccx, expr, impl_item.id)
-            }
-            hir::ImplItemKind::Method(ref sig, body_id) => {
-                check_bare_fn(self.ccx, &sig.decl, body_id, impl_item.id, impl_item.span);
+            hir::ImplItemKind::Const(..) |
+            hir::ImplItemKind::Method(..) => {
+                self.tcx.item_tables(self.tcx.hir.local_def_id(impl_item.id));
             }
             hir::ImplItemKind::Type(_) => {
                 // Nothing to do here.
@@ -615,61 +587,41 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
     }
 }
 
-pub fn check_wf_new(ccx: &CrateCtxt) -> CompileResult {
-    ccx.tcx.sess.track_errors(|| {
-        let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(ccx);
-        ccx.tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut visit.as_deep_visitor());
+pub fn check_wf_new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
+    tcx.sess.track_errors(|| {
+        let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
+        tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut visit.as_deep_visitor());
     })
 }
 
-pub fn check_item_types(ccx: &CrateCtxt) -> CompileResult {
-    ccx.tcx.sess.track_errors(|| {
-        let mut visit = CheckItemTypesVisitor { ccx: ccx };
-        ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemType,
+pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
+    tcx.sess.track_errors(|| {
+        let mut visit = CheckItemTypesVisitor { tcx: tcx };
+        tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemType,
                                               &mut visit.as_deep_visitor());
     })
 }
 
-pub fn check_item_bodies(ccx: &CrateCtxt) -> CompileResult {
-    ccx.tcx.sess.track_errors(|| {
-        let mut visit = CheckItemBodiesVisitor { ccx: ccx };
-        ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckTables, &mut visit);
-
-        // Process deferred obligations, now that all functions
-        // bodies have been fully inferred.
-        for (&item_id, obligations) in ccx.deferred_obligations.borrow().iter() {
-            // Use the same DepNode as for the body of the original function/item.
-            let def_id = ccx.tcx.hir.local_def_id(item_id);
-            let _task = ccx.tcx.dep_graph.in_task(DepNode::TypeckTables(def_id));
-
-            let param_env = ParameterEnvironment::for_item(ccx.tcx, item_id);
-            ccx.tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
-                let mut fulfillment_cx = traits::FulfillmentContext::new();
-                for obligation in obligations.iter().map(|o| o.to_obligation()) {
-                    fulfillment_cx.register_predicate_obligation(&infcx, obligation);
-                }
-
-                if let Err(errors) = fulfillment_cx.select_all_or_error(&infcx) {
-                    infcx.report_fulfillment_errors(&errors);
-                }
-            });
-        }
+pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
+    tcx.sess.track_errors(|| {
+        let mut visit = CheckItemBodiesVisitor { tcx: tcx };
+        tcx.visit_all_item_likes_in_krate(DepNode::TypeckTables, &mut visit);
     })
 }
 
-pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult {
-    ccx.tcx.sess.track_errors(|| {
-        let _task = ccx.tcx.dep_graph.in_task(DepNode::Dropck);
-        let drop_trait = match ccx.tcx.lang_items.drop_trait() {
-            Some(id) => ccx.tcx.lookup_trait_def(id), None => { return }
+pub fn check_drop_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
+    tcx.sess.track_errors(|| {
+        let _task = tcx.dep_graph.in_task(DepNode::Dropck);
+        let drop_trait = match tcx.lang_items.drop_trait() {
+            Some(id) => tcx.lookup_trait_def(id), None => { return }
         };
-        drop_trait.for_each_impl(ccx.tcx, |drop_impl_did| {
-            let _task = ccx.tcx.dep_graph.in_task(DepNode::DropckImpl(drop_impl_did));
+        drop_trait.for_each_impl(tcx, |drop_impl_did| {
+            let _task = tcx.dep_graph.in_task(DepNode::DropckImpl(drop_impl_did));
             if drop_impl_did.is_local() {
-                match dropck::check_drop_impl(ccx, drop_impl_did) {
+                match dropck::check_drop_impl(tcx, drop_impl_did) {
                     Ok(()) => {}
                     Err(()) => {
-                        assert!(ccx.tcx.sess.has_errors());
+                        assert!(tcx.sess.has_errors());
                     }
                 }
             }
@@ -677,47 +629,150 @@ pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult {
     })
 }
 
-fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                           decl: &'tcx hir::FnDecl,
-                           body_id: hir::BodyId,
-                           fn_id: ast::NodeId,
-                           span: Span) {
-    let body = ccx.tcx.hir.body(body_id);
-
-    let raw_fty = ccx.tcx.item_type(ccx.tcx.hir.local_def_id(fn_id));
-    let fn_ty = match raw_fty.sty {
-        ty::TyFnDef(.., f) => f,
-        _ => span_bug!(body.value.span, "check_bare_fn: function type expected")
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        typeck_tables,
+        closure_type,
+        closure_kind,
+        ..*providers
     };
+}
 
-    check_abi(ccx, span, fn_ty.abi);
+fn closure_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          def_id: DefId)
+                          -> ty::PolyFnSig<'tcx> {
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    tcx.item_tables(def_id).closure_tys[&node_id]
+}
 
-    ccx.inherited(fn_id).enter(|inh| {
-        // Compute the fty from point of view of inside fn.
-        let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body_id.node_id);
-        let fn_sig =
-            fn_ty.sig.subst(inh.tcx, &inh.parameter_environment.free_substs);
-        let fn_sig =
-            inh.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
-        let fn_sig =
-            inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
+fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          def_id: DefId)
+                          -> ty::ClosureKind {
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    tcx.item_tables(def_id).closure_kinds[&node_id]
+}
+
+fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                           def_id: DefId)
+                           -> &'tcx ty::TypeckTables<'tcx> {
+    // Closures' tables come from their outermost function,
+    // as they are part of the same "inference environment".
+    let outer_def_id = tcx.closure_base_def_id(def_id);
+    if outer_def_id != def_id {
+        return tcx.item_tables(outer_def_id);
+    }
+
+    let id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let span = tcx.hir.span(id);
+    let unsupported = || {
+        span_bug!(span, "can't type-check body of {:?}", def_id);
+    };
 
-        let fcx = check_fn(&inh, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body);
+    // Figure out what primary body this item has.
+    let mut fn_decl = None;
+    let body_id = match tcx.hir.get(id) {
+        hir::map::NodeItem(item) => {
+            match item.node {
+                hir::ItemConst(_, body) |
+                hir::ItemStatic(_, _, body) => body,
+                hir::ItemFn(ref decl, .., body) => {
+                    fn_decl = Some(decl);
+                    body
+                }
+                _ => unsupported()
+            }
+        }
+        hir::map::NodeTraitItem(item) => {
+            match item.node {
+                hir::TraitItemKind::Const(_, Some(body)) => body,
+                hir::TraitItemKind::Method(ref sig,
+                    hir::TraitMethod::Provided(body)) => {
+                        fn_decl = Some(&sig.decl);
+                        body
+                    }
+                _ => unsupported()
+            }
+        }
+        hir::map::NodeImplItem(item) => {
+            match item.node {
+                hir::ImplItemKind::Const(_, body) => body,
+                hir::ImplItemKind::Method(ref sig, body) => {
+                    fn_decl = Some(&sig.decl);
+                    body
+                }
+                _ => unsupported()
+            }
+        }
+        hir::map::NodeExpr(expr) => {
+            // FIXME(eddyb) Closures should have separate
+            // function definition IDs and expression IDs.
+            // Type-checking should not let closures get
+            // this far in a constant position.
+            // Assume that everything other than closures
+            // is a constant "initializer" expression.
+            match expr.node {
+                hir::ExprClosure(..) => {
+                    // We should've bailed out above for closures.
+                    span_bug!(expr.span, "unexpected closure")
+                }
+                _ => hir::BodyId { node_id: expr.id }
+            }
+        }
+        _ => unsupported()
+    };
+    let body = tcx.hir.body(body_id);
+
+    Inherited::build(tcx, id).enter(|inh| {
+        let fcx = if let Some(decl) = fn_decl {
+            let fn_sig = tcx.item_type(def_id).fn_sig();
+
+            check_abi(tcx, span, fn_sig.abi());
+
+            // Compute the fty from point of view of inside fn.
+            let fn_scope = inh.tcx.region_maps.call_site_extent(id, body_id.node_id);
+            let fn_sig =
+                fn_sig.subst(inh.tcx, &inh.parameter_environment.free_substs);
+            let fn_sig =
+                inh.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
+            let fn_sig =
+                inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
+
+            check_fn(&inh, fn_sig, decl, id, body)
+        } else {
+            let expected_type = tcx.item_type(def_id);
+            let fcx = FnCtxt::new(&inh, None, body.value.id);
+            fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
+
+            // Gather locals in statics (because of block expressions).
+            // This is technically unnecessary because locals in static items are forbidden,
+            // but prevents type checking from blowing up before const checking can properly
+            // emit an error.
+            GatherLocalsVisitor { fcx: &fcx }.visit_body(body);
+
+            fcx.check_expr_coercable_to_type(&body.value, expected_type);
+
+            fcx
+        };
 
         fcx.select_all_obligations_and_apply_defaults();
         fcx.closure_analyze(body);
         fcx.select_obligations_where_possible();
         fcx.check_casts();
-        fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
+        fcx.select_all_obligations_or_error();
+
+        if fn_decl.is_some() {
+            fcx.regionck_fn(id, body);
+        } else {
+            fcx.regionck_expr(body);
+        }
 
-        fcx.regionck_fn(fn_id, body);
-        fcx.resolve_type_vars_in_body(body);
-    });
+        fcx.resolve_type_vars_in_body(body)
+    })
 }
 
-fn check_abi<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, abi: Abi) {
-    if !ccx.tcx.sess.target.target.is_abi_supported(abi) {
-        struct_span_err!(ccx.tcx.sess, span, E0570,
+fn check_abi<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, abi: Abi) {
+    if !tcx.sess.target.target.is_abi_supported(abi) {
+        struct_span_err!(tcx.sess, span, E0570,
             "The ABI `{}` is not supported for the current target", abi).emit()
     }
 }
@@ -785,16 +840,14 @@ fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
                 _: hir::BodyId, _: Span, _: ast::NodeId) { }
 }
 
-/// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function
+/// Helper used for fns and closures. Does the grungy work of checking a function
 /// body and returns the function context used for that purpose, since in the case of a fn item
 /// there is still a bit more to do.
 ///
 /// * ...
 /// * inherited: other fields inherited from the enclosing fn (if any)
 fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
-                            unsafety: hir::Unsafety,
-                            unsafety_id: ast::NodeId,
-                            fn_sig: &ty::FnSig<'tcx>,
+                            fn_sig: ty::FnSig<'tcx>,
                             decl: &'gcx hir::FnDecl,
                             fn_id: ast::NodeId,
                             body: &'gcx hir::Body)
@@ -808,12 +861,17 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     // in the case of function expressions, based on the outer context.
     let mut fcx = FnCtxt::new(inherited, None, body.value.id);
     let ret_ty = fn_sig.output();
-    *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
+    *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
 
     fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
     fcx.ret_ty = fcx.instantiate_anon_types(&Some(ret_ty));
-    fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty.unwrap(),
-                               fn_sig.variadic);
+    fn_sig = fcx.tcx.mk_fn_sig(
+        fn_sig.inputs().iter().cloned(),
+        fcx.ret_ty.unwrap(),
+        fn_sig.variadic,
+        fn_sig.unsafety,
+        fn_sig.abi
+    );
 
     GatherLocalsVisitor { fcx: &fcx, }.visit_body(body);
 
@@ -839,30 +897,36 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     fcx
 }
 
-fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
-    let def_id = ccx.tcx.hir.local_def_id(id);
-    check_representable(ccx.tcx, span, def_id);
+fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          id: ast::NodeId,
+                          span: Span) {
+    let def_id = tcx.hir.local_def_id(id);
+    check_representable(tcx, span, def_id);
 
-    if ccx.tcx.lookup_simd(def_id) {
-        check_simd(ccx.tcx, span, def_id);
+    if tcx.lookup_adt_def(def_id).repr.simd {
+        check_simd(tcx, span, def_id);
     }
 }
 
-fn check_union(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
-    check_representable(ccx.tcx, span, ccx.tcx.hir.local_def_id(id));
+fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                         id: ast::NodeId,
+                         span: Span) {
+    check_representable(tcx, span, tcx.hir.local_def_id(id));
 }
 
-pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
+pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) {
     debug!("check_item_type(it.id={}, it.name={})",
            it.id,
-           ccx.tcx.item_path_str(ccx.tcx.hir.local_def_id(it.id)));
+           tcx.item_path_str(tcx.hir.local_def_id(it.id)));
     let _indenter = indenter();
     match it.node {
       // Consts can play a role in type-checking, so they are included here.
-      hir::ItemStatic(.., e) |
-      hir::ItemConst(_, e) => check_const(ccx, e, it.id),
+      hir::ItemStatic(..) |
+      hir::ItemConst(..) => {
+        tcx.item_tables(tcx.hir.local_def_id(it.id));
+      }
       hir::ItemEnum(ref enum_definition, _) => {
-        check_enum_variants(ccx,
+        check_enum_variants(tcx,
                             it.span,
                             &enum_definition.variants,
                             it.id);
@@ -870,48 +934,48 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
       hir::ItemFn(..) => {} // entirely within check_item_body
       hir::ItemImpl(.., ref impl_item_refs) => {
           debug!("ItemImpl {} with id {}", it.name, it.id);
-          let impl_def_id = ccx.tcx.hir.local_def_id(it.id);
-          if let Some(impl_trait_ref) = ccx.tcx.impl_trait_ref(impl_def_id) {
-              check_impl_items_against_trait(ccx,
+          let impl_def_id = tcx.hir.local_def_id(it.id);
+          if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) {
+              check_impl_items_against_trait(tcx,
                                              it.span,
                                              impl_def_id,
                                              impl_trait_ref,
                                              impl_item_refs);
               let trait_def_id = impl_trait_ref.def_id;
-              check_on_unimplemented(ccx, trait_def_id, it);
+              check_on_unimplemented(tcx, trait_def_id, it);
           }
       }
       hir::ItemTrait(..) => {
-        let def_id = ccx.tcx.hir.local_def_id(it.id);
-        check_on_unimplemented(ccx, def_id, it);
+        let def_id = tcx.hir.local_def_id(it.id);
+        check_on_unimplemented(tcx, def_id, it);
       }
       hir::ItemStruct(..) => {
-        check_struct(ccx, it.id, it.span);
+        check_struct(tcx, it.id, it.span);
       }
       hir::ItemUnion(..) => {
-        check_union(ccx, it.id, it.span);
+        check_union(tcx, it.id, it.span);
       }
       hir::ItemTy(_, ref generics) => {
-        let def_id = ccx.tcx.hir.local_def_id(it.id);
-        let pty_ty = ccx.tcx.item_type(def_id);
-        check_bounds_are_used(ccx, generics, pty_ty);
+        let def_id = tcx.hir.local_def_id(it.id);
+        let pty_ty = tcx.item_type(def_id);
+        check_bounds_are_used(tcx, generics, pty_ty);
       }
       hir::ItemForeignMod(ref m) => {
-        check_abi(ccx, it.span, m.abi);
+        check_abi(tcx, it.span, m.abi);
 
         if m.abi == Abi::RustIntrinsic {
             for item in &m.items {
-                intrinsic::check_intrinsic_type(ccx, item);
+                intrinsic::check_intrinsic_type(tcx, item);
             }
         } else if m.abi == Abi::PlatformIntrinsic {
             for item in &m.items {
-                intrinsic::check_platform_intrinsic_type(ccx, item);
+                intrinsic::check_platform_intrinsic_type(tcx, item);
             }
         } else {
             for item in &m.items {
-                let generics = ccx.tcx.item_generics(ccx.tcx.hir.local_def_id(item.id));
+                let generics = tcx.item_generics(tcx.hir.local_def_id(item.id));
                 if !generics.types.is_empty() {
-                    let mut err = struct_span_err!(ccx.tcx.sess, item.span, E0044,
+                    let mut err = struct_span_err!(tcx.sess, item.span, E0044,
                         "foreign items may not have type parameters");
                     span_help!(&mut err, item.span,
                         "consider using specialization instead of \
@@ -920,7 +984,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
                 }
 
                 if let hir::ForeignItemFn(ref fn_decl, _, _) = item.node {
-                    require_c_abi_if_variadic(ccx.tcx, fn_decl, m.abi, item.span);
+                    require_c_abi_if_variadic(tcx, fn_decl, m.abi, item.span);
                 }
             }
         }
@@ -929,10 +993,10 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
     }
 }
 
-fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn check_on_unimplemented<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     def_id: DefId,
                                     item: &hir::Item) {
-    let generics = ccx.tcx.item_generics(def_id);
+    let generics = tcx.item_generics(def_id);
     if let Some(ref attr) = item.attrs.iter().find(|a| {
         a.check_name("rustc_on_unimplemented")
     }) {
@@ -952,8 +1016,8 @@ fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         }) {
                             Some(_) => (),
                             None => {
-                                let name = ccx.tcx.item_name(def_id);
-                                span_err!(ccx.tcx.sess, attr.span, E0230,
+                                let name = tcx.item_name(def_id);
+                                span_err!(tcx.sess, attr.span, E0230,
                                                  "there is no type parameter \
                                                           {} on trait {}",
                                                            s, name);
@@ -961,7 +1025,7 @@ fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         },
                         // `{:1}` and `{}` are not to be used
                         Position::ArgumentIs(_) => {
-                            span_err!(ccx.tcx.sess, attr.span, E0231,
+                            span_err!(tcx.sess, attr.span, E0231,
                                                   "only named substitution \
                                                    parameters are allowed");
                         }
@@ -970,7 +1034,7 @@ fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             }
         } else {
             struct_span_err!(
-                ccx.tcx.sess, attr.span, E0232,
+                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\"]`"))
@@ -1028,7 +1092,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
 }
 
-fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                             impl_span: Span,
                                             impl_id: DefId,
                                             impl_trait_ref: ty::TraitRef<'tcx>,
@@ -1039,11 +1103,10 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     if impl_trait_ref.references_error() { return; }
 
     // Locate trait definition and items
-    let tcx = ccx.tcx;
     let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id);
     let mut overridden_associated_type = None;
 
-    let impl_items = || impl_item_refs.iter().map(|iiref| ccx.tcx.hir.impl_item(iiref.id));
+    let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir.impl_item(iiref.id));
 
     // Check existing impl methods to see if they are both present in trait
     // and compatible with trait signature
@@ -1058,7 +1121,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 hir::ImplItemKind::Const(..) => {
                     // Find associated const definition.
                     if ty_trait_item.kind == ty::AssociatedKind::Const {
-                        compare_const_impl(ccx,
+                        compare_const_impl(tcx,
                                            &ty_impl_item,
                                            impl_item.span,
                                            &ty_trait_item,
@@ -1082,7 +1145,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                     let trait_span = tcx.hir.span_if_local(ty_trait_item.def_id);
                     if ty_trait_item.kind == ty::AssociatedKind::Method {
                         let err_count = tcx.sess.err_count();
-                        compare_impl_method(ccx,
+                        compare_impl_method(tcx,
                                             &ty_impl_item,
                                             impl_item.span,
                                             body_id.node_id,
@@ -1092,7 +1155,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                             true); // start with old-broken-mode
                         if err_count == tcx.sess.err_count() {
                             // old broken mode did not report an error. Try with the new mode.
-                            compare_impl_method(ccx,
+                            compare_impl_method(tcx,
                                                 &ty_impl_item,
                                                 impl_item.span,
                                                 body_id.node_id,
@@ -1204,42 +1267,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-/// Checks a constant with a given type.
-fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
-                                   body: hir::BodyId,
-                                   expected_type: Ty<'tcx>,
-                                   id: ast::NodeId) {
-    let body = ccx.tcx.hir.body(body);
-    ccx.inherited(id).enter(|inh| {
-        let fcx = FnCtxt::new(&inh, None, body.value.id);
-        fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
-
-        // Gather locals in statics (because of block expressions).
-        // This is technically unnecessary because locals in static items are forbidden,
-        // but prevents type checking from blowing up before const checking can properly
-        // emit an error.
-        GatherLocalsVisitor { fcx: &fcx }.visit_body(body);
-
-        fcx.check_expr_coercable_to_type(&body.value, expected_type);
-
-        fcx.select_all_obligations_and_apply_defaults();
-        fcx.closure_analyze(body);
-        fcx.select_obligations_where_possible();
-        fcx.check_casts();
-        fcx.select_all_obligations_or_error();
-
-        fcx.regionck_expr(body);
-        fcx.resolve_type_vars_in_body(body);
-    });
-}
-
-fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                         body: hir::BodyId,
-                         id: ast::NodeId) {
-    let decl_ty = ccx.tcx.item_type(ccx.tcx.hir.local_def_id(id));
-    check_const_with_type(ccx, body, decl_ty, id);
-}
-
 /// Checks whether a type can be represented in memory. In particular, it
 /// identifies types that contain themselves without indirection through a
 /// pointer, which would mean their size is unbounded.
@@ -1295,64 +1322,59 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId
 }
 
 #[allow(trivial_numeric_casts)]
-pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                                    sp: Span,
-                                    vs: &'tcx [hir::Variant],
-                                    id: ast::NodeId) {
-    let def_id = ccx.tcx.hir.local_def_id(id);
-    let hint = *ccx.tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny);
-
-    if hint != attr::ReprAny && vs.is_empty() {
+pub fn check_enum_variants<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                     sp: Span,
+                                     vs: &'tcx [hir::Variant],
+                                     id: ast::NodeId) {
+    let def_id = tcx.hir.local_def_id(id);
+    let def = tcx.lookup_adt_def(def_id);
+
+    if vs.is_empty() && tcx.has_attr(def_id, "repr") {
         struct_span_err!(
-            ccx.tcx.sess, sp, E0084,
+            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);
-    if repr_type_ty == ccx.tcx.types.i128 || repr_type_ty == ccx.tcx.types.u128 {
-        if !ccx.tcx.sess.features.borrow().i128_type {
-            emit_feature_err(&ccx.tcx.sess.parse_sess,
+    let repr_type_ty = def.repr.discr_type().to_ty(tcx);
+    if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
+        if !tcx.sess.features.borrow().i128_type {
+            emit_feature_err(&tcx.sess.parse_sess,
                              "i128_type", sp, GateIssue::Language, "128-bit type is unstable");
         }
     }
 
     for v in vs {
         if let Some(e) = v.node.disr_expr {
-            check_const_with_type(ccx, e, repr_type_ty, e.node_id);
+            tcx.item_tables(tcx.hir.local_def_id(e.node_id));
         }
     }
 
-    let def_id = ccx.tcx.hir.local_def_id(id);
-
-    let variants = &ccx.tcx.lookup_adt_def(def_id).variants;
-    let mut disr_vals: Vec<ty::Disr> = Vec::new();
-    for (v, variant) in vs.iter().zip(variants.iter()) {
-        let current_disr_val = variant.disr_val;
-
+    let mut disr_vals: Vec<ConstInt> = Vec::new();
+    for (discr, v) in def.discriminants(tcx).zip(vs) {
         // Check for duplicate discriminant values
-        if let Some(i) = disr_vals.iter().position(|&x| x == current_disr_val) {
-            let variant_i_node_id = ccx.tcx.hir.as_local_node_id(variants[i].did).unwrap();
-            let variant_i = ccx.tcx.hir.expect_variant(variant_i_node_id);
+        if let Some(i) = disr_vals.iter().position(|&x| x == discr) {
+            let variant_i_node_id = tcx.hir.as_local_node_id(def.variants[i].did).unwrap();
+            let variant_i = tcx.hir.expect_variant(variant_i_node_id);
             let i_span = match variant_i.node.disr_expr {
-                Some(expr) => ccx.tcx.hir.span(expr.node_id),
-                None => ccx.tcx.hir.span(variant_i_node_id)
+                Some(expr) => tcx.hir.span(expr.node_id),
+                None => tcx.hir.span(variant_i_node_id)
             };
             let span = match v.node.disr_expr {
-                Some(expr) => ccx.tcx.hir.span(expr.node_id),
+                Some(expr) => tcx.hir.span(expr.node_id),
                 None => v.span
             };
-            struct_span_err!(ccx.tcx.sess, span, E0081,
+            struct_span_err!(tcx.sess, span, E0081,
                              "discriminant value `{}` already exists", disr_vals[i])
                 .span_label(i_span, &format!("first use of `{}`", disr_vals[i]))
                 .span_label(span , &format!("enum already has `{}`", disr_vals[i]))
                 .emit();
         }
-        disr_vals.push(current_disr_val);
+        disr_vals.push(discr);
     }
 
-    check_representable(ccx.tcx, sp, def_id);
+    check_representable(tcx, sp, def_id);
 }
 
 impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
@@ -1362,57 +1384,30 @@ fn ast_ty_to_ty_cache(&self) -> &RefCell<NodeMap<Ty<'tcx>>> {
         &self.ast_ty_to_ty_cache
     }
 
-    fn get_generics(&self, _: Span, id: DefId)
-                    -> Result<&'tcx ty::Generics<'tcx>, ErrorReported>
-    {
-        Ok(self.tcx().item_generics(id))
-    }
-
-    fn get_item_type(&self, _: Span, id: DefId) -> Result<Ty<'tcx>, ErrorReported>
-    {
-        Ok(self.tcx().item_type(id))
-    }
-
-    fn get_trait_def(&self, _: Span, id: DefId)
-                     -> Result<&'tcx ty::TraitDef, ErrorReported>
-    {
-        Ok(self.tcx().lookup_trait_def(id))
-    }
-
-    fn ensure_super_predicates(&self, _: Span, _: DefId) -> Result<(), ErrorReported> {
-        // all super predicates are ensured during collect pass
-        Ok(())
-    }
-
     fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
         Some(&self.parameter_environment.free_substs)
     }
 
-    fn get_type_parameter_bounds(&self,
-                                 _: Span,
-                                 node_id: ast::NodeId)
-                                 -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
+    fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
+                                 -> ty::GenericPredicates<'tcx>
     {
-        let def = self.tcx.type_parameter_def(node_id);
-        let r = self.parameter_environment
-                                  .caller_bounds
-                                  .iter()
-                                  .filter_map(|predicate| {
-                                      match *predicate {
-                                          ty::Predicate::Trait(ref data) => {
-                                              if data.0.self_ty().is_param(def.index) {
-                                                  Some(data.to_poly_trait_ref())
-                                              } else {
-                                                  None
-                                              }
-                                          }
-                                          _ => {
-                                              None
-                                          }
-                                      }
-                                  })
-                                  .collect();
-        Ok(r)
+        let tcx = self.tcx;
+        let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+        let item_id = tcx.hir.ty_param_owner(node_id);
+        let item_def_id = tcx.hir.local_def_id(item_id);
+        let generics = tcx.item_generics(item_def_id);
+        let index = generics.type_param_to_index[&def_id.index];
+        ty::GenericPredicates {
+            parent: None,
+            predicates: self.parameter_environment.caller_bounds.iter().filter(|predicate| {
+                match **predicate {
+                    ty::Predicate::Trait(ref data) => {
+                        data.0.self_ty().is_param(index)
+                    }
+                    _ => false
+                }
+            }).cloned().collect()
+        }
     }
 
     fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>)
@@ -1429,7 +1424,7 @@ fn ty_infer(&self, span: Span) -> Ty<'tcx> {
     }
 
     fn ty_infer_for_def(&self,
-                        ty_param_def: &ty::TypeParameterDef<'tcx>,
+                        ty_param_def: &ty::TypeParameterDef,
                         substs: &[Kind<'tcx>],
                         span: Span) -> Ty<'tcx> {
         self.type_var_for_def(span, ty_param_def, substs)
@@ -1494,7 +1489,6 @@ pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>,
         FnCtxt {
             ast_ty_to_ty_cache: RefCell::new(NodeMap()),
             body_id: body_id,
-            writeback_errors: Cell::new(false),
             err_count_on_creation: inh.tcx.sess.err_count(),
             ret_ty: rty,
             ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal,
@@ -1509,10 +1503,6 @@ pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>,
         }
     }
 
-    pub fn param_env(&self) -> &ty::ParameterEnvironment<'gcx> {
-        &self.parameter_environment
-    }
-
     pub fn sess(&self) -> &Session {
         &self.tcx.sess
     }
@@ -1614,6 +1604,7 @@ pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) {
 
         if ty.references_error() {
             self.has_errors.set(true);
+            self.set_tainted_by_errors();
         }
 
         // FIXME(canndrew): This is_never should probably be an is_uninhabited
@@ -1701,12 +1692,13 @@ fn instantiate_anon_types<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
             if let ty::TyAnon(def_id, substs) = ty.sty {
                 // Use the same type variable if the exact same TyAnon appears more
                 // than once in the return type (e.g. if it's pased to a type alias).
-                if let Some(ty_var) = self.anon_types.borrow().get(&def_id) {
+                let id = self.tcx.hir.as_local_node_id(def_id).unwrap();
+                if let Some(ty_var) = self.anon_types.borrow().get(&id) {
                     return ty_var;
                 }
                 let span = self.tcx.def_span(def_id);
                 let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span));
-                self.anon_types.borrow_mut().insert(def_id, ty_var);
+                self.anon_types.borrow_mut().insert(id, ty_var);
 
                 let item_predicates = self.tcx.item_predicates(def_id);
                 let bounds = item_predicates.instantiate(self.tcx, substs);
@@ -1759,10 +1751,6 @@ pub fn write_nil(&self, node_id: ast::NodeId) {
         self.write_ty(node_id, self.tcx.mk_nil());
     }
 
-    pub fn write_never(&self, node_id: ast::NodeId) {
-        self.write_ty(node_id, self.tcx.types.never);
-    }
-
     pub fn write_error(&self, node_id: ast::NodeId) {
         self.write_ty(node_id, self.tcx.types.err);
     }
@@ -2245,11 +2233,6 @@ fn select_all_obligations_or_error(&self) {
 
         let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
 
-        // Steal the deferred obligations before the fulfillment
-        // context can turn all of them into errors.
-        let obligations = fulfillment_cx.take_deferred_obligations();
-        self.deferred_obligations.borrow_mut().extend(obligations);
-
         match fulfillment_cx.select_all_or_error(self) {
             Ok(()) => { }
             Err(errors) => { self.report_fulfillment_errors(&errors); }
@@ -2423,13 +2406,13 @@ fn check_method_argument_types(&self,
                     let expected_arg_tys = self.expected_types_for_fn_args(
                         sp,
                         expected,
-                        fty.sig.0.output(),
-                        &fty.sig.0.inputs()[1..]
+                        fty.0.output(),
+                        &fty.0.inputs()[1..]
                     );
-                    self.check_argument_types(sp, &fty.sig.0.inputs()[1..], &expected_arg_tys[..],
-                                              args_no_rcvr, fty.sig.0.variadic, tuple_arguments,
+                    self.check_argument_types(sp, &fty.0.inputs()[1..], &expected_arg_tys[..],
+                                              args_no_rcvr, fty.0.variadic, tuple_arguments,
                                               self.tcx.hir.span_if_local(def_id));
-                    fty.sig.0.output()
+                    fty.0.output()
                 }
                 _ => {
                     span_bug!(callee_expr.span, "method without bare fn type");
@@ -3596,10 +3579,9 @@ fn check_expr_kind(&self,
               tcx.mk_nil()
           }
           hir::ExprBreak(label, ref expr_opt) => {
-            let loop_id = label.map(|l| l.loop_id);
             let coerce_to = {
                 let mut enclosing_loops = self.enclosing_loops.borrow_mut();
-                enclosing_loops.find_loop(loop_id).map(|ctxt| ctxt.coerce_to)
+                enclosing_loops.find_loop(label.loop_id).map(|ctxt| ctxt.coerce_to)
             };
             if let Some(coerce_to) = coerce_to {
                 let e_ty;
@@ -3614,8 +3596,9 @@ fn check_expr_kind(&self,
                     e_ty = tcx.mk_nil();
                     cause = self.misc(expr.span);
                 }
+
                 let mut enclosing_loops = self.enclosing_loops.borrow_mut();
-                let ctxt = enclosing_loops.find_loop(loop_id).unwrap();
+                let ctxt = enclosing_loops.find_loop(label.loop_id).unwrap();
 
                 let result = if let Some(ref e) = *expr_opt {
                     // Special-case the first element, as it has no "previous expressions".
@@ -4308,7 +4291,7 @@ pub fn instantiate_value_path(&self,
                 let container = self.tcx.associated_item(def_id).container;
                 match container {
                     ty::TraitContainer(trait_did) => {
-                        callee::check_legal_trait_for_method_call(self.ccx, span, trait_did)
+                        callee::check_legal_trait_for_method_call(self.tcx, span, trait_did)
                     }
                     ty::ImplContainer(_) => {}
                 }
@@ -4339,7 +4322,7 @@ pub fn instantiate_value_path(&self,
         // errors if type parameters are provided in an inappropriate place.
         let poly_segments = type_segment.is_some() as usize +
                             fn_segment.is_some() as usize;
-        self.tcx.prohibit_type_params(&segments[..segments.len() - poly_segments]);
+        AstConv::prohibit_type_params(self, &segments[..segments.len() - poly_segments]);
 
         match def {
             Def::Local(def_id) | Def::Upvar(def_id, ..) => {
@@ -4426,8 +4409,9 @@ pub fn instantiate_value_path(&self,
             if let Some(ast_ty) = types.get(i) {
                 // A provided type parameter.
                 self.to_ty(ast_ty)
-            } else if let (false, Some(default)) = (infer_types, def.default) {
+            } else if !infer_types && def.has_default {
                 // No type parameter provided, but a default exists.
+                let default = self.tcx.item_type(def.def_id);
                 default.subst_spanned(self.tcx, substs, Some(span))
             } else {
                 // No type parameters were provided, we can infer all.
@@ -4540,9 +4524,7 @@ fn check_path_parameter_count(&self,
                 &generics.types
             }
         });
-        let required_len = type_defs.iter()
-                                    .take_while(|d| d.default.is_none())
-                                    .count();
+        let required_len = type_defs.iter().take_while(|d| !d.has_default).count();
         if types.len() > type_defs.len() {
             let span = types[type_defs.len()].span;
             let expected_text = count_type_params(type_defs.len());
@@ -4630,7 +4612,7 @@ fn with_loop_ctxt<F: FnOnce()>(&self, id: ast::NodeId, ctxt: LoopCtxt<'gcx, 'tcx
     }
 }
 
-pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                        generics: &hir::Generics,
                                        ty: Ty<'tcx>) {
     debug!("check_bounds_are_used(n_tps={}, ty={:?})",
@@ -4649,7 +4631,7 @@ pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     for (&used, param) in tps_used.iter().zip(&generics.ty_params) {
         if !used {
-            struct_span_err!(ccx.tcx.sess, param.span, E0091,
+            struct_span_err!(tcx.sess, param.span, E0091,
                 "type parameter `{}` is unused",
                 param.name)
                 .span_label(param.span, &format!("unused type parameter"))
index d84e9d3fd3731d642efee92e57d2565ef30badc2..e1067d299fa01b8d3f387e367f65c7435e4c996c 100644 (file)
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::{self, PatKind};
 
-use self::SubjectNode::Subject;
-
 // a variation on try that just returns unit
 macro_rules! ignore_err {
     ($e:expr) => (match $e { Ok(e) => e, Err(_) => return () })
@@ -183,7 +181,7 @@ pub struct RegionCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     repeating_scope: ast::NodeId,
 
     // id of AST node being analyzed (the subject of the analysis).
-    subject: SubjectNode,
+    subject: ast::NodeId,
 
 }
 
@@ -195,14 +193,13 @@ fn deref(&self) -> &Self::Target {
 }
 
 pub struct RepeatingScope(ast::NodeId);
-pub enum SubjectNode { Subject(ast::NodeId), None }
+pub struct Subject(ast::NodeId);
 
 impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     pub fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
-               initial_repeating_scope: RepeatingScope,
+               RepeatingScope(initial_repeating_scope): RepeatingScope,
                initial_body_id: ast::NodeId,
-               subject: SubjectNode) -> RegionCtxt<'a, 'gcx, 'tcx> {
-        let RepeatingScope(initial_repeating_scope) = initial_repeating_scope;
+               Subject(subject): Subject) -> RegionCtxt<'a, 'gcx, 'tcx> {
         RegionCtxt {
             fcx: fcx,
             repeating_scope: initial_repeating_scope,
@@ -416,13 +413,7 @@ fn relate_free_regions(&mut self,
     }
 
     fn resolve_regions_and_report_errors(&self) {
-        let subject_node_id = match self.subject {
-            Subject(s) => s,
-            SubjectNode::None => {
-                bug!("cannot resolve_regions_and_report_errors \
-                      without subject node");
-            }
-        };
+        let subject_node_id = self.subject;
 
         self.fcx.resolve_regions_and_report_errors(&self.free_region_map,
                                                    subject_node_id);
@@ -936,7 +927,7 @@ fn constrain_autoderefs(&mut self,
                     // was applied on the base type, as that is always the case.
                     let fn_sig = method.ty.fn_sig();
                     let fn_sig = // late-bound regions should have been instantiated
-                        self.tcx.no_late_bound_regions(fn_sig).unwrap();
+                        self.tcx.no_late_bound_regions(&fn_sig).unwrap();
                     let self_ty = fn_sig.inputs()[0];
                     let (m, r) = match self_ty.sty {
                         ty::TyRef(r, ref m) => (m.mutbl, r),
index c2f64b1bd7906187da4c2ae583e3afaafe4ce074..7b14684267173e6fc2492bf662aee95a5cfc6227 100644 (file)
@@ -208,9 +208,9 @@ fn analyze_closure(&mut self,
 
         // If we are also inferred the closure kind here, update the
         // main table and process any deferred resolutions.
-        let closure_def_id = self.fcx.tcx.hir.local_def_id(id);
         if let Some(&kind) = self.temp_closure_kinds.get(&id) {
             self.fcx.tables.borrow_mut().closure_kinds.insert(id, kind);
+            let closure_def_id = self.fcx.tcx.hir.local_def_id(id);
             debug!("closure_kind({:?}) = {:?}", closure_def_id, kind);
 
             let mut deferred_call_resolutions =
index cef6a75e58dc9bdddfe8f1961a9450e2a7c7eff7..a4cb4071b4d88c319a88c59eda07db3e9866b4b0 100644 (file)
@@ -9,9 +9,8 @@
 // except according to those terms.
 
 use astconv::ExplicitSelf;
-use check::FnCtxt;
+use check::{Inherited, FnCtxt};
 use constrained_type_params::{identify_constrained_type_params, Parameter};
-use CrateCtxt;
 
 use hir::def_id::DefId;
 use middle::region::{CodeExtent};
@@ -27,8 +26,8 @@
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir;
 
-pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
-    ccx: &'ccx CrateCtxt<'ccx, 'tcx>,
+pub struct CheckTypeWellFormedVisitor<'a, 'tcx:'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     code: ObligationCauseCode<'tcx>,
 }
 
@@ -51,9 +50,9 @@ fn with_fcx<F>(&'tcx mut self, f: F) where
         let id = self.id;
         let span = self.span;
         self.inherited.enter(|inh| {
-            let fcx = FnCtxt::new(&inh, Some(inh.ccx.tcx.types.never), id);
+            let fcx = FnCtxt::new(&inh, None, id);
             let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor {
-                ccx: fcx.ccx,
+                tcx: fcx.tcx.global_tcx(),
                 code: code
             });
             fcx.select_all_obligations_or_error();
@@ -62,19 +61,15 @@ fn with_fcx<F>(&'tcx mut self, f: F) where
     }
 }
 
-impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
-    pub fn new(ccx: &'ccx CrateCtxt<'ccx, 'gcx>)
-               -> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
+impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
+    pub fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>)
+               -> CheckTypeWellFormedVisitor<'a, 'gcx> {
         CheckTypeWellFormedVisitor {
-            ccx: ccx,
+            tcx: tcx,
             code: ObligationCauseCode::MiscObligation
         }
     }
 
-    fn tcx(&self) -> TyCtxt<'ccx, 'gcx, 'gcx> {
-        self.ccx.tcx
-    }
-
     /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are
     /// well-formed, meaning that they do not require any constraints not declared in the struct
     /// definition itself. For example, this definition would be illegal:
@@ -87,10 +82,10 @@ fn tcx(&self) -> TyCtxt<'ccx, 'gcx, 'gcx> {
     /// not included it frequently leads to confusing errors in fn bodies. So it's better to check
     /// the types first.
     fn check_item_well_formed(&mut self, item: &hir::Item) {
-        let ccx = self.ccx;
+        let tcx = self.tcx;
         debug!("check_item_well_formed(it.id={}, it.name={})",
                item.id,
-               ccx.tcx.item_path_str(ccx.tcx.hir.local_def_id(item.id)));
+               tcx.item_path_str(tcx.hir.local_def_id(item.id)));
 
         match item.node {
             /// Right now we check that every default trait implementation
@@ -117,9 +112,9 @@ fn check_item_well_formed(&mut self, item: &hir::Item) {
             hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), ..) => {
                 // FIXME(#27579) what amount of WF checking do we need for neg impls?
 
-                let trait_ref = ccx.tcx.impl_trait_ref(ccx.tcx.hir.local_def_id(item.id)).unwrap();
-                if !ccx.tcx.trait_has_default_impl(trait_ref.def_id) {
-                    error_192(ccx, item.span);
+                let trait_ref = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)).unwrap();
+                if !tcx.trait_has_default_impl(trait_ref.def_id) {
+                    error_192(tcx, item.span);
                 }
             }
             hir::ItemFn(.., body_id) => {
@@ -187,11 +182,8 @@ fn check_associated_item(&mut self,
                     let method_ty = fcx.tcx.item_type(item.def_id);
                     let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method_ty);
                     let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs);
-                    let fty = match method_ty.sty {
-                        ty::TyFnDef(_, _, f) => f,
-                        _ => bug!()
-                    };
-                    this.check_fn_or_method(fcx, span, fty, &predicates,
+                    let sig = method_ty.fn_sig();
+                    this.check_fn_or_method(fcx, span, sig, &predicates,
                                             free_id_outlive, &mut implied_bounds);
                     let sig_if_method = sig_if_method.expect("bad signature for method");
                     this.check_method_receiver(fcx, sig_if_method, &item,
@@ -211,14 +203,14 @@ fn check_associated_item(&mut self,
     }
 
     fn for_item<'tcx>(&self, item: &hir::Item)
-                      -> CheckWfFcxBuilder<'ccx, 'gcx, 'tcx> {
+                      -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
         self.for_id(item.id, item.span)
     }
 
     fn for_id<'tcx>(&self, id: ast::NodeId, span: Span)
-                    -> CheckWfFcxBuilder<'ccx, 'gcx, 'tcx> {
+                    -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
         CheckWfFcxBuilder {
-            inherited: self.ccx.inherited(id),
+            inherited: Inherited::build(self.tcx, id),
             code: self.code.clone(),
             id: id,
             span: span
@@ -270,7 +262,7 @@ fn check_auto_trait(&mut self, trait_def_id: DefId, span: Span) {
         //
         // 3) that the trait definition does not have any type parameters
 
-        let predicates = self.tcx().item_predicates(trait_def_id);
+        let predicates = self.tcx.item_predicates(trait_def_id);
 
         // We must exclude the Self : Trait predicate contained by all
         // traits.
@@ -285,7 +277,7 @@ fn check_auto_trait(&mut self, trait_def_id: DefId, span: Span) {
                 }
             });
 
-        let has_ty_params = self.tcx().item_generics(trait_def_id).types.len() > 1;
+        let has_ty_params = self.tcx.item_generics(trait_def_id).types.len() > 1;
 
         // We use an if-else here, since the generics will also trigger
         // an extraneous error message when we find predicates like
@@ -296,14 +288,14 @@ fn check_auto_trait(&mut self, trait_def_id: DefId, span: Span) {
         // extraneous predicates created by things like
         // an associated type inside the trait.
         let mut err = None;
-        if !self.tcx().associated_item_def_ids(trait_def_id).is_empty() {
-            error_380(self.ccx, span);
+        if !self.tcx.associated_item_def_ids(trait_def_id).is_empty() {
+            error_380(self.tcx, span);
         } else if has_ty_params {
-            err = Some(struct_span_err!(self.tcx().sess, span, E0567,
+            err = Some(struct_span_err!(self.tcx.sess, span, E0567,
                 "traits with auto impls (`e.g. impl \
                     Trait for ..`) can not have type parameters"));
         } else if has_predicates {
-            err = Some(struct_span_err!(self.tcx().sess, span, E0568,
+            err = Some(struct_span_err!(self.tcx.sess, span, E0568,
                 "traits with auto impls (`e.g. impl \
                     Trait for ..`) cannot have predicates"));
         }
@@ -321,9 +313,9 @@ fn check_auto_trait(&mut self, trait_def_id: DefId, span: Span) {
     }
 
     fn check_trait(&mut self, item: &hir::Item) {
-        let trait_def_id = self.tcx().hir.local_def_id(item.id);
+        let trait_def_id = self.tcx.hir.local_def_id(item.id);
 
-        if self.tcx().trait_has_default_impl(trait_def_id) {
+        if self.tcx.trait_has_default_impl(trait_def_id) {
             self.check_auto_trait(trait_def_id, item.span);
         }
 
@@ -344,18 +336,13 @@ fn check_item_fn(&mut self,
             let def_id = fcx.tcx.hir.local_def_id(item.id);
             let ty = fcx.tcx.item_type(def_id);
             let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &ty);
-            let bare_fn_ty = match item_ty.sty {
-                ty::TyFnDef(.., ref bare_fn_ty) => bare_fn_ty,
-                _ => {
-                    span_bug!(item.span, "Fn item without fn type");
-                }
-            };
+            let sig = item_ty.fn_sig();
 
             let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs);
 
             let mut implied_bounds = vec![];
             let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body_id.node_id);
-            this.check_fn_or_method(fcx, item.span, bare_fn_ty, &predicates,
+            this.check_fn_or_method(fcx, item.span, sig, &predicates,
                                     free_id_outlive, &mut implied_bounds);
             implied_bounds
         })
@@ -440,14 +427,14 @@ fn check_where_clauses<'fcx, 'tcx>(&mut self,
     fn check_fn_or_method<'fcx, 'tcx>(&mut self,
                                       fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
                                       span: Span,
-                                      fty: &'tcx ty::BareFnTy<'tcx>,
+                                      sig: ty::PolyFnSig<'tcx>,
                                       predicates: &ty::InstantiatedPredicates<'tcx>,
                                       free_id_outlive: CodeExtent,
                                       implied_bounds: &mut Vec<Ty<'tcx>>)
     {
         let free_substs = &fcx.parameter_environment.free_substs;
-        let fty = fcx.instantiate_type_scheme(span, free_substs, &fty);
-        let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig);
+        let sig = fcx.instantiate_type_scheme(span, free_substs, &sig);
+        let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &sig);
 
         for input_ty in sig.inputs() {
             fcx.register_wf_obligation(&input_ty, span, self.code.clone());
@@ -514,15 +501,15 @@ fn check_variances_for_type_defn(&self,
                                      item: &hir::Item,
                                      ast_generics: &hir::Generics)
     {
-        let item_def_id = self.tcx().hir.local_def_id(item.id);
-        let ty = self.tcx().item_type(item_def_id);
-        if self.tcx().has_error_field(ty) {
+        let item_def_id = self.tcx.hir.local_def_id(item.id);
+        let ty = self.tcx.item_type(item_def_id);
+        if self.tcx.has_error_field(ty) {
             return;
         }
 
-        let ty_predicates = self.tcx().item_predicates(item_def_id);
+        let ty_predicates = self.tcx.item_predicates(item_def_id);
         assert_eq!(ty_predicates.parent, None);
-        let variances = self.tcx().item_variances(item_def_id);
+        let variances = self.tcx.item_variances(item_def_id);
 
         let mut constrained_parameters: FxHashSet<_> =
             variances.iter().enumerate()
@@ -555,15 +542,15 @@ fn report_bivariance(&self,
                          span: Span,
                          param_name: ast::Name)
     {
-        let mut err = error_392(self.ccx, span, param_name);
+        let mut err = error_392(self.tcx, span, param_name);
 
-        let suggested_marker_id = self.tcx().lang_items.phantom_data();
+        let suggested_marker_id = self.tcx.lang_items.phantom_data();
         match suggested_marker_id {
             Some(def_id) => {
                 err.help(
                     &format!("consider removing `{}` or using a marker such as `{}`",
                              param_name,
-                             self.tcx().item_path_str(def_id)));
+                             self.tcx.item_path_str(def_id)));
             }
             None => {
                 // no lang items, no help!
@@ -595,7 +582,7 @@ fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) {
     }
 }
 
-impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
+impl<'a, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
         NestedVisitorMap::None
     }
@@ -681,21 +668,21 @@ fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> {
     }
 }
 
-fn error_192(ccx: &CrateCtxt, span: Span) {
-    span_err!(ccx.tcx.sess, span, E0192,
+fn error_192(tcx: TyCtxt, span: Span) {
+    span_err!(tcx.sess, span, E0192,
               "negative impls are only allowed for traits with \
                default impls (e.g., `Send` and `Sync`)")
 }
 
-fn error_380(ccx: &CrateCtxt, span: Span) {
-    span_err!(ccx.tcx.sess, span, E0380,
+fn error_380(tcx: TyCtxt, span: Span) {
+    span_err!(tcx.sess, span, E0380,
               "traits with default impls (`e.g. impl \
                Trait for ..`) must have no methods or associated items")
 }
 
-fn error_392<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, param_name: ast::Name)
+fn error_392<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, param_name: ast::Name)
                        -> DiagnosticBuilder<'tcx> {
-    let mut err = struct_span_err!(ccx.tcx.sess, span, E0392,
+    let mut err = struct_span_err!(tcx.sess, span, E0392,
                   "parameter `{}` is never used", param_name);
     err.span_label(span, &format!("unused type parameter"));
     err
index a2922270583796ba54520c48a6710315167328dc..1382ab34ca52048b7ba419a5800913f12649b214 100644 (file)
 use self::ResolveReason::*;
 
 use check::FnCtxt;
-use hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee};
 use rustc::ty::adjustment;
 use rustc::ty::fold::{TypeFolder,TypeFoldable};
 use rustc::infer::{InferCtxt, FixupError};
 use rustc::util::nodemap::{DefIdMap, DefIdSet};
 
-use std::cell::Cell;
 use std::mem;
 
 use syntax::ast;
@@ -34,9 +32,8 @@
 // Entry point
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body) {
-        assert_eq!(self.writeback_errors.get(), false);
-
+    pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body)
+                                     -> &'gcx ty::TypeckTables<'gcx> {
         let item_id = self.tcx.hir.body_owner(body.id());
         let item_def_id = self.tcx.hir.local_def_id(item_id);
 
@@ -50,18 +47,18 @@ pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body) {
         wbcx.visit_liberated_fn_sigs();
         wbcx.visit_fru_field_types();
         wbcx.visit_anon_types();
-        wbcx.visit_deferred_obligations(item_id);
         wbcx.visit_type_nodes();
         wbcx.visit_cast_types();
         wbcx.visit_lints();
 
-        let tables = self.tcx.alloc_tables(wbcx.tables);
-        self.tcx.tables.borrow_mut().insert(item_def_id, tables);
-
-        let used_trait_imports = mem::replace(&mut *self.used_trait_imports.borrow_mut(),
+        let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports,
                                               DefIdSet());
         debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
-        self.tcx.used_trait_imports.borrow_mut().insert(item_def_id, used_trait_imports);
+        wbcx.tables.used_trait_imports = used_trait_imports;
+
+        wbcx.tables.tainted_by_errors = self.is_tainted_by_errors();
+
+        self.tcx.alloc_tables(wbcx.tables)
     }
 }
 
@@ -197,19 +194,11 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
     }
 
     fn visit_stmt(&mut self, s: &'gcx hir::Stmt) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         self.visit_node_id(ResolvingExpr(s.span), s.node.id());
         intravisit::walk_stmt(self, s);
     }
 
     fn visit_expr(&mut self, e: &'gcx hir::Expr) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         self.fix_scalar_builtin_expr(e);
 
         self.visit_node_id(ResolvingExpr(e.span), e.id);
@@ -229,29 +218,16 @@ fn visit_expr(&mut self, e: &'gcx hir::Expr) {
     }
 
     fn visit_block(&mut self, b: &'gcx hir::Block) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         self.visit_node_id(ResolvingExpr(b.span), b.id);
         intravisit::walk_block(self, b);
     }
 
     fn visit_pat(&mut self, p: &'gcx hir::Pat) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         self.visit_node_id(ResolvingPattern(p.span), p.id);
-
         intravisit::walk_pat(self, p);
     }
 
     fn visit_local(&mut self, l: &'gcx hir::Local) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         let var_ty = self.fcx.local_ty(l.span, l.id);
         let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span));
         self.write_ty_to_tables(l.id, var_ty);
@@ -261,10 +237,6 @@ fn visit_local(&mut self, l: &'gcx hir::Local) {
 
 impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
     fn visit_upvar_borrow_map(&mut self) {
-        if self.fcx.writeback_errors.get() {
-            return;
-        }
-
         for (upvar_id, upvar_capture) in self.fcx.tables.borrow().upvar_capture_map.iter() {
             let new_upvar_capture = match *upvar_capture {
                 ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
@@ -282,48 +254,30 @@ fn visit_upvar_borrow_map(&mut self) {
         }
     }
 
-    fn visit_closures(&self) {
-        if self.fcx.writeback_errors.get() {
-            return
-        }
-
+    fn visit_closures(&mut self) {
         for (&id, closure_ty) in self.fcx.tables.borrow().closure_tys.iter() {
             let closure_ty = self.resolve(closure_ty, ResolvingClosure(id));
-            let def_id = self.tcx().hir.local_def_id(id);
-            self.tcx().closure_tys.borrow_mut().insert(def_id, closure_ty);
+            self.tables.closure_tys.insert(id, closure_ty);
         }
 
         for (&id, &closure_kind) in self.fcx.tables.borrow().closure_kinds.iter() {
-            let def_id = self.tcx().hir.local_def_id(id);
-            self.tcx().closure_kinds.borrow_mut().insert(def_id, closure_kind);
+            self.tables.closure_kinds.insert(id, closure_kind);
         }
     }
 
     fn visit_cast_types(&mut self) {
-        if self.fcx.writeback_errors.get() {
-            return
-        }
-
         self.tables.cast_kinds.extend(
             self.fcx.tables.borrow().cast_kinds.iter().map(|(&key, &value)| (key, value)));
     }
 
     fn visit_lints(&mut self) {
-        if self.fcx.writeback_errors.get() {
-            return
-        }
-
         self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints);
     }
 
-    fn visit_anon_types(&self) {
-        if self.fcx.writeback_errors.get() {
-            return
-        }
-
+    fn visit_anon_types(&mut self) {
         let gcx = self.tcx().global_tcx();
-        for (&def_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
-            let reason = ResolvingAnonTy(def_id);
+        for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
+            let reason = ResolvingAnonTy(node_id);
             let inside_ty = self.resolve(&concrete_ty, reason);
 
             // Convert the type from the function into a type valid outside
@@ -361,7 +315,7 @@ fn visit_anon_types(&self) {
                 }
             });
 
-            gcx.item_types.borrow_mut().insert(def_id, outside_ty);
+            self.tables.node_types.insert(node_id, outside_ty);
         }
     }
 
@@ -412,6 +366,10 @@ fn visit_adjustments(&mut self, reason: ResolveReason, id: ast::NodeId) {
                         adjustment::Adjust::MutToConstPointer
                     }
 
+                    adjustment::Adjust::ClosureFnPointer => {
+                        adjustment::Adjust::ClosureFnPointer
+                    }
+
                     adjustment::Adjust::UnsafeFnPointer => {
                         adjustment::Adjust::UnsafeFnPointer
                     }
@@ -479,23 +437,10 @@ fn visit_fru_field_types(&mut self) {
         }
     }
 
-    fn visit_deferred_obligations(&mut self, item_id: ast::NodeId) {
-        let deferred_obligations = self.fcx.deferred_obligations.borrow();
-        let obligations: Vec<_> = deferred_obligations.iter().map(|obligation| {
-            let reason = ResolvingDeferredObligation(obligation.cause.span);
-            self.resolve(obligation, reason)
-        }).collect();
-
-        if !obligations.is_empty() {
-            assert!(self.fcx.ccx.deferred_obligations.borrow_mut()
-                                .insert(item_id, obligations).is_none());
-        }
-    }
-
     fn visit_type_nodes(&self) {
         for (&id, ty) in self.fcx.ast_ty_to_ty_cache.borrow().iter() {
             let ty = self.resolve(ty, ResolvingTyNode(id));
-            self.fcx.ccx.ast_ty_to_ty_cache.borrow_mut().insert(id, ty);
+            self.fcx.tcx.ast_ty_to_ty_cache.borrow_mut().insert(id, ty);
         }
     }
 
@@ -524,8 +469,7 @@ enum ResolveReason {
     ResolvingClosure(ast::NodeId),
     ResolvingFnSig(ast::NodeId),
     ResolvingFieldTypes(ast::NodeId),
-    ResolvingAnonTy(DefId),
-    ResolvingDeferredObligation(Span),
+    ResolvingAnonTy(ast::NodeId),
     ResolvingTyNode(ast::NodeId),
 }
 
@@ -541,13 +485,10 @@ fn span(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Span {
             ResolvingClosure(id) |
             ResolvingFnSig(id) |
             ResolvingFieldTypes(id) |
-            ResolvingTyNode(id) => {
+            ResolvingTyNode(id) |
+            ResolvingAnonTy(id) => {
                 tcx.hir.span(id)
             }
-            ResolvingAnonTy(did) => {
-                tcx.def_span(did)
-            }
-            ResolvingDeferredObligation(span) => span
         }
     }
 }
@@ -559,7 +500,6 @@ fn span(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Span {
 struct Resolver<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
     tcx: TyCtxt<'cx, 'gcx, 'tcx>,
     infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
-    writeback_errors: &'cx Cell<bool>,
     reason: ResolveReason,
 }
 
@@ -568,22 +508,19 @@ fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>,
            reason: ResolveReason)
            -> Resolver<'cx, 'gcx, 'tcx>
     {
-        Resolver::from_infcx(fcx, &fcx.writeback_errors, reason)
+        Resolver::from_infcx(fcx, reason)
     }
 
     fn from_infcx(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
-                  writeback_errors: &'cx Cell<bool>,
                   reason: ResolveReason)
                   -> Resolver<'cx, 'gcx, 'tcx>
     {
         Resolver { infcx: infcx,
                    tcx: infcx.tcx,
-                   writeback_errors: writeback_errors,
                    reason: reason }
     }
 
     fn report_error(&self, e: FixupError) {
-        self.writeback_errors.set(true);
         if !self.tcx.sess.has_errors() {
             match self.reason {
                 ResolvingExpr(span) => {
@@ -622,7 +559,6 @@ fn report_error(&self, e: FixupError) {
 
                 ResolvingFnSig(_) |
                 ResolvingFieldTypes(_) |
-                ResolvingDeferredObligation(_) |
                 ResolvingTyNode(_) => {
                     // any failures here should also fail when
                     // resolving the patterns, closure types, or
index 6dff6d57e4facc1d576c06f0dcf89dcf6131f029..3791079dc812cb0b6d69ffb017c38af77a64a59d 100644 (file)
@@ -70,7 +70,8 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         let item_def_id = tcx.hir.local_def_id(item_id);
 
         // this will have been written by the main typeck pass
-        if let Some(imports) = tcx.used_trait_imports.borrow().get(&item_def_id) {
+        if let Some(tables) = tcx.maps.typeck_tables.borrow().get(&item_def_id) {
+            let imports = &tables.used_trait_imports;
             debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
             used_trait_imports.extend(imports);
         } else {
index 96875fce468d2e34473ddc0c2a7b25c37e3755de..3cdf9fc93ae600617a4c84aa935dfdb1adcaec07 100644 (file)
 use rustc::hir::map as hir_map;
 use rustc::hir::{self, ItemImpl};
 
-pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    check_trait(tcx, tcx.lang_items.drop_trait(), visit_implementation_of_drop);
-    check_trait(tcx, tcx.lang_items.copy_trait(), visit_implementation_of_copy);
-    check_trait(
-        tcx,
-        tcx.lang_items.coerce_unsized_trait(),
-        visit_implementation_of_coerce_unsized);
+pub fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_def_id: DefId) {
+    Checker { tcx, trait_def_id }
+        .check(tcx.lang_items.drop_trait(), visit_implementation_of_drop)
+        .check(tcx.lang_items.copy_trait(), visit_implementation_of_copy)
+        .check(tcx.lang_items.coerce_unsized_trait(),
+               visit_implementation_of_coerce_unsized);
 }
 
-fn check_trait<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                            trait_def_id: Option<DefId>,
-                            mut f: F)
-    where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId)
-{
-    if let Some(trait_def_id) = trait_def_id {
-        let mut impls = vec![];
-        tcx.lookup_trait_def(trait_def_id).for_each_impl(tcx, |did| {
-            impls.push(did);
-        });
-        impls.sort();
-        for impl_def_id in impls {
-            f(tcx, trait_def_id, impl_def_id);
+struct Checker<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    trait_def_id: DefId
+}
+
+impl<'a, 'tcx> Checker<'a, 'tcx> {
+    fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self
+        where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId)
+    {
+        if Some(self.trait_def_id) == trait_def_id {
+            for &impl_id in self.tcx.hir.trait_impls(self.trait_def_id) {
+                let impl_def_id = self.tcx.hir.local_def_id(impl_id);
+                f(self.tcx, self.trait_def_id, impl_def_id);
+            }
         }
+        self
     }
 }
 
 fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                           _drop_did: DefId,
                                           impl_did: DefId) {
-    let items = tcx.associated_item_def_ids(impl_did);
-    if items.is_empty() {
-        // We'll error out later. For now, just don't ICE.
-        return;
-    }
-    let method_def_id = items[0];
-
-    let self_type = tcx.item_type(impl_did);
-    match self_type.sty {
-        ty::TyAdt(type_def, _) => {
-            type_def.set_destructor(method_def_id);
-        }
+    match tcx.item_type(impl_did).sty {
+        ty::TyAdt(..) => {}
         _ => {
             // Destructors only work on nominal types.
             if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_did) {
@@ -205,7 +196,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
            source,
            target);
 
-    tcx.infer_ctxt(param_env, Reveal::ExactMatch).enter(|infcx| {
+    tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
         let cause = ObligationCause::misc(span, impl_node_id);
         let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
                            mt_b: ty::TypeAndMut<'tcx>,
@@ -341,7 +332,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
 
         if let Some(kind) = kind {
-            tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
+            tcx.maps.custom_coerce_unsized_kind.borrow_mut().insert(impl_did, kind);
         }
     });
 }
diff --git a/src/librustc_typeck/coherence/inherent.rs b/src/librustc_typeck/coherence/inherent.rs
new file mode 100644 (file)
index 0000000..e3b4ba9
--- /dev/null
@@ -0,0 +1,356 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::dep_graph::DepNode;
+use rustc::hir::def_id::DefId;
+use rustc::hir;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::lint;
+use rustc::traits::{self, Reveal};
+use rustc::ty::{self, TyCtxt};
+
+use syntax::ast;
+use syntax_pos::Span;
+
+struct InherentCollect<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>
+}
+
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
+    fn visit_item(&mut self, item: &hir::Item) {
+        let (unsafety, ty) = match item.node {
+            hir::ItemImpl(unsafety, .., None, ref ty, _) => (unsafety, ty),
+            _ => return
+        };
+
+        match unsafety {
+            hir::Unsafety::Normal => {
+                // OK
+            }
+            hir::Unsafety::Unsafe => {
+                span_err!(self.tcx.sess,
+                          item.span,
+                          E0197,
+                          "inherent impls cannot be declared as unsafe");
+            }
+        }
+
+        let def_id = self.tcx.hir.local_def_id(item.id);
+        let self_ty = self.tcx.item_type(def_id);
+        match self_ty.sty {
+            ty::TyAdt(def, _) => {
+                self.check_def_id(item, def.did);
+            }
+            ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
+                self.check_def_id(item, data.principal().unwrap().def_id());
+            }
+            ty::TyChar => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.char_impl(),
+                                          "char",
+                                          "char",
+                                          item.span);
+            }
+            ty::TyStr => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.str_impl(),
+                                          "str",
+                                          "str",
+                                          item.span);
+            }
+            ty::TySlice(_) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.slice_impl(),
+                                          "slice",
+                                          "[T]",
+                                          item.span);
+            }
+            ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.const_ptr_impl(),
+                                          "const_ptr",
+                                          "*const T",
+                                          item.span);
+            }
+            ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.mut_ptr_impl(),
+                                          "mut_ptr",
+                                          "*mut T",
+                                          item.span);
+            }
+            ty::TyInt(ast::IntTy::I8) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.i8_impl(),
+                                          "i8",
+                                          "i8",
+                                          item.span);
+            }
+            ty::TyInt(ast::IntTy::I16) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.i16_impl(),
+                                          "i16",
+                                          "i16",
+                                          item.span);
+            }
+            ty::TyInt(ast::IntTy::I32) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.i32_impl(),
+                                          "i32",
+                                          "i32",
+                                          item.span);
+            }
+            ty::TyInt(ast::IntTy::I64) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.i64_impl(),
+                                          "i64",
+                                          "i64",
+                                          item.span);
+            }
+            ty::TyInt(ast::IntTy::I128) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.i128_impl(),
+                                          "i128",
+                                          "i128",
+                                          item.span);
+            }
+            ty::TyInt(ast::IntTy::Is) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.isize_impl(),
+                                          "isize",
+                                          "isize",
+                                          item.span);
+            }
+            ty::TyUint(ast::UintTy::U8) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.u8_impl(),
+                                          "u8",
+                                          "u8",
+                                          item.span);
+            }
+            ty::TyUint(ast::UintTy::U16) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.u16_impl(),
+                                          "u16",
+                                          "u16",
+                                          item.span);
+            }
+            ty::TyUint(ast::UintTy::U32) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.u32_impl(),
+                                          "u32",
+                                          "u32",
+                                          item.span);
+            }
+            ty::TyUint(ast::UintTy::U64) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.u64_impl(),
+                                          "u64",
+                                          "u64",
+                                          item.span);
+            }
+            ty::TyUint(ast::UintTy::U128) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.u128_impl(),
+                                          "u128",
+                                          "u128",
+                                          item.span);
+            }
+            ty::TyUint(ast::UintTy::Us) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.usize_impl(),
+                                          "usize",
+                                          "usize",
+                                          item.span);
+            }
+            ty::TyFloat(ast::FloatTy::F32) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.f32_impl(),
+                                          "f32",
+                                          "f32",
+                                          item.span);
+            }
+            ty::TyFloat(ast::FloatTy::F64) => {
+                self.check_primitive_impl(def_id,
+                                          self.tcx.lang_items.f64_impl(),
+                                          "f64",
+                                          "f64",
+                                          item.span);
+            }
+            ty::TyError => {
+                return;
+            }
+            _ => {
+                struct_span_err!(self.tcx.sess,
+                                 ty.span,
+                                 E0118,
+                                 "no base type found for inherent implementation")
+                    .span_label(ty.span, &format!("impl requires a base type"))
+                    .note(&format!("either implement a trait on it or create a newtype \
+                                    to wrap it instead"))
+                    .emit();
+                return;
+            }
+        }
+    }
+
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+    }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+    }
+}
+
+impl<'a, 'tcx> InherentCollect<'a, 'tcx> {
+    fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
+        if def_id.is_local() {
+            // Add the implementation to the mapping from implementation to base
+            // type def ID, if there is a base type for this implementation and
+            // the implementation does not have any associated traits.
+            let impl_def_id = self.tcx.hir.local_def_id(item.id);
+
+            // Subtle: it'd be better to collect these into a local map
+            // and then write the vector only once all items are known,
+            // but that leads to degenerate dep-graphs. The problem is
+            // that the write of that big vector winds up having reads
+            // from *all* impls in the krate, since we've lost the
+            // precision basically.  This would be ok in the firewall
+            // model so once we've made progess towards that we can modify
+            // the strategy here. In the meantime, using `push` is ok
+            // because we are doing this as a pre-pass before anyone
+            // actually reads from `inherent_impls` -- and we know this is
+            // true beacuse we hold the refcell lock.
+            self.tcx.maps.inherent_impls.borrow_mut().push(def_id, impl_def_id);
+        } else {
+            struct_span_err!(self.tcx.sess,
+                             item.span,
+                             E0116,
+                             "cannot define inherent `impl` for a type outside of the crate \
+                              where the type is defined")
+                .span_label(item.span,
+                            &format!("impl for type defined outside of crate."))
+                .note("define and implement a trait or new type instead")
+                .emit();
+        }
+    }
+
+    fn check_primitive_impl(&self,
+                            impl_def_id: DefId,
+                            lang_def_id: Option<DefId>,
+                            lang: &str,
+                            ty: &str,
+                            span: Span) {
+        match lang_def_id {
+            Some(lang_def_id) if lang_def_id == impl_def_id => {
+                // OK
+            }
+            _ => {
+                struct_span_err!(self.tcx.sess,
+                                 span,
+                                 E0390,
+                                 "only a single inherent implementation marked with `#[lang = \
+                                  \"{}\"]` is allowed for the `{}` primitive",
+                                 lang,
+                                 ty)
+                    .span_help(span, "consider using a trait to implement these methods")
+                    .emit();
+            }
+        }
+    }
+}
+
+struct InherentOverlapChecker<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>
+}
+
+impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
+    fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
+        #[derive(Copy, Clone, PartialEq)]
+        enum Namespace {
+            Type,
+            Value,
+        }
+
+        let name_and_namespace = |def_id| {
+            let item = self.tcx.associated_item(def_id);
+            (item.name, match item.kind {
+                ty::AssociatedKind::Type => Namespace::Type,
+                ty::AssociatedKind::Const |
+                ty::AssociatedKind::Method => Namespace::Value,
+            })
+        };
+
+        let impl_items1 = self.tcx.associated_item_def_ids(impl1);
+        let impl_items2 = self.tcx.associated_item_def_ids(impl2);
+
+        for &item1 in &impl_items1[..] {
+            let (name, namespace) = name_and_namespace(item1);
+
+            for &item2 in &impl_items2[..] {
+                if (name, namespace) == name_and_namespace(item2) {
+                    let msg = format!("duplicate definitions with name `{}`", name);
+                    let node_id = self.tcx.hir.as_local_node_id(item1).unwrap();
+                    self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
+                                           node_id,
+                                           self.tcx.span_of_impl(item1).unwrap(),
+                                           msg);
+                }
+            }
+        }
+    }
+
+    fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
+        let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id));
+
+        let inherent_impls = self.tcx.maps.inherent_impls.borrow();
+        let impls = match inherent_impls.get(&ty_def_id) {
+            Some(impls) => impls,
+            None => return,
+        };
+
+        for (i, &impl1_def_id) in impls.iter().enumerate() {
+            for &impl2_def_id in &impls[(i + 1)..] {
+                self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
+                    if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
+                        self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
+                    }
+                });
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> {
+    fn visit_item(&mut self, item: &'v hir::Item) {
+        match item.node {
+            hir::ItemEnum(..) |
+            hir::ItemStruct(..) |
+            hir::ItemTrait(..) |
+            hir::ItemUnion(..) => {
+                let type_def_id = self.tcx.hir.local_def_id(item.id);
+                self.check_for_overlapping_inherent_impls(type_def_id);
+            }
+            _ => {}
+        }
+    }
+
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+    }
+
+    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+    }
+}
+
+pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl,
+                                      &mut InherentCollect { tcx });
+    tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial,
+                                      &mut InherentOverlapChecker { tcx });
+}
index b6a863fd2ed0d533626972afbf1c6a219659a63d..9ecf42daeaae52021fd7f60f0a4dfd91de90f3d7 100644 (file)
 // done by the orphan and overlap modules. Then we build up various
 // mappings. That mapping code resides here.
 
-use dep_graph::DepTrackingMap;
-use hir::def_id::DefId;
-use rustc::ty::{self, maps, TyCtxt, TypeFoldable};
-use rustc::ty::{Ty, TyBool, TyChar, TyError};
-use rustc::ty::{TyParam, TyRawPtr};
-use rustc::ty::{TyRef, TyAdt, TyDynamic, TyNever, TyTuple};
-use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
-use rustc::ty::{TyUint, TyClosure, TyFnDef, TyFnPtr};
-use rustc::ty::{TyProjection, TyAnon};
-use CrateCtxt;
-use syntax_pos::Span;
+use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use rustc::ty::{self, TyCtxt, TypeFoldable};
+use rustc::ty::maps::Providers;
 use rustc::dep_graph::DepNode;
-use rustc::hir::itemlikevisit::ItemLikeVisitor;
-use rustc::hir::{Item, ItemImpl};
-use rustc::hir;
-use std::cell::RefMut;
+
+use syntax::ast;
+use syntax_pos::DUMMY_SP;
 
 mod builtin;
+mod inherent;
 mod orphan;
 mod overlap;
 mod unsafety;
 
-struct CoherenceCollect<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    inherent_impls: RefMut<'a, DepTrackingMap<maps::InherentImpls<'tcx>>>,
-}
-
-impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCollect<'a, 'tcx> {
-    fn visit_item(&mut self, item: &Item) {
-        if let ItemImpl(..) = item.node {
-            self.check_implementation(item)
-        }
-    }
-
-    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
-    }
+fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
+    let impl_def_id = tcx.hir.local_def_id(node_id);
 
-    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
-    }
-}
+    // If there are no traits, then this implementation must have a
+    // base type.
 
-impl<'a, 'tcx> CoherenceCollect<'a, 'tcx> {
-    fn check(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-        let inherent_impls = tcx.inherent_impls.borrow_mut();
-        let mut this = &mut CoherenceCollect { tcx, inherent_impls };
+    if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) {
+        debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
+                trait_ref,
+                tcx.item_path_str(impl_def_id));
 
-        // Check implementations and traits. This populates the tables
-        // containing the inherent methods and extension methods. It also
-        // builds up the trait inheritance table.
-        tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, this);
-    }
-
-    // Returns the def ID of the base type, if there is one.
-    fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
-        match ty.sty {
-            TyAdt(def, _) => Some(def.did),
-
-            TyDynamic(ref t, ..) => t.principal().map(|p| p.def_id()),
-
-            TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) |
-            TySlice(..) | TyFnDef(..) | TyFnPtr(_) | TyTuple(..) | TyParam(..) | TyError |
-            TyNever | TyRawPtr(_) | TyRef(..) | TyProjection(..) => None,
-
-            TyInfer(..) | TyClosure(..) | TyAnon(..) => {
-                // `ty` comes from a user declaration so we should only expect types
-                // that the user can type
-                span_bug!(span,
-                          "coherence encountered unexpected type searching for base type: {}",
-                          ty);
-            }
+        // Skip impls where one of the self type is an error type.
+        // This occurs with e.g. resolve failures (#30589).
+        if trait_ref.references_error() {
+            return;
         }
-    }
 
-    fn check_implementation(&mut self, item: &Item) {
-        let tcx = self.tcx;
-        let impl_did = tcx.hir.local_def_id(item.id);
-        let self_type = tcx.item_type(impl_did);
-
-        // If there are no traits, then this implementation must have a
-        // base type.
-
-        if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
-            debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
-                   trait_ref,
-                   item.name);
-
-            // Skip impls where one of the self type is an error type.
-            // This occurs with e.g. resolve failures (#30589).
-            if trait_ref.references_error() {
-                return;
-            }
-
-            enforce_trait_manually_implementable(self.tcx, item.span, trait_ref.def_id);
-            self.add_trait_impl(trait_ref, impl_did);
-        } else {
-            // Skip inherent impls where the self type is an error
-            // type. This occurs with e.g. resolve failures (#30589).
-            if self_type.references_error() {
-                return;
-            }
-
-            // Add the implementation to the mapping from implementation to base
-            // type def ID, if there is a base type for this implementation and
-            // the implementation does not have any associated traits.
-            if let Some(base_def_id) = self.get_base_type_def_id(item.span, self_type) {
-                self.add_inherent_impl(base_def_id, impl_did);
-            }
-        }
+        enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id);
+        let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
+        trait_def.record_local_impl(tcx, impl_def_id, trait_ref);
     }
+}
 
-    fn add_inherent_impl(&mut self, base_def_id: DefId, impl_def_id: DefId) {
-        // Subtle: it'd be better to collect these into a local map
-        // and then write the vector only once all items are known,
-        // but that leads to degenerate dep-graphs. The problem is
-        // that the write of that big vector winds up having reads
-        // from *all* impls in the krate, since we've lost the
-        // precision basically.  This would be ok in the firewall
-        // model so once we've made progess towards that we can modify
-        // the strategy here. In the meantime, using `push` is ok
-        // because we are doing this as a pre-pass before anyone
-        // actually reads from `inherent_impls` -- and we know this is
-        // true beacuse we hold the refcell lock.
-        self.inherent_impls.push(base_def_id, impl_def_id);
+fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_def_id: DefId) {
+    let did = Some(trait_def_id);
+    let li = &tcx.lang_items;
+
+    // Disallow *all* explicit impls of `Sized` and `Unsize` for now.
+    if did == li.sized_trait() {
+        let span = tcx.span_of_impl(impl_def_id).unwrap();
+        struct_span_err!(tcx.sess,
+                         span,
+                         E0322,
+                         "explicit impls for the `Sized` trait are not permitted")
+            .span_label(span, &format!("impl of 'Sized' not allowed"))
+            .emit();
+        return;
     }
 
-    fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'tcx>, impl_def_id: DefId) {
-        debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
-               impl_trait_ref,
-               impl_def_id);
-        let trait_def = self.tcx.lookup_trait_def(impl_trait_ref.def_id);
-        trait_def.record_local_impl(self.tcx, impl_def_id, impl_trait_ref);
+    if did == li.unsize_trait() {
+        let span = tcx.span_of_impl(impl_def_id).unwrap();
+        span_err!(tcx.sess,
+                  span,
+                  E0328,
+                  "explicit impls for the `Unsize` trait are not permitted");
+        return;
     }
-}
 
-fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: DefId) {
     if tcx.sess.features.borrow().unboxed_closures {
-        // the feature gate allows all of them
+        // the feature gate allows all Fn traits
         return;
     }
-    let did = Some(trait_def_id);
-    let li = &tcx.lang_items;
 
     let trait_name = if did == li.fn_trait() {
         "Fn"
@@ -167,7 +92,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
         return; // everything OK
     };
     let mut err = struct_span_err!(tcx.sess,
-                                   sp,
+                                   tcx.span_of_impl(impl_def_id).unwrap(),
                                    E0183,
                                    "manual implementations of `{}` are experimental",
                                    trait_name);
@@ -176,12 +101,41 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
     err.emit();
 }
 
-pub fn check_coherence(ccx: &CrateCtxt) {
-    CoherenceCollect::check(ccx.tcx);
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        coherent_trait,
+        coherent_inherent_impls,
+        ..*providers
+    };
+}
+
+fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            (_, def_id): (CrateNum, DefId)) {
+    tcx.populate_implementations_for_trait_if_necessary(def_id);
+
+    let impls = tcx.hir.trait_impls(def_id);
+    for &impl_id in impls {
+        check_impl(tcx, impl_id);
+    }
+    for &impl_id in impls {
+        overlap::check_impl(tcx, impl_id);
+    }
+    builtin::check_trait(tcx, def_id);
+}
+
+fn coherent_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _: CrateNum) {
+    inherent::check(tcx);
+}
+
+pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    let _task = tcx.dep_graph.in_task(DepNode::Coherence);
+    for &trait_def_id in tcx.hir.krate().trait_impls.keys() {
+        ty::queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, trait_def_id));
+    }
+
+    unsafety::check(tcx);
+    orphan::check(tcx);
+    overlap::check_default_impls(tcx);
 
-    let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence);
-    unsafety::check(ccx.tcx);
-    orphan::check(ccx.tcx);
-    overlap::check(ccx.tcx);
-    builtin::check(ccx.tcx);
+    ty::queries::coherent_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE);
 }
index 9ef231499df5145c1fc0036624c60f769e9c4f4a..ee361ab6073d4e5c4df5b2029cef9ad10a430da0 100644 (file)
 //! Orphan checker: every impl either implements a trait defined in this
 //! crate or pertains to a type defined in this crate.
 
-use hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::traits;
 use rustc::ty::{self, TyCtxt};
-use syntax::ast;
-use syntax_pos::Span;
 use rustc::dep_graph::DepNode;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir;
@@ -29,46 +26,6 @@ struct OrphanChecker<'cx, 'tcx: 'cx> {
     tcx: TyCtxt<'cx, 'tcx, 'tcx>,
 }
 
-impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
-    fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
-        if def_id.krate != LOCAL_CRATE {
-            struct_span_err!(self.tcx.sess,
-                             item.span,
-                             E0116,
-                             "cannot define inherent `impl` for a type outside of the crate \
-                              where the type is defined")
-                .span_label(item.span,
-                            &format!("impl for type defined outside of crate."))
-                .note("define and implement a trait or new type instead")
-                .emit();
-        }
-    }
-
-    fn check_primitive_impl(&self,
-                            impl_def_id: DefId,
-                            lang_def_id: Option<DefId>,
-                            lang: &str,
-                            ty: &str,
-                            span: Span) {
-        match lang_def_id {
-            Some(lang_def_id) if lang_def_id == impl_def_id => {
-                // OK
-            }
-            _ => {
-                struct_span_err!(self.tcx.sess,
-                                 span,
-                                 E0390,
-                                 "only a single inherent implementation marked with `#[lang = \
-                                  \"{}\"]` is allowed for the `{}` primitive",
-                                 lang,
-                                 ty)
-                    .span_help(span, "consider using a trait to implement these methods")
-                    .emit();
-            }
-        }
-    }
-}
-
 impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
     /// Checks exactly one impl for orphan rules and other such
     /// restrictions.  In this fn, it can happen that multiple errors
@@ -78,168 +35,6 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         let def_id = self.tcx.hir.local_def_id(item.id);
         match item.node {
-            hir::ItemImpl(.., None, ref ty, _) => {
-                // For inherent impls, self type must be a nominal type
-                // defined in this crate.
-                debug!("coherence2::orphan check: inherent impl {}",
-                       self.tcx.hir.node_to_string(item.id));
-                let self_ty = self.tcx.item_type(def_id);
-                match self_ty.sty {
-                    ty::TyAdt(def, _) => {
-                        self.check_def_id(item, def.did);
-                    }
-                    ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
-                        self.check_def_id(item, data.principal().unwrap().def_id());
-                    }
-                    ty::TyChar => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.char_impl(),
-                                                  "char",
-                                                  "char",
-                                                  item.span);
-                    }
-                    ty::TyStr => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.str_impl(),
-                                                  "str",
-                                                  "str",
-                                                  item.span);
-                    }
-                    ty::TySlice(_) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.slice_impl(),
-                                                  "slice",
-                                                  "[T]",
-                                                  item.span);
-                    }
-                    ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.const_ptr_impl(),
-                                                  "const_ptr",
-                                                  "*const T",
-                                                  item.span);
-                    }
-                    ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.mut_ptr_impl(),
-                                                  "mut_ptr",
-                                                  "*mut T",
-                                                  item.span);
-                    }
-                    ty::TyInt(ast::IntTy::I8) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.i8_impl(),
-                                                  "i8",
-                                                  "i8",
-                                                  item.span);
-                    }
-                    ty::TyInt(ast::IntTy::I16) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.i16_impl(),
-                                                  "i16",
-                                                  "i16",
-                                                  item.span);
-                    }
-                    ty::TyInt(ast::IntTy::I32) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.i32_impl(),
-                                                  "i32",
-                                                  "i32",
-                                                  item.span);
-                    }
-                    ty::TyInt(ast::IntTy::I64) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.i64_impl(),
-                                                  "i64",
-                                                  "i64",
-                                                  item.span);
-                    }
-                    ty::TyInt(ast::IntTy::I128) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.i128_impl(),
-                                                  "i128",
-                                                  "i128",
-                                                  item.span);
-                    }
-                    ty::TyInt(ast::IntTy::Is) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.isize_impl(),
-                                                  "isize",
-                                                  "isize",
-                                                  item.span);
-                    }
-                    ty::TyUint(ast::UintTy::U8) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.u8_impl(),
-                                                  "u8",
-                                                  "u8",
-                                                  item.span);
-                    }
-                    ty::TyUint(ast::UintTy::U16) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.u16_impl(),
-                                                  "u16",
-                                                  "u16",
-                                                  item.span);
-                    }
-                    ty::TyUint(ast::UintTy::U32) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.u32_impl(),
-                                                  "u32",
-                                                  "u32",
-                                                  item.span);
-                    }
-                    ty::TyUint(ast::UintTy::U64) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.u64_impl(),
-                                                  "u64",
-                                                  "u64",
-                                                  item.span);
-                    }
-                    ty::TyUint(ast::UintTy::U128) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.u128_impl(),
-                                                  "u128",
-                                                  "u128",
-                                                  item.span);
-                    }
-                    ty::TyUint(ast::UintTy::Us) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.usize_impl(),
-                                                  "usize",
-                                                  "usize",
-                                                  item.span);
-                    }
-                    ty::TyFloat(ast::FloatTy::F32) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.f32_impl(),
-                                                  "f32",
-                                                  "f32",
-                                                  item.span);
-                    }
-                    ty::TyFloat(ast::FloatTy::F64) => {
-                        self.check_primitive_impl(def_id,
-                                                  self.tcx.lang_items.f64_impl(),
-                                                  "f64",
-                                                  "f64",
-                                                  item.span);
-                    }
-                    ty::TyError => {
-                        return;
-                    }
-                    _ => {
-                        struct_span_err!(self.tcx.sess,
-                                         ty.span,
-                                         E0118,
-                                         "no base type found for inherent implementation")
-                            .span_label(ty.span, &format!("impl requires a base type"))
-                            .note(&format!("either implement a trait on it or create a newtype \
-                                            to wrap it instead"))
-                            .emit();
-                        return;
-                    }
-                }
-            }
             hir::ItemImpl(.., Some(_), _, _) => {
                 // "Trait" impl
                 debug!("coherence2::orphan check: trait impl {}",
@@ -311,7 +106,7 @@ fn visit_item(&mut self, item: &hir::Item) {
                        trait_def_id,
                        self.tcx.trait_has_default_impl(trait_def_id));
                 if self.tcx.trait_has_default_impl(trait_def_id) &&
-                   trait_def_id.krate != LOCAL_CRATE {
+                   !trait_def_id.is_local() {
                     let self_ty = trait_ref.self_ty();
                     let opt_self_def_id = match self_ty.sty {
                         ty::TyAdt(self_def, _) => Some(self_def.did),
@@ -346,31 +141,13 @@ fn visit_item(&mut self, item: &hir::Item) {
                         return;
                     }
                 }
-
-                // Disallow *all* explicit impls of `Sized` and `Unsize` for now.
-                if Some(trait_def_id) == self.tcx.lang_items.sized_trait() {
-                    struct_span_err!(self.tcx.sess,
-                                     item.span,
-                                     E0322,
-                                     "explicit impls for the `Sized` trait are not permitted")
-                        .span_label(item.span, &format!("impl of 'Sized' not allowed"))
-                        .emit();
-                    return;
-                }
-                if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() {
-                    span_err!(self.tcx.sess,
-                              item.span,
-                              E0328,
-                              "explicit impls for the `Unsize` trait are not permitted");
-                    return;
-                }
             }
             hir::ItemDefaultImpl(_, ref item_trait_ref) => {
                 // "Trait" impl
                 debug!("coherence2::orphan check: default trait impl {}",
                        self.tcx.hir.node_to_string(item.id));
                 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
-                if trait_ref.def_id.krate != LOCAL_CRATE {
+                if !trait_ref.def_id.is_local() {
                     struct_span_err!(self.tcx.sess,
                                      item_trait_ref.path.span,
                                      E0318,
index 56c17dc2f6efda144dbb9e2be510ab19648c57db..d334d0c4338f9bc843887410dd1945f061f7c1be 100644 (file)
 //! same type. Likewise, no two inherent impls for a given type
 //! constructor provide a method with the same name.
 
-use hir::def_id::DefId;
-use rustc::traits::{self, Reveal};
+use rustc::traits;
 use rustc::ty::{self, TyCtxt, TypeFoldable};
 use syntax::ast;
 use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
-use util::nodemap::DefIdMap;
-use lint;
 
-pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let mut overlap = OverlapChecker {
-        tcx: tcx,
-        default_impls: DefIdMap(),
-    };
+pub fn check_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    let mut overlap = OverlapChecker { tcx };
 
     // this secondary walk specifically checks for some other cases,
     // like defaulted traits, for which additional overlap rules exist
     tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
 }
 
-struct OverlapChecker<'cx, 'tcx: 'cx> {
-    tcx: TyCtxt<'cx, 'tcx, 'tcx>,
-
-    // maps from a trait def-id to an impl id
-    default_impls: DefIdMap<ast::NodeId>,
-}
+pub fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
+    let impl_def_id = tcx.hir.local_def_id(node_id);
+    let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+    let trait_def_id = trait_ref.def_id;
 
-impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
-    fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
-        #[derive(Copy, Clone, PartialEq)]
-        enum Namespace {
-            Type,
-            Value,
-        }
+    if trait_ref.references_error() {
+        debug!("coherence: skipping impl {:?} with error {:?}",
+               impl_def_id, trait_ref);
+        return
+    }
 
-        let name_and_namespace = |def_id| {
-            let item = self.tcx.associated_item(def_id);
-            (item.name, match item.kind {
-                ty::AssociatedKind::Type => Namespace::Type,
-                ty::AssociatedKind::Const |
-                ty::AssociatedKind::Method => Namespace::Value,
-            })
-        };
-
-        let impl_items1 = self.tcx.associated_item_def_ids(impl1);
-        let impl_items2 = self.tcx.associated_item_def_ids(impl2);
-
-        for &item1 in &impl_items1[..] {
-            let (name, namespace) = name_and_namespace(item1);
-
-            for &item2 in &impl_items2[..] {
-                if (name, namespace) == name_and_namespace(item2) {
-                    let msg = format!("duplicate definitions with name `{}`", name);
-                    let node_id = self.tcx.hir.as_local_node_id(item1).unwrap();
-                    self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
-                                           node_id,
-                                           self.tcx.span_of_impl(item1).unwrap(),
-                                           msg);
-                }
+    let _task =
+        tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
+
+    let def = tcx.lookup_trait_def(trait_def_id);
+
+    // attempt to insert into the specialization graph
+    let insert_result = def.add_impl_for_specialization(tcx, impl_def_id);
+
+    // insertion failed due to overlap
+    if let Err(overlap) = insert_result {
+        let mut err = struct_span_err!(tcx.sess,
+                                       tcx.span_of_impl(impl_def_id).unwrap(),
+                                       E0119,
+                                       "conflicting implementations of trait `{}`{}:",
+                                       overlap.trait_desc,
+                                       overlap.self_desc.clone().map_or(String::new(),
+                                                                        |ty| {
+            format!(" for type `{}`", ty)
+        }));
+
+        match tcx.span_of_impl(overlap.with_impl) {
+            Ok(span) => {
+                err.span_label(span, &format!("first implementation here"));
+                err.span_label(tcx.span_of_impl(impl_def_id).unwrap(),
+                               &format!("conflicting implementation{}",
+                                        overlap.self_desc
+                                            .map_or(String::new(),
+                                                    |ty| format!(" for `{}`", ty))));
+            }
+            Err(cname) => {
+                err.note(&format!("conflicting implementation in crate `{}`", cname));
             }
         }
+
+        err.emit();
     }
 
-    fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
-        let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id));
-
-        let inherent_impls = self.tcx.inherent_impls.borrow();
-        let impls = match inherent_impls.get(&ty_def_id) {
-            Some(impls) => impls,
-            None => return,
-        };
-
-        for (i, &impl1_def_id) in impls.iter().enumerate() {
-            for &impl2_def_id in &impls[(i + 1)..] {
-                self.tcx.infer_ctxt((), Reveal::ExactMatch).enter(|infcx| {
-                    if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
-                        self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
-                    }
-                });
+    // check for overlap with the automatic `impl Trait for Trait`
+    if let ty::TyDynamic(ref data, ..) = trait_ref.self_ty().sty {
+        // This is something like impl Trait1 for Trait2. Illegal
+        // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
+
+        if data.principal().map_or(true, |p| !tcx.is_object_safe(p.def_id())) {
+            // This is an error, but it will be reported by wfcheck.  Ignore it here.
+            // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
+        } else {
+            let mut supertrait_def_ids =
+                traits::supertrait_def_ids(tcx,
+                                           data.principal().unwrap().def_id());
+            if supertrait_def_ids.any(|d| d == trait_def_id) {
+                span_err!(tcx.sess,
+                          tcx.span_of_impl(impl_def_id).unwrap(),
+                          E0371,
+                          "the object type `{}` automatically \
+                           implements the trait `{}`",
+                          trait_ref.self_ty(),
+                          tcx.item_path_str(trait_def_id));
             }
         }
     }
 }
 
+struct OverlapChecker<'cx, 'tcx: 'cx> {
+    tcx: TyCtxt<'cx, 'tcx, 'tcx>,
+}
+
 impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &'v hir::Item) {
         match item.node {
-            hir::ItemEnum(..) |
-            hir::ItemStruct(..) |
-            hir::ItemTrait(..) |
-            hir::ItemUnion(..) => {
-                let type_def_id = self.tcx.hir.local_def_id(item.id);
-                self.check_for_overlapping_inherent_impls(type_def_id);
-            }
-
             hir::ItemDefaultImpl(..) => {
                 // look for another default impl; note that due to the
                 // general orphan/coherence rules, it must always be
@@ -115,8 +114,8 @@ fn visit_item(&mut self, item: &'v hir::Item) {
                 let impl_def_id = self.tcx.hir.local_def_id(item.id);
                 let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
 
-                let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
-                if let Some(prev_id) = prev_default_impl {
+                let prev_id = self.tcx.hir.trait_default_impl(trait_ref.def_id).unwrap();
+                if prev_id != item.id {
                     let mut err = struct_span_err!(self.tcx.sess,
                                                    self.tcx.span_of_impl(impl_def_id).unwrap(),
                                                    E0521,
@@ -131,76 +130,6 @@ fn visit_item(&mut self, item: &'v hir::Item) {
                 }
             }
             hir::ItemImpl(.., Some(_), _, _) => {
-                let impl_def_id = self.tcx.hir.local_def_id(item.id);
-                let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
-                let trait_def_id = trait_ref.def_id;
-
-                if trait_ref.references_error() {
-                    debug!("coherence: skipping impl {:?} with error {:?}",
-                           impl_def_id, trait_ref);
-                    return
-                }
-
-                let _task =
-                    self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
-
-                let def = self.tcx.lookup_trait_def(trait_def_id);
-
-                // attempt to insert into the specialization graph
-                let insert_result = def.add_impl_for_specialization(self.tcx, impl_def_id);
-
-                // insertion failed due to overlap
-                if let Err(overlap) = insert_result {
-                    let mut err = struct_span_err!(self.tcx.sess,
-                                                   self.tcx.span_of_impl(impl_def_id).unwrap(),
-                                                   E0119,
-                                                   "conflicting implementations of trait `{}`{}:",
-                                                   overlap.trait_desc,
-                                                   overlap.self_desc.clone().map_or(String::new(),
-                                                                                    |ty| {
-                        format!(" for type `{}`", ty)
-                    }));
-
-                    match self.tcx.span_of_impl(overlap.with_impl) {
-                        Ok(span) => {
-                            err.span_label(span, &format!("first implementation here"));
-                            err.span_label(self.tcx.span_of_impl(impl_def_id).unwrap(),
-                                           &format!("conflicting implementation{}",
-                                                    overlap.self_desc
-                                                        .map_or(String::new(),
-                                                                |ty| format!(" for `{}`", ty))));
-                        }
-                        Err(cname) => {
-                            err.note(&format!("conflicting implementation in crate `{}`", cname));
-                        }
-                    }
-
-                    err.emit();
-                }
-
-                // check for overlap with the automatic `impl Trait for Trait`
-                if let ty::TyDynamic(ref data, ..) = trait_ref.self_ty().sty {
-                    // This is something like impl Trait1 for Trait2. Illegal
-                    // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
-
-                    if data.principal().map_or(true, |p| !self.tcx.is_object_safe(p.def_id())) {
-                        // This is an error, but it will be reported by wfcheck.  Ignore it here.
-                        // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
-                    } else {
-                        let mut supertrait_def_ids =
-                            traits::supertrait_def_ids(self.tcx,
-                                                       data.principal().unwrap().def_id());
-                        if supertrait_def_ids.any(|d| d == trait_def_id) {
-                            span_err!(self.tcx.sess,
-                                      item.span,
-                                      E0371,
-                                      "the object type `{}` automatically \
-                                       implements the trait `{}`",
-                                      trait_ref.self_ty(),
-                                      self.tcx.item_path_str(trait_def_id));
-                        }
-                    }
-                }
             }
             _ => {}
         }
index 8c98e2952ebe9ce155696b2779fe49535486c3bb..22247d2531aec32e821417765016ae4de0e0017f 100644 (file)
@@ -31,20 +31,7 @@ fn check_unsafety_coherence(&mut self,
                                 unsafety: hir::Unsafety,
                                 polarity: hir::ImplPolarity) {
         match self.tcx.impl_trait_ref(self.tcx.hir.local_def_id(item.id)) {
-            None => {
-                // Inherent impl.
-                match unsafety {
-                    hir::Unsafety::Normal => {
-                        // OK
-                    }
-                    hir::Unsafety::Unsafe => {
-                        span_err!(self.tcx.sess,
-                                  item.span,
-                                  E0197,
-                                  "inherent impls cannot be declared as unsafe");
-                    }
-                }
-            }
+            None => {}
 
             Some(trait_ref) => {
                 let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id);
@@ -100,7 +87,7 @@ fn visit_item(&mut self, item: &'v hir::Item) {
             hir::ItemDefaultImpl(unsafety, _) => {
                 self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive);
             }
-            hir::ItemImpl(unsafety, polarity, ref generics, ..) => {
+            hir::ItemImpl(unsafety, polarity, ref generics, Some(_), _, _) => {
                 self.check_unsafety_coherence(item, Some(generics), unsafety, polarity);
             }
             _ => {}
index 217405a81ec2dc7e5b01088fe0592b1aa670cfc6..7f413a0dfc3aba59ce1a3e27f7ed6e75e0f23112 100644 (file)
 for other items.
 
 There are some shortcomings in this design:
-
-- Before walking the set of supertraits for a given trait, you must
-  call `ensure_super_predicates` on that trait def-id. Otherwise,
-  `item_super_predicates` will result in ICEs.
 - Because the item generics include defaults, cycles through type
   parameter defaults are illegal even if those defaults are never
   employed. This is not necessarily a bug.
 use constrained_type_params as ctp;
 use middle::lang_items::SizedTraitLangItem;
 use middle::const_val::ConstVal;
-use rustc_const_eval::EvalHint::UncheckedExprHint;
+use middle::resolve_lifetime as rl;
 use rustc_const_eval::{ConstContext, report_const_eval_err};
 use rustc::ty::subst::Substs;
-use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer, ReprOptions};
+use rustc::ty::{ToPredicate, ReprOptions};
 use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
+use rustc::ty::maps::Providers;
 use rustc::ty::util::IntTypeExt;
 use rustc::dep_graph::DepNode;
-use util::common::{ErrorReported, MemoizationMap};
+use util::common::MemoizationMap;
 use util::nodemap::{NodeMap, FxHashMap};
-use CrateCtxt;
 
 use rustc_const_math::ConstInt;
 
 use std::cell::RefCell;
+use std::collections::BTreeMap;
 
-use syntax::{abi, ast, attr};
+use syntax::{abi, ast};
+use syntax::codemap::Spanned;
 use syntax::symbol::{Symbol, keywords};
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 
 use rustc::hir::{self, map as hir_map};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 ///////////////////////////////////////////////////////////////////////////
 // Main entry point
 
-pub fn collect_item_types(ccx: &CrateCtxt) {
-    let mut visitor = CollectItemTypesVisitor { ccx: ccx };
-    ccx.tcx.visit_all_item_likes_in_krate(DepNode::CollectItem, &mut visitor.as_deep_visitor());
+pub fn collect_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    let mut visitor = CollectItemTypesVisitor { tcx: tcx };
+    tcx.visit_all_item_likes_in_krate(DepNode::CollectItem, &mut visitor.as_deep_visitor());
+}
+
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        ty,
+        generics,
+        predicates,
+        super_predicates,
+        type_param_predicates,
+        trait_def,
+        adt_def,
+        impl_trait_ref,
+        ..*providers
+    };
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -102,29 +114,18 @@ pub fn collect_item_types(ccx: &CrateCtxt) {
 /// available in various different forms at various points in the
 /// process. So we can't just store a pointer to e.g. the AST or the
 /// parsed ty form, we have to be more flexible. To this end, the
-/// `ItemCtxt` is parameterized by a `GetTypeParameterBounds` object
-/// that it uses to satisfy `get_type_parameter_bounds` requests.
-/// This object might draw the information from the AST
-/// (`hir::Generics`) or it might draw from a `ty::GenericPredicates`
-/// or both (a tuple).
+/// `ItemCtxt` is parameterized by a `DefId` that it uses to satisfy
+/// `get_type_parameter_bounds` requests, drawing the information from
+/// the AST (`hir::Generics`), recursively.
 struct ItemCtxt<'a,'tcx:'a> {
-    ccx: &'a CrateCtxt<'a,'tcx>,
-    param_bounds: &'a (GetTypeParameterBounds<'tcx>+'a),
-}
-
-#[derive(Copy, Clone, PartialEq, Eq)]
-pub enum AstConvRequest {
-    GetGenerics(DefId),
-    GetItemTypeScheme(DefId),
-    GetTraitDef(DefId),
-    EnsureSuperPredicates(DefId),
-    GetTypeParameterBounds(ast::NodeId),
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    item_def_id: DefId,
 }
 
 ///////////////////////////////////////////////////////////////////////////
 
 struct CollectItemTypesVisitor<'a, 'tcx: 'a> {
-    ccx: &'a CrateCtxt<'a, 'tcx>
+    tcx: TyCtxt<'a, 'tcx, 'tcx>
 }
 
 impl<'a, 'tcx> CollectItemTypesVisitor<'a, 'tcx> {
@@ -168,9 +169,9 @@ impl<'a, 'tcx> CollectItemTypesVisitor<'a, 'tcx> {
     fn with_collect_item_sig<OP>(&self, id: ast::NodeId, op: OP)
         where OP: FnOnce()
     {
-        let def_id = self.ccx.tcx.hir.local_def_id(id);
-        self.ccx.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), || {
-            self.ccx.tcx.hir.read(id);
+        let def_id = self.tcx.hir.local_def_id(id);
+        self.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), || {
+            self.tcx.hir.read(id);
             op();
         });
     }
@@ -178,41 +179,52 @@ fn with_collect_item_sig<OP>(&self, id: ast::NodeId, op: OP)
 
 impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.ccx.tcx.hir)
+        NestedVisitorMap::OnlyBodies(&self.tcx.hir)
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item) {
-        self.with_collect_item_sig(item.id, || convert_item(self.ccx, item));
+        self.with_collect_item_sig(item.id, || convert_item(self.tcx, item));
         intravisit::walk_item(self, item);
     }
 
+    fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
+        for param in &generics.ty_params {
+            if param.default.is_some() {
+                let def_id = self.tcx.hir.local_def_id(param.id);
+                self.tcx.item_type(def_id);
+            }
+        }
+        intravisit::walk_generics(self, generics);
+    }
+
     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         if let hir::ExprClosure(..) = expr.node {
-            let def_id = self.ccx.tcx.hir.local_def_id(expr.id);
-            generics_of_def_id(self.ccx, def_id);
-            type_of_def_id(self.ccx, def_id);
+            let def_id = self.tcx.hir.local_def_id(expr.id);
+            self.tcx.item_generics(def_id);
+            self.tcx.item_type(def_id);
         }
         intravisit::walk_expr(self, expr);
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
         if let hir::TyImplTrait(..) = ty.node {
-            let def_id = self.ccx.tcx.hir.local_def_id(ty.id);
-            generics_of_def_id(self.ccx, def_id);
+            let def_id = self.tcx.hir.local_def_id(ty.id);
+            self.tcx.item_generics(def_id);
+            self.tcx.item_predicates(def_id);
         }
         intravisit::walk_ty(self, ty);
     }
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
         self.with_collect_item_sig(trait_item.id, || {
-            convert_trait_item(self.ccx, trait_item)
+            convert_trait_item(self.tcx, trait_item)
         });
         intravisit::walk_trait_item(self, trait_item);
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
         self.with_collect_item_sig(impl_item.id, || {
-            convert_impl_item(self.ccx, impl_item)
+            convert_impl_item(self.tcx, impl_item)
         });
         intravisit::walk_impl_item(self, impl_item);
     }
@@ -221,153 +233,13 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
 ///////////////////////////////////////////////////////////////////////////
 // Utility types and common code for the above passes.
 
-impl<'a,'tcx> CrateCtxt<'a,'tcx> {
-    fn icx(&'a self, param_bounds: &'a GetTypeParameterBounds<'tcx>) -> ItemCtxt<'a,'tcx> {
+impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
+    fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId)
+           -> ItemCtxt<'a,'tcx> {
         ItemCtxt {
-            ccx: self,
-            param_bounds: param_bounds,
-        }
-    }
-
-    fn cycle_check<F,R>(&self,
-                        span: Span,
-                        request: AstConvRequest,
-                        code: F)
-                        -> Result<R,ErrorReported>
-        where F: FnOnce() -> Result<R,ErrorReported>
-    {
-        {
-            let mut stack = self.stack.borrow_mut();
-            if let Some((i, _)) = stack.iter().enumerate().rev().find(|&(_, r)| *r == request) {
-                let cycle = &stack[i..];
-                self.report_cycle(span, cycle);
-                return Err(ErrorReported);
-            }
-            stack.push(request);
+            tcx: tcx,
+            item_def_id: item_def_id,
         }
-
-        let result = code();
-
-        self.stack.borrow_mut().pop();
-        result
-    }
-
-    fn report_cycle(&self,
-                    span: Span,
-                    cycle: &[AstConvRequest])
-    {
-        assert!(!cycle.is_empty());
-        let tcx = self.tcx;
-
-        let mut err = struct_span_err!(tcx.sess, span, E0391,
-            "unsupported cyclic reference between types/traits detected");
-        err.span_label(span, &format!("cyclic reference"));
-
-        match cycle[0] {
-            AstConvRequest::GetGenerics(def_id) |
-            AstConvRequest::GetItemTypeScheme(def_id) |
-            AstConvRequest::GetTraitDef(def_id) => {
-                err.note(
-                    &format!("the cycle begins when processing `{}`...",
-                             tcx.item_path_str(def_id)));
-            }
-            AstConvRequest::EnsureSuperPredicates(def_id) => {
-                err.note(
-                    &format!("the cycle begins when computing the supertraits of `{}`...",
-                             tcx.item_path_str(def_id)));
-            }
-            AstConvRequest::GetTypeParameterBounds(id) => {
-                let def = tcx.type_parameter_def(id);
-                err.note(
-                    &format!("the cycle begins when computing the bounds \
-                              for type parameter `{}`...",
-                             def.name));
-            }
-        }
-
-        for request in &cycle[1..] {
-            match *request {
-                AstConvRequest::GetGenerics(def_id) |
-                AstConvRequest::GetItemTypeScheme(def_id) |
-                AstConvRequest::GetTraitDef(def_id) => {
-                    err.note(
-                        &format!("...which then requires processing `{}`...",
-                                 tcx.item_path_str(def_id)));
-                }
-                AstConvRequest::EnsureSuperPredicates(def_id) => {
-                    err.note(
-                        &format!("...which then requires computing the supertraits of `{}`...",
-                                 tcx.item_path_str(def_id)));
-                }
-                AstConvRequest::GetTypeParameterBounds(id) => {
-                    let def = tcx.type_parameter_def(id);
-                    err.note(
-                        &format!("...which then requires computing the bounds \
-                                  for type parameter `{}`...",
-                                 def.name));
-                }
-            }
-        }
-
-        match cycle[0] {
-            AstConvRequest::GetGenerics(def_id) |
-            AstConvRequest::GetItemTypeScheme(def_id) |
-            AstConvRequest::GetTraitDef(def_id) => {
-                err.note(
-                    &format!("...which then again requires processing `{}`, completing the cycle.",
-                             tcx.item_path_str(def_id)));
-            }
-            AstConvRequest::EnsureSuperPredicates(def_id) => {
-                err.note(
-                    &format!("...which then again requires computing the supertraits of `{}`, \
-                              completing the cycle.",
-                             tcx.item_path_str(def_id)));
-            }
-            AstConvRequest::GetTypeParameterBounds(id) => {
-                let def = tcx.type_parameter_def(id);
-                err.note(
-                    &format!("...which then again requires computing the bounds \
-                              for type parameter `{}`, completing the cycle.",
-                             def.name));
-            }
-        }
-        err.emit();
-    }
-
-    /// Loads the trait def for a given trait, returning ErrorReported if a cycle arises.
-    fn get_trait_def(&self, def_id: DefId)
-                     -> &'tcx ty::TraitDef
-    {
-        let tcx = self.tcx;
-
-        if let Some(trait_id) = tcx.hir.as_local_node_id(def_id) {
-            let item = match tcx.hir.get(trait_id) {
-                hir_map::NodeItem(item) => item,
-                _ => bug!("get_trait_def({:?}): not an item", trait_id)
-            };
-
-            generics_of_def_id(self, def_id);
-            trait_def_of_item(self, &item)
-        } else {
-            tcx.lookup_trait_def(def_id)
-        }
-    }
-
-    /// Ensure that the (transitive) super predicates for
-    /// `trait_def_id` are available. This will report a cycle error
-    /// if a trait `X` (transitively) extends itself in some form.
-    fn ensure_super_predicates(&self, span: Span, trait_def_id: DefId)
-                               -> Result<(), ErrorReported>
-    {
-        self.cycle_check(span, AstConvRequest::EnsureSuperPredicates(trait_def_id), || {
-            let def_ids = ensure_super_predicates_step(self, trait_def_id);
-
-            for def_id in def_ids {
-                self.ensure_super_predicates(span, def_id)?;
-            }
-
-            Ok(())
-        })
     }
 }
 
@@ -378,58 +250,18 @@ fn to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
 }
 
 impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { self.ccx.tcx }
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { self.tcx }
 
     fn ast_ty_to_ty_cache(&self) -> &RefCell<NodeMap<Ty<'tcx>>> {
-        &self.ccx.ast_ty_to_ty_cache
-    }
-
-    fn get_generics(&self, span: Span, id: DefId)
-                    -> Result<&'tcx ty::Generics<'tcx>, ErrorReported>
-    {
-        self.ccx.cycle_check(span, AstConvRequest::GetGenerics(id), || {
-            Ok(generics_of_def_id(self.ccx, id))
-        })
-    }
-
-    fn get_item_type(&self, span: Span, id: DefId) -> Result<Ty<'tcx>, ErrorReported> {
-        self.ccx.cycle_check(span, AstConvRequest::GetItemTypeScheme(id), || {
-            Ok(type_of_def_id(self.ccx, id))
-        })
-    }
-
-    fn get_trait_def(&self, span: Span, id: DefId)
-                     -> Result<&'tcx ty::TraitDef, ErrorReported>
-    {
-        self.ccx.cycle_check(span, AstConvRequest::GetTraitDef(id), || {
-            Ok(self.ccx.get_trait_def(id))
-        })
+        &self.tcx.ast_ty_to_ty_cache
     }
 
-    fn ensure_super_predicates(&self,
-                               span: Span,
-                               trait_def_id: DefId)
-                               -> Result<(), ErrorReported>
-    {
-        debug!("ensure_super_predicates(trait_def_id={:?})",
-               trait_def_id);
-
-        self.ccx.ensure_super_predicates(span, trait_def_id)
-    }
-
-
     fn get_type_parameter_bounds(&self,
                                  span: Span,
-                                 node_id: ast::NodeId)
-                                 -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
+                                 def_id: DefId)
+                                 -> ty::GenericPredicates<'tcx>
     {
-        self.ccx.cycle_check(span, AstConvRequest::GetTypeParameterBounds(node_id), || {
-            let v = self.param_bounds.get_type_parameter_bounds(self, span, node_id)
-                                     .into_iter()
-                                     .filter_map(|p| p.to_opt_poly_trait_ref())
-                                     .collect();
-            Ok(v)
-        })
+        ty::queries::type_param_predicates::get(self.tcx, span, (self.item_def_id, def_id))
     }
 
     fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
@@ -483,120 +315,121 @@ fn set_tainted_by_errors(&self) {
     }
 }
 
-/// Interface used to find the bounds on a type parameter from within
-/// an `ItemCtxt`. This allows us to use multiple kinds of sources.
-trait GetTypeParameterBounds<'tcx> {
-    fn get_type_parameter_bounds(&self,
-                                 astconv: &AstConv<'tcx, 'tcx>,
-                                 span: Span,
-                                 node_id: ast::NodeId)
-                                 -> Vec<ty::Predicate<'tcx>>;
-}
-
-/// Find bounds from both elements of the tuple.
-impl<'a,'b,'tcx,A,B> GetTypeParameterBounds<'tcx> for (&'a A,&'b B)
-    where A : GetTypeParameterBounds<'tcx>, B : GetTypeParameterBounds<'tcx>
-{
-    fn get_type_parameter_bounds(&self,
-                                 astconv: &AstConv<'tcx, 'tcx>,
-                                 span: Span,
-                                 node_id: ast::NodeId)
-                                 -> Vec<ty::Predicate<'tcx>>
-    {
-        let mut v = self.0.get_type_parameter_bounds(astconv, span, node_id);
-        v.extend(self.1.get_type_parameter_bounds(astconv, span, node_id));
-        v
-    }
-}
+fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                   (item_def_id, def_id): (DefId, DefId))
+                                   -> ty::GenericPredicates<'tcx> {
+    use rustc::hir::map::*;
+    use rustc::hir::*;
+
+    // In the AST, bounds can derive from two places. Either
+    // written inline like `<T:Foo>` or in a where clause like
+    // `where T:Foo`.
+
+    let param_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let param_owner = tcx.hir.ty_param_owner(param_id);
+    let param_owner_def_id = tcx.hir.local_def_id(param_owner);
+    let generics = tcx.item_generics(param_owner_def_id);
+    let index = generics.type_param_to_index[&def_id.index];
+    let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id));
+
+    // Don't look for bounds where the type parameter isn't in scope.
+    let parent = if item_def_id == param_owner_def_id {
+        None
+    } else {
+        tcx.item_generics(item_def_id).parent
+    };
 
-/// Empty set of bounds.
-impl<'tcx> GetTypeParameterBounds<'tcx> for () {
-    fn get_type_parameter_bounds(&self,
-                                 _astconv: &AstConv<'tcx, 'tcx>,
-                                 _span: Span,
-                                 _node_id: ast::NodeId)
-                                 -> Vec<ty::Predicate<'tcx>>
-    {
-        Vec::new()
-    }
-}
+    let mut result = parent.map_or(ty::GenericPredicates {
+        parent: None,
+        predicates: vec![]
+    }, |parent| {
+        let icx = ItemCtxt::new(tcx, parent);
+        icx.get_type_parameter_bounds(DUMMY_SP, def_id)
+    });
 
-/// Find bounds from the parsed and converted predicates.  This is
-/// used when converting methods, because by that time the predicates
-/// from the trait/impl have been fully converted.
-impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> {
-    fn get_type_parameter_bounds(&self,
-                                 astconv: &AstConv<'tcx, 'tcx>,
-                                 span: Span,
-                                 node_id: ast::NodeId)
-                                 -> Vec<ty::Predicate<'tcx>>
-    {
-        let def = astconv.tcx().type_parameter_def(node_id);
+    let item_node_id = tcx.hir.as_local_node_id(item_def_id).unwrap();
+    let ast_generics = match tcx.hir.get(item_node_id) {
+        NodeTraitItem(item) => {
+            match item.node {
+                TraitItemKind::Method(ref sig, _) => &sig.generics,
+                _ => return result
+            }
+        }
 
-        let mut results = self.parent.map_or(vec![], |def_id| {
-            let parent = astconv.tcx().item_predicates(def_id);
-            parent.get_type_parameter_bounds(astconv, span, node_id)
-        });
+        NodeImplItem(item) => {
+            match item.node {
+                ImplItemKind::Method(ref sig, _) => &sig.generics,
+                _ => return result
+            }
+        }
 
-        results.extend(self.predicates.iter().filter(|predicate| {
-            match **predicate {
-                ty::Predicate::Trait(ref data) => {
-                    data.skip_binder().self_ty().is_param(def.index)
-                }
-                ty::Predicate::TypeOutlives(ref data) => {
-                    data.skip_binder().0.is_param(def.index)
-                }
-                ty::Predicate::Equate(..) |
-                ty::Predicate::RegionOutlives(..) |
-                ty::Predicate::WellFormed(..) |
-                ty::Predicate::ObjectSafe(..) |
-                ty::Predicate::ClosureKind(..) |
-                ty::Predicate::Projection(..) => {
-                    false
+        NodeItem(item) => {
+            match item.node {
+                ItemFn(.., ref generics, _) |
+                ItemImpl(_, _, ref generics, ..) |
+                ItemTy(_, ref generics) |
+                ItemEnum(_, ref generics) |
+                ItemStruct(_, ref generics) |
+                ItemUnion(_, ref generics) => generics,
+                ItemTrait(_, ref generics, ..) => {
+                    // Implied `Self: Trait` and supertrait bounds.
+                    if param_id == item_node_id {
+                        result.predicates.push(ty::TraitRef {
+                            def_id: item_def_id,
+                            substs: Substs::identity_for_item(tcx, item_def_id)
+                        }.to_predicate());
+                    }
+                    generics
                 }
+                _ => return result
             }
-        }).cloned());
+        }
 
-        results
-    }
-}
+        NodeForeignItem(item) => {
+            match item.node {
+                ForeignItemFn(_, _, ref generics) => generics,
+                _ => return result
+            }
+        }
 
-/// Find bounds from hir::Generics. This requires scanning through the
-/// AST. We do this to avoid having to convert *all* the bounds, which
-/// would create artificial cycles. Instead we can only convert the
-/// bounds for a type parameter `X` if `X::Foo` is used.
-impl<'tcx> GetTypeParameterBounds<'tcx> for hir::Generics {
-    fn get_type_parameter_bounds(&self,
-                                 astconv: &AstConv<'tcx, 'tcx>,
-                                 _: Span,
-                                 node_id: ast::NodeId)
-                                 -> Vec<ty::Predicate<'tcx>>
-    {
-        // In the AST, bounds can derive from two places. Either
-        // written inline like `<T:Foo>` or in a where clause like
-        // `where T:Foo`.
+        _ => return result
+    };
 
-        let def = astconv.tcx().type_parameter_def(node_id);
-        let ty = astconv.tcx().mk_param_from_def(&def);
+    let icx = ItemCtxt::new(tcx, item_def_id);
+    result.predicates.extend(
+        icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty));
+    result
+}
 
+impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
+    /// Find bounds from hir::Generics. This requires scanning through the
+    /// AST. We do this to avoid having to convert *all* the bounds, which
+    /// would create artificial cycles. Instead we can only convert the
+    /// bounds for a type parameter `X` if `X::Foo` is used.
+    fn type_parameter_bounds_in_generics(&self,
+                                         ast_generics: &hir::Generics,
+                                         param_id: ast::NodeId,
+                                         ty: Ty<'tcx>)
+                                         -> Vec<ty::Predicate<'tcx>>
+    {
         let from_ty_params =
-            self.ty_params
+            ast_generics.ty_params
                 .iter()
-                .filter(|p| p.id == node_id)
+                .filter(|p| p.id == param_id)
                 .flat_map(|p| p.bounds.iter())
-                .flat_map(|b| predicates_from_bound(astconv, ty, b));
+                .flat_map(|b| predicates_from_bound(self, ty, b));
 
         let from_where_clauses =
-            self.where_clause
+            ast_generics.where_clause
                 .predicates
                 .iter()
                 .filter_map(|wp| match *wp {
                     hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
                     _ => None
                 })
-                .filter(|bp| is_param(astconv.tcx(), &bp.bounded_ty, node_id))
+                .filter(|bp| is_param(self.tcx, &bp.bounded_ty, param_id))
                 .flat_map(|bp| bp.bounds.iter())
-                .flat_map(|b| predicates_from_bound(astconv, ty, b));
+                .flat_map(|b| predicates_from_bound(self, ty, b));
 
         from_ty_params.chain(from_where_clauses).collect()
     }
@@ -624,76 +457,10 @@ fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                           struct_generics: &'tcx ty::Generics<'tcx>,
-                           struct_predicates: &ty::GenericPredicates<'tcx>,
-                           field: &hir::StructField,
-                           ty_f: &'tcx ty::FieldDef)
-{
-    let tt = ccx.icx(struct_predicates).to_ty(&field.ty);
-    ccx.tcx.item_types.borrow_mut().insert(ty_f.did, tt);
-
-    let def_id = ccx.tcx.hir.local_def_id(field.id);
-    assert_eq!(def_id, ty_f.did);
-    ccx.tcx.generics.borrow_mut().insert(def_id, struct_generics);
-    ccx.tcx.predicates.borrow_mut().insert(def_id, struct_predicates.clone());
-}
-
-fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                            id: ast::NodeId,
-                            sig: &hir::MethodSig,
-                            rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,) {
-    let def_id = ccx.tcx.hir.local_def_id(id);
-    let ty_generics = generics_of_def_id(ccx, def_id);
-
-    let ty_generic_predicates =
-        ty_generic_predicates(ccx, &sig.generics, ty_generics.parent, vec![], false);
-
-    let fty = AstConv::ty_of_fn(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
-                                sig.unsafety, sig.abi, &sig.decl);
-
-    let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
-                                ccx.tcx.hir.span(id), def_id);
-    let fty = ccx.tcx.mk_fn_def(def_id, substs, fty);
-    ccx.tcx.item_types.borrow_mut().insert(def_id, fty);
-    ccx.tcx.predicates.borrow_mut().insert(def_id, ty_generic_predicates);
-}
-
-fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                      container: AssociatedItemContainer,
-                                      id: ast::NodeId,
-                                      ty: ty::Ty<'tcx>)
-{
-    let predicates = ty::GenericPredicates {
-        parent: Some(container.id()),
-        predicates: vec![]
-    };
-    let def_id = ccx.tcx.hir.local_def_id(id);
-    ccx.tcx.predicates.borrow_mut().insert(def_id, predicates);
-    ccx.tcx.item_types.borrow_mut().insert(def_id, ty);
-}
-
-fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                     container: AssociatedItemContainer,
-                                     id: ast::NodeId,
-                                     ty: Option<Ty<'tcx>>)
-{
-    let predicates = ty::GenericPredicates {
-        parent: Some(container.id()),
-        predicates: vec![]
-    };
-    let def_id = ccx.tcx.hir.local_def_id(id);
-    ccx.tcx.predicates.borrow_mut().insert(def_id, predicates);
-
-    if let Some(ty) = ty {
-        ccx.tcx.item_types.borrow_mut().insert(def_id, ty);
-    }
-}
-
-fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
-                                 span: Span,
-                                 generics: &hir::Generics,
-                                 thing: &'static str) {
+fn ensure_no_ty_param_bounds(tcx: TyCtxt,
+                             span: Span,
+                             generics: &hir::Generics,
+                             thing: &'static str) {
     let mut warn = false;
 
     for ty_param in generics.ty_params.iter() {
@@ -722,256 +489,183 @@ fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
         // eventually accept these, but it will not be
         // part of this PR. Still, convert to warning to
         // make bootstrapping easier.
-        span_warn!(ccx.tcx.sess, span, E0122,
+        span_warn!(tcx.sess, span, E0122,
                    "trait bounds are not (yet) enforced \
                    in {} definitions",
                    thing);
     }
 }
 
-fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
-    let tcx = ccx.tcx;
+fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) {
     debug!("convert: item {} with id {}", it.name, it.id);
-    let def_id = ccx.tcx.hir.local_def_id(it.id);
+    let def_id = tcx.hir.local_def_id(it.id);
     match it.node {
         // These don't define types.
         hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => {
         }
         hir::ItemForeignMod(ref foreign_mod) => {
             for item in &foreign_mod.items {
-                convert_foreign_item(ccx, item);
+                let def_id = tcx.hir.local_def_id(item.id);
+                tcx.item_generics(def_id);
+                tcx.item_type(def_id);
+                tcx.item_predicates(def_id);
             }
         }
         hir::ItemEnum(ref enum_definition, _) => {
-            let ty = type_of_def_id(ccx, def_id);
-            let generics = generics_of_def_id(ccx, def_id);
-            let predicates = predicates_of_item(ccx, it);
-            convert_enum_variant_types(ccx,
-                                       tcx.lookup_adt_def(ccx.tcx.hir.local_def_id(it.id)),
-                                       ty,
-                                       generics,
-                                       predicates,
-                                       &enum_definition.variants);
+            tcx.item_generics(def_id);
+            tcx.item_type(def_id);
+            tcx.item_predicates(def_id);
+            convert_enum_variant_types(tcx, def_id, &enum_definition.variants);
         },
-        hir::ItemDefaultImpl(_, ref ast_trait_ref) => {
-            let trait_ref =
-                AstConv::instantiate_mono_trait_ref(&ccx.icx(&()),
-                                                    ast_trait_ref,
-                                                    tcx.mk_self_type());
-
-            tcx.record_trait_has_default_impl(trait_ref.def_id);
-
-            tcx.impl_trait_refs.borrow_mut().insert(ccx.tcx.hir.local_def_id(it.id),
-                                                    Some(trait_ref));
+        hir::ItemDefaultImpl(..) => {
+            tcx.impl_trait_ref(def_id);
         }
-        hir::ItemImpl(..,
-                      ref generics,
-                      ref opt_trait_ref,
-                      ref selfty,
-                      _) => {
-            // Create generics from the generics specified in the impl head.
-            debug!("convert: ast_generics={:?}", generics);
-            generics_of_def_id(ccx, def_id);
-            let mut ty_predicates =
-                ty_generic_predicates(ccx, generics, None, vec![], false);
-
-            debug!("convert: impl_bounds={:?}", ty_predicates);
-
-            let selfty = ccx.icx(&ty_predicates).to_ty(&selfty);
-            tcx.item_types.borrow_mut().insert(def_id, selfty);
-
-            let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| {
-                AstConv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
-                                                    ast_trait_ref,
-                                                    selfty)
-            });
-            tcx.impl_trait_refs.borrow_mut().insert(def_id, trait_ref);
-
-            // Subtle: before we store the predicates into the tcx, we
-            // sort them so that predicates like `T: Foo<Item=U>` come
-            // before uses of `U`.  This avoids false ambiguity errors
-            // in trait checking. See `setup_constraining_predicates`
-            // for details.
-            ctp::setup_constraining_predicates(&mut ty_predicates.predicates,
-                                               trait_ref,
-                                               &mut ctp::parameters_for_impl(selfty, trait_ref));
-
-            tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone());
+        hir::ItemImpl(..) => {
+            tcx.item_generics(def_id);
+            tcx.item_type(def_id);
+            tcx.impl_trait_ref(def_id);
+            tcx.item_predicates(def_id);
         },
         hir::ItemTrait(..) => {
-            generics_of_def_id(ccx, def_id);
-            trait_def_of_item(ccx, it);
-            let _: Result<(), ErrorReported> = // any error is already reported, can ignore
-                ccx.ensure_super_predicates(it.span, def_id);
-            convert_trait_predicates(ccx, it);
+            tcx.item_generics(def_id);
+            tcx.lookup_trait_def(def_id);
+            ty::queries::super_predicates::get(tcx, it.span, def_id);
+            tcx.item_predicates(def_id);
         },
         hir::ItemStruct(ref struct_def, _) |
         hir::ItemUnion(ref struct_def, _) => {
-            let ty = type_of_def_id(ccx, def_id);
-            let generics = generics_of_def_id(ccx, def_id);
-            let predicates = predicates_of_item(ccx, it);
-
-            let variant = tcx.lookup_adt_def(def_id).struct_variant();
-
-            for (f, ty_f) in struct_def.fields().iter().zip(variant.fields.iter()) {
-                convert_field(ccx, generics, &predicates, f, ty_f)
+            tcx.item_generics(def_id);
+            tcx.item_type(def_id);
+            tcx.item_predicates(def_id);
+
+            for f in struct_def.fields() {
+                let def_id = tcx.hir.local_def_id(f.id);
+                tcx.item_generics(def_id);
+                tcx.item_type(def_id);
+                tcx.item_predicates(def_id);
             }
 
             if !struct_def.is_struct() {
-                convert_variant_ctor(ccx, struct_def.id(), variant, ty, predicates);
+                convert_variant_ctor(tcx, struct_def.id());
             }
         },
         hir::ItemTy(_, ref generics) => {
-            ensure_no_ty_param_bounds(ccx, it.span, generics, "type");
-            type_of_def_id(ccx, def_id);
-            generics_of_def_id(ccx, def_id);
-            predicates_of_item(ccx, it);
+            ensure_no_ty_param_bounds(tcx, it.span, generics, "type");
+            tcx.item_generics(def_id);
+            tcx.item_type(def_id);
+            tcx.item_predicates(def_id);
         },
         _ => {
-            type_of_def_id(ccx, def_id);
-            generics_of_def_id(ccx, def_id);
-            predicates_of_item(ccx, it);
+            tcx.item_generics(def_id);
+            tcx.item_type(def_id);
+            tcx.item_predicates(def_id);
         },
     }
 }
 
-fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) {
-    let tcx = ccx.tcx;
-
-    // we can lookup details about the trait because items are visited
-    // before trait-items
-    let trait_def_id = tcx.hir.get_parent_did(trait_item.id);
-    let trait_predicates = tcx.item_predicates(trait_def_id);
+fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::TraitItem) {
+    let def_id = tcx.hir.local_def_id(trait_item.id);
+    tcx.item_generics(def_id);
 
     match trait_item.node {
-        hir::TraitItemKind::Const(ref ty, _) => {
-            let const_def_id = ccx.tcx.hir.local_def_id(trait_item.id);
-            generics_of_def_id(ccx, const_def_id);
-            let ty = ccx.icx(&trait_predicates).to_ty(&ty);
-            convert_associated_const(ccx,
-                                     TraitContainer(trait_def_id),
-                                     trait_item.id,
-                                     ty);
+        hir::TraitItemKind::Const(..) |
+        hir::TraitItemKind::Type(_, Some(_)) |
+        hir::TraitItemKind::Method(..) => {
+            tcx.item_type(def_id);
         }
 
-        hir::TraitItemKind::Type(_, ref opt_ty) => {
-            let type_def_id = ccx.tcx.hir.local_def_id(trait_item.id);
-            generics_of_def_id(ccx, type_def_id);
-
-            let typ = opt_ty.as_ref().map({
-                |ty| ccx.icx(&trait_predicates).to_ty(&ty)
-            });
-
-            convert_associated_type(ccx, TraitContainer(trait_def_id), trait_item.id, typ);
-        }
+        hir::TraitItemKind::Type(_, None) => {}
+    };
 
-        hir::TraitItemKind::Method(ref sig, _) => {
-            convert_method(ccx, trait_item.id, sig, &trait_predicates);
-        }
-    }
+    tcx.item_predicates(def_id);
 }
 
-fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
-    let tcx = ccx.tcx;
-
-    // we can lookup details about the impl because items are visited
-    // before impl-items
-    let impl_def_id = tcx.hir.get_parent_did(impl_item.id);
-    let impl_predicates = tcx.item_predicates(impl_def_id);
-    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
-
-    match impl_item.node {
-        hir::ImplItemKind::Const(ref ty, _) => {
-            let const_def_id = ccx.tcx.hir.local_def_id(impl_item.id);
-            generics_of_def_id(ccx, const_def_id);
-            let ty = ccx.icx(&impl_predicates).to_ty(&ty);
-            convert_associated_const(ccx,
-                                     ImplContainer(impl_def_id),
-                                     impl_item.id,
-                                     ty);
-        }
-
-        hir::ImplItemKind::Type(ref ty) => {
-            let type_def_id = ccx.tcx.hir.local_def_id(impl_item.id);
-            generics_of_def_id(ccx, type_def_id);
-
-            if impl_trait_ref.is_none() {
-                span_err!(tcx.sess, impl_item.span, E0202,
-                          "associated types are not allowed in inherent impls");
-            }
-
-            let typ = ccx.icx(&impl_predicates).to_ty(ty);
-
-            convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ));
-        }
-
-        hir::ImplItemKind::Method(ref sig, _) => {
-            convert_method(ccx, impl_item.id, sig, &impl_predicates);
-        }
-    }
+fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item: &hir::ImplItem) {
+    let def_id = tcx.hir.local_def_id(impl_item.id);
+    tcx.item_generics(def_id);
+    tcx.item_type(def_id);
+    tcx.item_predicates(def_id);
 }
 
-fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                  ctor_id: ast::NodeId,
-                                  variant: &'tcx ty::VariantDef,
-                                  ty: Ty<'tcx>,
-                                  predicates: ty::GenericPredicates<'tcx>) {
-    let tcx = ccx.tcx;
+fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                  ctor_id: ast::NodeId) {
     let def_id = tcx.hir.local_def_id(ctor_id);
-    generics_of_def_id(ccx, def_id);
-    let ctor_ty = match variant.ctor_kind {
-        CtorKind::Fictive | CtorKind::Const => ty,
-        CtorKind::Fn => {
-            let inputs = variant.fields.iter().map(|field| tcx.item_type(field.did));
-            let substs = mk_item_substs(&ccx.icx(&predicates), ccx.tcx.hir.span(ctor_id), def_id);
-            tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy {
-                unsafety: hir::Unsafety::Normal,
-                abi: abi::Abi::Rust,
-                sig: ty::Binder(ccx.tcx.mk_fn_sig(inputs, ty, false))
-            }))
-        }
-    };
-    tcx.item_types.borrow_mut().insert(def_id, ctor_ty);
-    tcx.predicates.borrow_mut().insert(tcx.hir.local_def_id(ctor_id), predicates);
+    tcx.item_generics(def_id);
+    tcx.item_type(def_id);
+    tcx.item_predicates(def_id);
 }
 
-fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                        def: &'tcx ty::AdtDef,
-                                        ty: Ty<'tcx>,
-                                        generics: &'tcx ty::Generics<'tcx>,
-                                        predicates: ty::GenericPredicates<'tcx>,
+fn evaluate_disr_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                body: hir::BodyId)
+                                -> Result<ConstVal<'tcx>, ()> {
+    let e = &tcx.hir.body(body).value;
+    ConstContext::new(tcx, body).eval(e).map_err(|err| {
+        // enum variant evaluation happens before the global constant check
+        // so we need to report the real error
+        report_const_eval_err(tcx, &err, e.span, "enum discriminant");
+    })
+}
+
+fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                        def_id: DefId,
                                         variants: &[hir::Variant]) {
-    // fill the field types
-    for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) {
-        for (f, ty_f) in variant.node.data.fields().iter().zip(ty_variant.fields.iter()) {
-            convert_field(ccx, generics, &predicates, f, ty_f)
+    let def = tcx.lookup_adt_def(def_id);
+    let repr_type = def.repr.discr_type();
+    let initial = repr_type.initial_discriminant(tcx);
+    let mut prev_discr = None::<ConstInt>;
+
+    // fill the discriminant values and field types
+    for variant in variants {
+        let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr());
+        prev_discr = Some(if let Some(e) = variant.node.disr_expr {
+            let expr_did = tcx.hir.local_def_id(e.node_id);
+            let result = tcx.maps.monomorphic_const_eval.memoize(expr_did, || {
+                evaluate_disr_expr(tcx, e)
+            });
+
+            match result {
+                Ok(ConstVal::Integral(x)) => Some(x),
+                _ => None
+            }
+        } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
+            Some(discr)
+        } else {
+            struct_span_err!(tcx.sess, variant.span, E0370,
+                             "enum discriminant overflowed")
+                .span_label(variant.span, &format!("overflowed on value after {}",
+                                                   prev_discr.unwrap()))
+                .note(&format!("explicitly set `{} = {}` if that is desired outcome",
+                               variant.node.name, wrapped_discr))
+                .emit();
+            None
+        }.unwrap_or(wrapped_discr));
+
+        for f in variant.node.data.fields() {
+            let def_id = tcx.hir.local_def_id(f.id);
+            tcx.item_generics(def_id);
+            tcx.item_type(def_id);
+            tcx.item_predicates(def_id);
         }
 
         // Convert the ctor, if any. This also registers the variant as
         // an item.
-        convert_variant_ctor(
-            ccx,
-            variant.node.data.id(),
-            ty_variant,
-            ty,
-            predicates.clone()
-        );
+        convert_variant_ctor(tcx, variant.node.data.id());
     }
 }
 
-fn convert_struct_variant<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn convert_struct_variant<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     did: DefId,
                                     name: ast::Name,
-                                    disr_val: ty::Disr,
+                                    discr: ty::VariantDiscr,
                                     def: &hir::VariantData)
                                     -> ty::VariantDef {
     let mut seen_fields: FxHashMap<ast::Name, Span> = FxHashMap();
-    let node_id = ccx.tcx.hir.as_local_node_id(did).unwrap();
+    let node_id = tcx.hir.as_local_node_id(did).unwrap();
     let fields = def.fields().iter().map(|f| {
-        let fid = ccx.tcx.hir.local_def_id(f.id);
+        let fid = tcx.hir.local_def_id(f.id);
         let dup_span = seen_fields.get(&f.name).cloned();
         if let Some(prev_span) = dup_span {
-            struct_span_err!(ccx.tcx.sess, f.span, E0124,
+            struct_span_err!(tcx.sess, f.span, E0124,
                              "field `{}` is already declared",
                              f.name)
                 .span_label(f.span, &"field already declared")
@@ -984,647 +678,524 @@ fn convert_struct_variant<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         ty::FieldDef {
             did: fid,
             name: f.name,
-            vis: ty::Visibility::from_hir(&f.vis, node_id, ccx.tcx)
+            vis: ty::Visibility::from_hir(&f.vis, node_id, tcx)
         }
     }).collect();
     ty::VariantDef {
         did: did,
         name: name,
-        disr_val: disr_val,
+        discr: discr,
         fields: fields,
         ctor_kind: CtorKind::from_hir(def),
     }
 }
 
-fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                it: &hir::Item,
-                                def: &hir::VariantData)
-                                -> &'tcx ty::AdtDef
-{
-    let did = ccx.tcx.hir.local_def_id(it.id);
-    // Use separate constructor id for unit/tuple structs and reuse did for braced structs.
-    let ctor_id = if !def.is_struct() { Some(ccx.tcx.hir.local_def_id(def.id())) } else { None };
-    let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name, 0, def)];
-    let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Struct, None, variants,
-        ReprOptions::new(&ccx.tcx, did));
-    if let Some(ctor_id) = ctor_id {
-        // Make adt definition available through constructor id as well.
-        ccx.tcx.adt_defs.borrow_mut().insert(ctor_id, adt);
-    }
+fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                     def_id: DefId)
+                     -> &'tcx ty::AdtDef {
+    use rustc::hir::map::*;
+    use rustc::hir::*;
 
-    ccx.tcx.adt_defs.borrow_mut().insert(did, adt);
-    adt
-}
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let item = match tcx.hir.get(node_id) {
+        NodeItem(item) => item,
 
-fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                it: &hir::Item,
-                                def: &hir::VariantData)
-                                -> &'tcx ty::AdtDef
-{
-    let did = ccx.tcx.hir.local_def_id(it.id);
-    let variants = vec![convert_struct_variant(ccx, did, it.name, 0, def)];
-    let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, None, variants,
-                                    ReprOptions::new(&ccx.tcx, did));
-    ccx.tcx.adt_defs.borrow_mut().insert(did, adt);
-    adt
-}
+        // Make adt definition available through constructor id as well.
+        NodeStructCtor(_) => {
+            return tcx.lookup_adt_def(tcx.hir.get_parent_did(node_id));
+        }
 
-fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId)
-                      -> Option<ConstInt> {
-    let e = &ccx.tcx.hir.body(body).value;
-    debug!("disr expr, checking {}", ccx.tcx.hir.node_to_pretty_string(e.id));
-
-    let ty_hint = repr_ty.to_ty(ccx.tcx);
-    let print_err = |cv: ConstVal| {
-        struct_span_err!(ccx.tcx.sess, e.span, E0079, "mismatched types")
-            .note_expected_found(&"type", &ty_hint, &format!("{}", cv.description()))
-            .span_label(e.span, &format!("expected '{}' type", ty_hint))
-            .emit();
+        _ => bug!()
     };
 
-    let hint = UncheckedExprHint(ty_hint);
-    match ConstContext::new(ccx.tcx, body).eval(e, hint) {
-        Ok(ConstVal::Integral(i)) => {
-            // FIXME: eval should return an error if the hint does not match the type of the body.
-            // i.e. eventually the match below would not exist.
-            match (repr_ty, i) {
-                (attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) |
-                (attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) |
-                (attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) |
-                (attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) |
-                (attr::SignedInt(ast::IntTy::I128), ConstInt::I128(_)) |
-                (attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) |
-                (attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) |
-                (attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) |
-                (attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) |
-                (attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) |
-                (attr::UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) |
-                (attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) =>
-                    Some(i),
-                (_, i) => {
-                    print_err(ConstVal::Integral(i));
-                    None
-                },
-            }
-        },
-        Ok(cv) => {
-            print_err(cv);
-            None
-        },
-        // enum variant evaluation happens before the global constant check
-        // so we need to report the real error
-        Err(err) => {
-            let mut diag = report_const_eval_err(
-                ccx.tcx, &err, e.span, "enum discriminant");
-            diag.emit();
-            None
+    let repr = ReprOptions::new(tcx, def_id);
+    let (kind, variants) = match item.node {
+        ItemEnum(ref def, _) => {
+            let mut distance_from_explicit = 0;
+            (AdtKind::Enum, def.variants.iter().map(|v| {
+                let did = tcx.hir.local_def_id(v.node.data.id());
+                let discr = if let Some(e) = v.node.disr_expr {
+                    distance_from_explicit = 0;
+                    ty::VariantDiscr::Explicit(tcx.hir.local_def_id(e.node_id))
+                } else {
+                    ty::VariantDiscr::Relative(distance_from_explicit)
+                };
+                distance_from_explicit += 1;
+
+                convert_struct_variant(tcx, did, v.node.name, discr, &v.node.data)
+            }).collect())
         }
-    }
-}
-
-fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                              it: &hir::Item,
-                              def: &hir::EnumDef)
-                              -> &'tcx ty::AdtDef
-{
-    let tcx = ccx.tcx;
-    let did = tcx.hir.local_def_id(it.id);
-    let repr_hints = tcx.lookup_repr_hints(did);
-    let repr_type = tcx.enum_repr_type(repr_hints.get(0));
-    let initial = ConstInt::new_inttype(repr_type.initial_discriminant(tcx), repr_type,
-                                        tcx.sess.target.uint_type, tcx.sess.target.int_type)
-        .unwrap();
-    let mut prev_disr = None::<ConstInt>;
-    let variants = def.variants.iter().map(|v| {
-        let wrapped_disr = prev_disr.map_or(initial, |d| d.wrap_incr());
-        let disr = if let Some(e) = v.node.disr_expr {
-            // FIXME: i128 discriminants
-            evaluate_disr_expr(ccx, repr_type, e)
-        } else if let Some(disr) = prev_disr.map_or(Some(initial),
-                                                    |v| (v + ConstInt::Infer(1)).ok()) {
-            Some(disr)
-        } else {
-            struct_span_err!(tcx.sess, v.span, E0370,
-                             "enum discriminant overflowed")
-                .span_label(v.span, &format!("overflowed on value after {}", prev_disr.unwrap()))
-                .note(&format!("explicitly set `{} = {}` if that is desired outcome",
-                               v.node.name, wrapped_disr))
-                .emit();
-            None
-        }.unwrap_or(wrapped_disr);
-        prev_disr = Some(disr);
-        let did = tcx.hir.local_def_id(v.node.data.id());
-        convert_struct_variant(ccx, did, v.node.name, disr.to_u128_unchecked(), &v.node.data)
-    }).collect();
-    let adt = tcx.alloc_adt_def(did, AdtKind::Enum, Some(repr_type), variants,
-                                ReprOptions::new(&ccx.tcx, did));
-    tcx.adt_defs.borrow_mut().insert(did, adt);
-    adt
+        ItemStruct(ref def, _) => {
+            // Use separate constructor id for unit/tuple structs and reuse did for braced structs.
+            let ctor_id = if !def.is_struct() {
+                Some(tcx.hir.local_def_id(def.id()))
+            } else {
+                None
+            };
+            (AdtKind::Struct, vec![
+                convert_struct_variant(tcx, ctor_id.unwrap_or(def_id), item.name,
+                                       ty::VariantDiscr::Relative(0), def)
+            ])
+        }
+        ItemUnion(ref def, _) => {
+            (AdtKind::Union, vec![
+                convert_struct_variant(tcx, def_id, item.name,
+                                       ty::VariantDiscr::Relative(0), def)
+            ])
+        }
+        _ => bug!()
+    };
+    tcx.alloc_adt_def(def_id, kind, variants, repr)
 }
 
 /// Ensures that the super-predicates of the trait with def-id
-/// trait_def_id are converted and stored. This does NOT ensure that
-/// the transitive super-predicates are converted; that is the job of
-/// the `ensure_super_predicates()` method in the `AstConv` impl
-/// above. Returns a list of trait def-ids that must be ensured as
-/// well to guarantee that the transitive superpredicates are
-/// converted.
-fn ensure_super_predicates_step(ccx: &CrateCtxt,
-                                trait_def_id: DefId)
-                                -> Vec<DefId>
-{
-    let tcx = ccx.tcx;
-
-    debug!("ensure_super_predicates_step(trait_def_id={:?})", trait_def_id);
+/// trait_def_id are converted and stored. This also ensures that
+/// the transitive super-predicates are converted;
+fn super_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                              trait_def_id: DefId)
+                              -> ty::GenericPredicates<'tcx> {
+    debug!("super_predicates(trait_def_id={:?})", trait_def_id);
+    let trait_node_id = tcx.hir.as_local_node_id(trait_def_id).unwrap();
+
+    let item = match tcx.hir.get(trait_node_id) {
+        hir_map::NodeItem(item) => item,
+        _ => bug!("trait_node_id {} is not an item", trait_node_id)
+    };
 
-    let trait_node_id = if let Some(n) = tcx.hir.as_local_node_id(trait_def_id) {
-        n
-    } else {
-        // If this trait comes from an external crate, then all of the
-        // supertraits it may depend on also must come from external
-        // crates, and hence all of them already have their
-        // super-predicates "converted" (and available from crate
-        // meta-data), so there is no need to transitively test them.
-        return Vec::new();
+    let (generics, bounds) = match item.node {
+        hir::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits),
+        _ => span_bug!(item.span,
+                       "super_predicates invoked on non-trait"),
     };
 
-    let superpredicates = tcx.super_predicates.borrow().get(&trait_def_id).cloned();
-    let superpredicates = superpredicates.unwrap_or_else(|| {
-        let item = match ccx.tcx.hir.get(trait_node_id) {
-            hir_map::NodeItem(item) => item,
-            _ => bug!("trait_node_id {} is not an item", trait_node_id)
-        };
+    let icx = ItemCtxt::new(tcx, trait_def_id);
 
-        let (generics, bounds) = match item.node {
-            hir::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits),
-            _ => span_bug!(item.span,
-                           "ensure_super_predicates_step invoked on non-trait"),
-        };
+    // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`.
+    let self_param_ty = tcx.mk_self_type();
+    let superbounds1 = compute_bounds(&icx,
+                                      self_param_ty,
+                                      bounds,
+                                      SizedByDefault::No,
+                                      item.span);
 
-        // In-scope when converting the superbounds for `Trait` are
-        // that `Self:Trait` as well as any bounds that appear on the
-        // generic types:
-        generics_of_def_id(ccx, trait_def_id);
-        trait_def_of_item(ccx, item);
-        let trait_ref = ty::TraitRef {
-            def_id: trait_def_id,
-            substs: Substs::identity_for_item(tcx, trait_def_id)
-        };
-        let self_predicate = ty::GenericPredicates {
-            parent: None,
-            predicates: vec![trait_ref.to_predicate()]
-        };
-        let scope = &(generics, &self_predicate);
-
-        // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`.
-        let self_param_ty = tcx.mk_self_type();
-        let superbounds1 = compute_bounds(&ccx.icx(scope),
-                                          self_param_ty,
-                                          bounds,
-                                          SizedByDefault::No,
-                                          item.span);
-
-        let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
-
-        // Convert any explicit superbounds in the where clause,
-        // e.g. `trait Foo where Self : Bar`:
-        let superbounds2 = generics.get_type_parameter_bounds(&ccx.icx(scope), item.span, item.id);
-
-        // Combine the two lists to form the complete set of superbounds:
-        let superbounds = superbounds1.into_iter().chain(superbounds2).collect();
-        let superpredicates = ty::GenericPredicates {
-            parent: None,
-            predicates: superbounds
-        };
-        debug!("superpredicates for trait {:?} = {:?}",
-               tcx.hir.local_def_id(item.id),
-               superpredicates);
+    let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
 
-        tcx.super_predicates.borrow_mut().insert(trait_def_id, superpredicates.clone());
+    // Convert any explicit superbounds in the where clause,
+    // e.g. `trait Foo where Self : Bar`:
+    let superbounds2 = icx.type_parameter_bounds_in_generics(generics, item.id, self_param_ty);
 
-        superpredicates
-    });
+    // Combine the two lists to form the complete set of superbounds:
+    let superbounds: Vec<_> = superbounds1.into_iter().chain(superbounds2).collect();
+
+    // Now require that immediate supertraits are converted,
+    // which will, in turn, reach indirect supertraits.
+    for bound in superbounds.iter().filter_map(|p| p.to_opt_poly_trait_ref()) {
+        ty::queries::super_predicates::get(tcx, item.span, bound.def_id());
+    }
+
+    ty::GenericPredicates {
+        parent: None,
+        predicates: superbounds
+    }
+}
+
+fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                       def_id: DefId)
+                       -> &'tcx ty::TraitDef {
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let item = tcx.hir.expect_item(node_id);
+
+    let unsafety = match item.node {
+        hir::ItemTrait(unsafety, ..) => unsafety,
+        _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
+    };
+
+    let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar");
+    if paren_sugar && !tcx.sess.features.borrow().unboxed_closures {
+        let mut err = tcx.sess.struct_span_err(
+            item.span,
+            "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \
+             which traits can use parenthetical notation");
+        help!(&mut err,
+            "add `#![feature(unboxed_closures)]` to \
+             the crate attributes to use it");
+        err.emit();
+    }
 
-    let def_ids: Vec<_> = superpredicates.predicates
-                                         .iter()
-                                         .filter_map(|p| p.to_opt_poly_trait_ref())
-                                         .map(|tr| tr.def_id())
-                                         .collect();
+    let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx);
+    let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, def_path_hash);
 
-    debug!("ensure_super_predicates_step: def_ids={:?}", def_ids);
+    if tcx.hir.trait_is_auto(def_id) {
+        def.record_has_default_impl();
+    }
 
-    def_ids
+    tcx.alloc_trait_def(def)
 }
 
-fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) -> &'tcx ty::TraitDef {
-    let def_id = ccx.tcx.hir.local_def_id(it.id);
-    let tcx = ccx.tcx;
+fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                      def_id: DefId)
+                      -> &'tcx ty::Generics {
+    use rustc::hir::map::*;
+    use rustc::hir::*;
+
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+
+    let node = tcx.hir.get(node_id);
+    let parent_def_id = match node {
+        NodeImplItem(_) |
+        NodeTraitItem(_) |
+        NodeVariant(_) |
+        NodeStructCtor(_) |
+        NodeField(_) => {
+            let parent_id = tcx.hir.get_parent(node_id);
+            Some(tcx.hir.local_def_id(parent_id))
+        }
+        NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
+            Some(tcx.closure_base_def_id(def_id))
+        }
+        NodeTy(&hir::Ty { node: hir::TyImplTrait(..), .. }) => {
+            let mut parent_id = node_id;
+            loop {
+                match tcx.hir.get(parent_id) {
+                    NodeItem(_) | NodeImplItem(_) | NodeTraitItem(_) => break,
+                    _ => {
+                        parent_id = tcx.hir.get_parent_node(parent_id);
+                    }
+                }
+            }
+            Some(tcx.hir.local_def_id(parent_id))
+        }
+        _ => None
+    };
 
-    tcx.trait_defs.memoize(def_id, || {
-        let unsafety = match it.node {
-            hir::ItemTrait(unsafety, ..) => unsafety,
-            _ => span_bug!(it.span, "trait_def_of_item invoked on non-trait"),
-        };
+    let mut opt_self = None;
+    let mut allow_defaults = false;
 
-        let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar");
-        if paren_sugar && !ccx.tcx.sess.features.borrow().unboxed_closures {
-            let mut err = ccx.tcx.sess.struct_span_err(
-                it.span,
-                "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \
-                which traits can use parenthetical notation");
-            help!(&mut err,
-                "add `#![feature(unboxed_closures)]` to \
-                the crate attributes to use it");
-            err.emit();
+    let no_generics = hir::Generics::empty();
+    let ast_generics = match node {
+        NodeTraitItem(item) => {
+            match item.node {
+                TraitItemKind::Method(ref sig, _) => &sig.generics,
+                _ => &no_generics
+            }
         }
 
-        let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx);
-        tcx.alloc_trait_def(ty::TraitDef::new(def_id, unsafety, paren_sugar, def_path_hash))
-    })
-}
+        NodeImplItem(item) => {
+            match item.node {
+                ImplItemKind::Method(ref sig, _) => &sig.generics,
+                _ => &no_generics
+            }
+        }
 
-fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) {
-    let tcx = ccx.tcx;
+        NodeItem(item) => {
+            match item.node {
+                ItemFn(.., ref generics, _) |
+                ItemImpl(_, _, ref generics, ..) => generics,
+
+                ItemTy(_, ref generics) |
+                ItemEnum(_, ref generics) |
+                ItemStruct(_, ref generics) |
+                ItemUnion(_, ref generics) => {
+                    allow_defaults = true;
+                    generics
+                }
 
-    let def_id = ccx.tcx.hir.local_def_id(it.id);
+                ItemTrait(_, ref generics, ..) => {
+                    // Add in the self type parameter.
+                    //
+                    // Something of a hack: use the node id for the trait, also as
+                    // the node id for the Self type parameter.
+                    let param_id = item.id;
+
+                    opt_self = Some(ty::TypeParameterDef {
+                        index: 0,
+                        name: keywords::SelfType.name(),
+                        def_id: tcx.hir.local_def_id(param_id),
+                        has_default: false,
+                        object_lifetime_default: rl::Set1::Empty,
+                        pure_wrt_drop: false,
+                    });
+
+                    allow_defaults = true;
+                    generics
+                }
 
-    generics_of_def_id(ccx, def_id);
-    trait_def_of_item(ccx, it);
+                _ => &no_generics
+            }
+        }
 
-    let (generics, items) = match it.node {
-        hir::ItemTrait(_, ref generics, _, ref items) => (generics, items),
-        ref s => {
-            span_bug!(
-                it.span,
-                "trait_def_of_item invoked on {:?}",
-                s);
+        NodeForeignItem(item) => {
+            match item.node {
+                ForeignItemStatic(..) => &no_generics,
+                ForeignItemFn(_, _, ref generics) => generics
+            }
         }
+
+        _ => &no_generics
     };
 
-    let super_predicates = ccx.tcx.item_super_predicates(def_id);
+    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 = tcx.item_generics(def_id);
+        assert_eq!(has_self, false);
+        parent_has_self = generics.has_self;
+        own_start = generics.count() as u32;
+        (generics.parent_regions + generics.regions.len() as u32,
+            generics.parent_types + generics.types.len() as u32)
+    });
 
-    // `ty_generic_predicates` below will consider the bounds on the type
-    // parameters (including `Self`) and the explicit where-clauses,
-    // but to get the full set of predicates on a trait we need to add
-    // in the supertrait bounds and anything declared on the
-    // associated types.
-    let mut base_predicates = super_predicates.predicates;
+    let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
+    let regions = early_lifetimes.enumerate().map(|(i, l)| {
+        let issue_32330 = tcx.named_region_map.issue_32330.get(&l.lifetime.id).cloned();
+        ty::RegionParameterDef {
+            name: l.lifetime.name,
+            index: own_start + i as u32,
+            def_id: tcx.hir.local_def_id(l.lifetime.id),
+            pure_wrt_drop: l.pure_wrt_drop,
+            issue_32330: issue_32330,
+        }
+    }).collect::<Vec<_>>();
 
-    // Add in a predicate that `Self:Trait` (where `Trait` is the
-    // current trait).  This is needed for builtin bounds.
-    let trait_ref = ty::TraitRef {
-        def_id: def_id,
-        substs: Substs::identity_for_item(tcx, def_id)
-    };
-    let self_predicate = trait_ref.to_poly_trait_ref().to_predicate();
-    base_predicates.push(self_predicate);
-
-    // add in the explicit where-clauses
-    let mut trait_predicates =
-        ty_generic_predicates(ccx, generics, None, base_predicates, true);
-
-    let assoc_predicates = predicates_for_associated_types(ccx,
-                                                           generics,
-                                                           &trait_predicates,
-                                                           trait_ref,
-                                                           items);
-    trait_predicates.predicates.extend(assoc_predicates);
-
-    tcx.predicates.borrow_mut().insert(def_id, trait_predicates);
-    return;
-
-    fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                                 ast_generics: &hir::Generics,
-                                                 trait_predicates: &ty::GenericPredicates<'tcx>,
-                                                 self_trait_ref: ty::TraitRef<'tcx>,
-                                                 trait_item_refs: &[hir::TraitItemRef])
-                                                 -> Vec<ty::Predicate<'tcx>>
-    {
-        trait_item_refs.iter().flat_map(|trait_item_ref| {
-            let trait_item = ccx.tcx.hir.trait_item(trait_item_ref.id);
-            let bounds = match trait_item.node {
-                hir::TraitItemKind::Type(ref bounds, _) => bounds,
-                _ => {
-                    return vec![].into_iter();
-                }
-            };
+    let object_lifetime_defaults =
+        tcx.named_region_map.object_lifetime_defaults.get(&node_id);
 
-            let assoc_ty = ccx.tcx.mk_projection(self_trait_ref,
-                                                 trait_item.name);
+    // 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)| {
+        if p.name == keywords::SelfType.name() {
+            span_bug!(p.span, "`Self` should not be the name of a regular parameter");
+        }
 
-            let bounds = compute_bounds(&ccx.icx(&(ast_generics, trait_predicates)),
-                                        assoc_ty,
-                                        bounds,
-                                        SizedByDefault::Yes,
-                                        trait_item.span);
+        if !allow_defaults && p.default.is_some() {
+            if !tcx.sess.features.borrow().default_type_parameter_fallback {
+                tcx.sess.add_lint(
+                    lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
+                    p.id,
+                    p.span,
+                    format!("defaults for type parameters are only allowed in `struct`, \
+                             `enum`, `type`, or `trait` definitions."));
+            }
+        }
 
-            bounds.predicates(ccx.tcx, assoc_ty).into_iter()
-        }).collect()
+        ty::TypeParameterDef {
+            index: type_start + i as u32,
+            name: p.name,
+            def_id: tcx.hir.local_def_id(p.id),
+            has_default: p.default.is_some(),
+            object_lifetime_default:
+                object_lifetime_defaults.map_or(rl::Set1::Empty, |o| o[i]),
+            pure_wrt_drop: p.pure_wrt_drop,
+        }
+    });
+    let mut types: Vec<_> = opt_self.into_iter().chain(types).collect();
+
+    // provide junk type parameter defs - the only place that
+    // cares about anything but the length is instantiation,
+    // and we don't do that for closures.
+    if let NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) = node {
+        tcx.with_freevars(node_id, |fv| {
+            types.extend(fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef {
+                index: type_start + i as u32,
+                name: Symbol::intern("<upvar>"),
+                def_id: def_id,
+                has_default: false,
+                object_lifetime_default: rl::Set1::Empty,
+                pure_wrt_drop: false,
+            }));
+        });
     }
+
+    let mut type_param_to_index = BTreeMap::new();
+    for param in &types {
+        type_param_to_index.insert(param.def_id.index, param.index);
+    }
+
+    tcx.alloc_generics(ty::Generics {
+        parent: parent_def_id,
+        parent_regions: parent_regions,
+        parent_types: parent_types,
+        regions: regions,
+        types: types,
+        type_param_to_index: type_param_to_index,
+        has_self: has_self || parent_has_self
+    })
 }
 
-fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                def_id: DefId)
-                                -> &'tcx ty::Generics<'tcx> {
-    let tcx = ccx.tcx;
-    let node_id = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
-        id
-    } else {
-        return tcx.item_generics(def_id);
-    };
-    tcx.generics.memoize(def_id, || {
-        use rustc::hir::map::*;
-        use rustc::hir::*;
-
-        let node = tcx.hir.get(node_id);
-        let parent_def_id = match node {
-            NodeImplItem(_) |
-            NodeTraitItem(_) |
-            NodeVariant(_) |
-            NodeStructCtor(_) => {
-                let parent_id = tcx.hir.get_parent(node_id);
-                Some(tcx.hir.local_def_id(parent_id))
-            }
-            NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
-                Some(tcx.closure_base_def_id(def_id))
-            }
-            NodeTy(&hir::Ty { node: hir::TyImplTrait(..), .. }) => {
-                let mut parent_id = node_id;
-                loop {
-                    match tcx.hir.get(parent_id) {
-                        NodeItem(_) | NodeImplItem(_) | NodeTraitItem(_) => break,
-                        _ => {
-                            parent_id = tcx.hir.get_parent_node(parent_id);
-                        }
-                    }
-                }
-                Some(tcx.hir.local_def_id(parent_id))
-            }
-            _ => None
-        };
+fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                def_id: DefId)
+                -> Ty<'tcx> {
+    use rustc::hir::map::*;
+    use rustc::hir::*;
 
-        let mut opt_self = None;
-        let mut allow_defaults = false;
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
 
-        let no_generics = hir::Generics::empty();
-        let ast_generics = match node {
-            NodeTraitItem(item) => {
-                match item.node {
-                    TraitItemKind::Method(ref sig, _) => &sig.generics,
-                    _ => &no_generics
-                }
-            }
+    let icx = ItemCtxt::new(tcx, def_id);
 
-            NodeImplItem(item) => {
-                match item.node {
-                    ImplItemKind::Method(ref sig, _) => &sig.generics,
-                    _ => &no_generics
+    match tcx.hir.get(node_id) {
+        NodeTraitItem(item) => {
+            match item.node {
+                TraitItemKind::Method(ref sig, _) => {
+                    let fty = AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl);
+                    let substs = Substs::identity_for_item(tcx, def_id);
+                    tcx.mk_fn_def(def_id, substs, fty)
+                }
+                TraitItemKind::Const(ref ty, _) |
+                TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
+                TraitItemKind::Type(_, None) => {
+                    span_bug!(item.span, "associated type missing default");
                 }
             }
+        }
 
-            NodeItem(item) => {
-                match item.node {
-                    ItemFn(.., ref generics, _) |
-                    ItemImpl(_, _, ref generics, ..) => generics,
-
-                    ItemTy(_, ref generics) |
-                    ItemEnum(_, ref generics) |
-                    ItemStruct(_, ref generics) |
-                    ItemUnion(_, ref generics) => {
-                        allow_defaults = true;
-                        generics
-                    }
-
-                    ItemTrait(_, ref generics, ..) => {
-                        // Add in the self type parameter.
-                        //
-                        // Something of a hack: use the node id for the trait, also as
-                        // the node id for the Self type parameter.
-                        let param_id = item.id;
-
-                        let parent = ccx.tcx.hir.get_parent(param_id);
-
-                        let def = ty::TypeParameterDef {
-                            index: 0,
-                            name: keywords::SelfType.name(),
-                            def_id: tcx.hir.local_def_id(param_id),
-                            default_def_id: tcx.hir.local_def_id(parent),
-                            default: None,
-                            pure_wrt_drop: false,
-                        };
-                        tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
-                        opt_self = Some(def);
-
-                        allow_defaults = true;
-                        generics
+        NodeImplItem(item) => {
+            match item.node {
+                ImplItemKind::Method(ref sig, _) => {
+                    let fty = AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl);
+                    let substs = Substs::identity_for_item(tcx, def_id);
+                    tcx.mk_fn_def(def_id, substs, fty)
+                }
+                ImplItemKind::Const(ref ty, _) => icx.to_ty(ty),
+                ImplItemKind::Type(ref ty) => {
+                    if tcx.impl_trait_ref(tcx.hir.get_parent_did(node_id)).is_none() {
+                        span_err!(tcx.sess, item.span, E0202,
+                                  "associated types are not allowed in inherent impls");
                     }
 
-                    _ => &no_generics
+                    icx.to_ty(ty)
                 }
             }
+        }
 
-            NodeForeignItem(item) => {
-                match item.node {
-                    ForeignItemStatic(..) => &no_generics,
-                    ForeignItemFn(_, _, ref generics) => generics
+        NodeItem(item) => {
+            match item.node {
+                ItemStatic(ref t, ..) | ItemConst(ref t, _) |
+                ItemTy(ref t, _) | ItemImpl(.., ref t, _) => {
+                    icx.to_ty(t)
+                }
+                ItemFn(ref decl, unsafety, _, abi, _, _) => {
+                    let tofd = AstConv::ty_of_fn(&icx, unsafety, abi, &decl);
+                    let substs = Substs::identity_for_item(tcx, def_id);
+                    tcx.mk_fn_def(def_id, substs, tofd)
+                }
+                ItemEnum(..) |
+                ItemStruct(..) |
+                ItemUnion(..) => {
+                    let def = tcx.lookup_adt_def(def_id);
+                    let substs = Substs::identity_for_item(tcx, def_id);
+                    tcx.mk_adt(def, substs)
+                }
+                ItemDefaultImpl(..) |
+                ItemTrait(..) |
+                ItemMod(..) |
+                ItemForeignMod(..) |
+                ItemExternCrate(..) |
+                ItemUse(..) => {
+                    span_bug!(
+                        item.span,
+                        "compute_type_of_item: unexpected item type: {:?}",
+                        item.node);
                 }
             }
+        }
 
-            _ => &no_generics
-        };
+        NodeForeignItem(foreign_item) => {
+            let abi = tcx.hir.get_foreign_abi(node_id);
 
-        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!(has_self, false);
-            parent_has_self = generics.has_self;
-            own_start = generics.count() as u32;
-            (generics.parent_regions + generics.regions.len() as u32,
-             generics.parent_types + generics.types.len() as u32)
-        });
+            match foreign_item.node {
+                ForeignItemFn(ref fn_decl, _, _) => {
+                    compute_type_of_foreign_fn_decl(tcx, def_id, fn_decl, abi)
+                }
+                ForeignItemStatic(ref t, _) => icx.to_ty(t)
+            }
+        }
 
-        let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics);
-        let regions = early_lifetimes.iter().enumerate().map(|(i, l)| {
-            let issue_32330 = ccx.tcx.named_region_map.issue_32330
-                                                      .get(&l.lifetime.id)
-                                                      .cloned();
-            ty::RegionParameterDef {
-                name: l.lifetime.name,
-                index: own_start + i as u32,
-                def_id: tcx.hir.local_def_id(l.lifetime.id),
-                pure_wrt_drop: l.pure_wrt_drop,
-                issue_32330: issue_32330,
+        NodeStructCtor(&ref def) |
+        NodeVariant(&Spanned { node: hir::Variant_ { data: ref def, .. }, .. }) => {
+            let ty = tcx.item_type(tcx.hir.get_parent_did(node_id));
+            match *def {
+                VariantData::Unit(..) | VariantData::Struct(..) => ty,
+                VariantData::Tuple(ref fields, _) => {
+                    let inputs = fields.iter().map(|f| {
+                        tcx.item_type(tcx.hir.local_def_id(f.id))
+                    });
+                    let substs = Substs::identity_for_item(tcx, def_id);
+                    tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig(
+                        inputs,
+                        ty,
+                        false,
+                        hir::Unsafety::Normal,
+                        abi::Abi::Rust
+                    )))
+                }
             }
-        }).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 = type_start + i as u32;
-            get_or_create_type_parameter_def(ccx, i, p, allow_defaults)
-        });
-        let mut types: Vec<_> = opt_self.into_iter().chain(types).collect();
-
-        // provide junk type parameter defs - the only place that
-        // cares about anything but the length is instantiation,
-        // and we don't do that for closures.
-        if let NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) = node {
-            tcx.with_freevars(node_id, |fv| {
-                types.extend(fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef {
-                    index: type_start + i as u32,
-                    name: Symbol::intern("<upvar>"),
-                    def_id: def_id,
-                    default_def_id: parent_def_id.unwrap(),
-                    default: None,
-                    pure_wrt_drop: false,
-               }));
-            });
+        NodeField(field) => icx.to_ty(&field.ty),
+
+        NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
+            tcx.mk_closure(def_id, Substs::for_item(
+                tcx, def_id,
+                |def, _| {
+                    let region = def.to_early_bound_region_data();
+                    tcx.mk_region(ty::ReEarlyBound(region))
+                },
+                |def, _| tcx.mk_param_from_def(def)
+            ))
         }
 
-        tcx.alloc_generics(ty::Generics {
-            parent: parent_def_id,
-            parent_regions: parent_regions,
-            parent_types: parent_types,
-            regions: regions,
-            types: types,
-            has_self: has_self || parent_has_self
-        })
-    })
-}
+        NodeExpr(_) => match tcx.hir.get(tcx.hir.get_parent_node(node_id)) {
+            NodeTy(&hir::Ty { node: TyArray(_, body), .. }) |
+            NodeExpr(&hir::Expr { node: ExprRepeat(_, body), .. })
+                if body.node_id == node_id => tcx.types.usize,
 
-fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                            def_id: DefId)
-                            -> Ty<'tcx> {
-    let node_id = if let Some(id) = ccx.tcx.hir.as_local_node_id(def_id) {
-        id
-    } else {
-        return ccx.tcx.item_type(def_id);
-    };
-    ccx.tcx.item_types.memoize(def_id, || {
-        use rustc::hir::map::*;
-        use rustc::hir::*;
-
-        // Alway bring in generics, as computing the type needs them.
-        generics_of_def_id(ccx, def_id);
-
-        let ty = match ccx.tcx.hir.get(node_id) {
-            NodeItem(item) => {
-                match item.node {
-                    ItemStatic(ref t, ..) | ItemConst(ref t, _) => {
-                        ccx.icx(&()).to_ty(&t)
-                    }
-                    ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
-                        let tofd = AstConv::ty_of_fn(&ccx.icx(generics), unsafety, abi, &decl);
-                        let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
-                        ccx.tcx.mk_fn_def(def_id, substs, tofd)
-                    }
-                    ItemTy(ref t, ref generics) => {
-                        ccx.icx(generics).to_ty(&t)
-                    }
-                    ItemEnum(ref ei, ref generics) => {
-                        let def = convert_enum_def(ccx, item, ei);
-                        let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
-                        ccx.tcx.mk_adt(def, substs)
-                    }
-                    ItemStruct(ref si, ref generics) => {
-                        let def = convert_struct_def(ccx, item, si);
-                        let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
-                        ccx.tcx.mk_adt(def, substs)
-                    }
-                    ItemUnion(ref un, ref generics) => {
-                        let def = convert_union_def(ccx, item, un);
-                        let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
-                        ccx.tcx.mk_adt(def, substs)
-                    }
-                    ItemDefaultImpl(..) |
-                    ItemTrait(..) |
-                    ItemImpl(..) |
-                    ItemMod(..) |
-                    ItemForeignMod(..) |
-                    ItemExternCrate(..) |
-                    ItemUse(..) => {
-                        span_bug!(
-                            item.span,
-                            "compute_type_of_item: unexpected item type: {:?}",
-                            item.node);
-                    }
+            NodeVariant(&Spanned { node: Variant_ { disr_expr: Some(e), .. }, .. })
+                if e.node_id == node_id => {
+                    tcx.lookup_adt_def(tcx.hir.get_parent_did(node_id))
+                        .repr.discr_type().to_ty(tcx)
                 }
-            }
-            NodeForeignItem(foreign_item) => {
-                let abi = ccx.tcx.hir.get_foreign_abi(node_id);
-
-                match foreign_item.node {
-                    ForeignItemFn(ref fn_decl, _, ref generics) => {
-                        compute_type_of_foreign_fn_decl(
-                            ccx, ccx.tcx.hir.local_def_id(foreign_item.id),
-                            fn_decl, generics, abi)
-                    }
-                    ForeignItemStatic(ref t, _) => {
-                        ccx.icx(&()).to_ty(t)
-                    }
-                }
-            }
-            NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
-                ccx.tcx.mk_closure(def_id, Substs::for_item(
-                    ccx.tcx, def_id,
-                    |def, _| {
-                        let region = def.to_early_bound_region_data();
-                        ccx.tcx.mk_region(ty::ReEarlyBound(region))
-                    },
-                    |def, _| ccx.tcx.mk_param_from_def(def)
-                ))
-            }
+
             x => {
-                bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
+                bug!("unexpected expr parent in type_of_def_id(): {:?}", x);
             }
-        };
-
-        ty
-    })
-}
-
-fn predicates_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                it: &hir::Item)
-                                -> ty::GenericPredicates<'tcx> {
-    let def_id = ccx.tcx.hir.local_def_id(it.id);
+        },
 
-    let no_generics = hir::Generics::empty();
-    let generics = match it.node {
-        hir::ItemFn(.., ref generics, _) |
-        hir::ItemTy(_, ref generics) |
-        hir::ItemEnum(_, ref generics) |
-        hir::ItemStruct(_, ref generics) |
-        hir::ItemUnion(_, ref generics) => generics,
-        _ => &no_generics
-    };
+        NodeTyParam(&hir::TyParam { default: Some(ref ty), .. }) => {
+            icx.to_ty(ty)
+        }
 
-    let predicates = ty_generic_predicates(ccx, generics, None, vec![], false);
-    ccx.tcx.predicates.borrow_mut().insert(def_id, predicates.clone());
+        NodeTy(&hir::Ty { node: TyImplTrait(..), .. }) => {
+            let owner = tcx.hir.get_parent_did(node_id);
+            tcx.item_tables(owner).node_id_to_type(node_id)
+        }
 
-    predicates
+        x => {
+            bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
+        }
+    }
 }
 
-fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                  it: &hir::ForeignItem)
-{
-    // For reasons I cannot fully articulate, I do so hate the AST
-    // map, and I regard each time that I use it as a personal and
-    // moral failing, but at the moment it seems like the only
-    // convenient way to extract the ABI. - ndm
-    let def_id = ccx.tcx.hir.local_def_id(it.id);
-    type_of_def_id(ccx, def_id);
-    generics_of_def_id(ccx, def_id);
-
-    let no_generics = hir::Generics::empty();
-    let generics = match it.node {
-        hir::ForeignItemFn(_, _, ref generics) => generics,
-        hir::ForeignItemStatic(..) => &no_generics
-    };
+fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            def_id: DefId)
+                            -> Option<ty::TraitRef<'tcx>> {
+    let icx = ItemCtxt::new(tcx, def_id);
 
-    let predicates = ty_generic_predicates(ccx, generics, None, vec![], false);
-    ccx.tcx.predicates.borrow_mut().insert(def_id, predicates);
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    match tcx.hir.expect_item(node_id).node {
+        hir::ItemDefaultImpl(_, ref ast_trait_ref) => {
+            Some(AstConv::instantiate_mono_trait_ref(&icx,
+                                                     ast_trait_ref,
+                                                     tcx.mk_self_type()))
+        }
+        hir::ItemImpl(.., ref opt_trait_ref, _, _) => {
+            opt_trait_ref.as_ref().map(|ast_trait_ref| {
+                let selfty = tcx.item_type(def_id);
+                AstConv::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
+            })
+        }
+        _ => bug!()
+    }
 }
 
 // Is it marked with ?Sized
@@ -1676,60 +1247,123 @@ fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
 /// the lifetimes that are declared. For fns or methods, we have to
 /// screen out those that do not appear in any where-clauses etc using
 /// `resolve_lifetime::early_bound_lifetimes`.
-fn early_bound_lifetimes_from_generics<'a, 'tcx, 'hir>(
-    ccx: &CrateCtxt<'a, 'tcx>,
-    ast_generics: &'hir hir::Generics)
-    -> Vec<&'hir hir::LifetimeDef>
+fn early_bound_lifetimes_from_generics<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    ast_generics: &'a hir::Generics)
+    -> impl Iterator<Item=&'a hir::LifetimeDef>
 {
     ast_generics
         .lifetimes
         .iter()
-        .filter(|l| !ccx.tcx.named_region_map.late_bound.contains(&l.lifetime.id))
-        .collect()
+        .filter(move |l| !tcx.named_region_map.late_bound.contains(&l.lifetime.id))
 }
 
-fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                                  ast_generics: &hir::Generics,
-                                  parent: Option<DefId>,
-                                  super_predicates: Vec<ty::Predicate<'tcx>>,
-                                  has_self: bool)
-                                  -> ty::GenericPredicates<'tcx>
-{
-    let tcx = ccx.tcx;
-    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.count() as u32
-    });
-    let ref base_predicates = match parent {
-        Some(def_id) => {
-            assert_eq!(super_predicates, vec![]);
-            tcx.item_predicates(def_id)
+fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        def_id: DefId)
+                        -> ty::GenericPredicates<'tcx> {
+    use rustc::hir::map::*;
+    use rustc::hir::*;
+
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    let node = tcx.hir.get(node_id);
+
+    let mut is_trait = None;
+
+    let icx = ItemCtxt::new(tcx, def_id);
+    let no_generics = hir::Generics::empty();
+    let ast_generics = match node {
+        NodeTraitItem(item) => {
+            match item.node {
+                TraitItemKind::Method(ref sig, _) => &sig.generics,
+                _ => &no_generics
+            }
         }
-        None => {
-            ty::GenericPredicates {
-                parent: None,
-                predicates: super_predicates.clone()
+
+        NodeImplItem(item) => {
+            match item.node {
+                ImplItemKind::Method(ref sig, _) => &sig.generics,
+                _ => &no_generics
+            }
+        }
+
+        NodeItem(item) => {
+            match item.node {
+                ItemFn(.., ref generics, _) |
+                ItemImpl(_, _, ref generics, ..) |
+                ItemTy(_, ref generics) |
+                ItemEnum(_, ref generics) |
+                ItemStruct(_, ref generics) |
+                ItemUnion(_, ref generics) => {
+                    generics
+                }
+
+                ItemTrait(_, ref generics, .., ref items) => {
+                    is_trait = Some((ty::TraitRef {
+                        def_id: def_id,
+                        substs: Substs::identity_for_item(tcx, def_id)
+                    }, items));
+                    generics
+                }
+
+                _ => &no_generics
             }
         }
+
+        NodeForeignItem(item) => {
+            match item.node {
+                ForeignItemStatic(..) => &no_generics,
+                ForeignItemFn(_, _, ref generics) => generics
+            }
+        }
+
+        NodeTy(&Ty { node: TyImplTrait(ref bounds), span, .. }) => {
+            let substs = Substs::identity_for_item(tcx, def_id);
+            let anon_ty = tcx.mk_anon(def_id, substs);
+
+            // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
+            let bounds = compute_bounds(&icx, anon_ty, bounds,
+                                        SizedByDefault::Yes,
+                                        span);
+            return ty::GenericPredicates {
+                parent: None,
+                predicates: bounds.predicates(tcx, anon_ty)
+            };
+        }
+
+        _ => &no_generics
     };
-    let mut predicates = super_predicates;
+
+    let generics = tcx.item_generics(def_id);
+    let parent_count = generics.parent_count() as u32;
+    let has_own_self = generics.has_self && parent_count == 0;
+
+    let mut predicates = vec![];
+
+    // Below we'll consider the bounds on the type parameters (including `Self`)
+    // and the explicit where-clauses, but to get the full set of predicates
+    // on a trait we need to add in the supertrait bounds and bounds found on
+    // associated types.
+    if let Some((trait_ref, _)) = is_trait {
+        predicates = tcx.item_super_predicates(def_id).predicates;
+
+        // Add in a predicate that `Self:Trait` (where `Trait` is the
+        // current trait).  This is needed for builtin bounds.
+        predicates.push(trait_ref.to_poly_trait_ref().to_predicate());
+    }
 
     // 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 {
+    let mut index = parent_count + has_own_self as u32;
+    for param in early_bound_lifetimes_from_generics(tcx, ast_generics) {
+        let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
             index: index,
             name: param.lifetime.name
         }));
+        index += 1;
+
         for bound in &param.bounds {
-            let bound_region = AstConv::ast_region_to_region(&ccx.icx(&()), bound, None);
+            let bound_region = AstConv::ast_region_to_region(&icx, bound, None);
             let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region));
             predicates.push(outlives.to_predicate());
         }
@@ -1737,16 +1371,16 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 
     // 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 = 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)),
+    for param in &ast_generics.ty_params {
+        let param_ty = ty::ParamTy::new(index, param.name).to_ty(tcx);
+        index += 1;
+
+        let bounds = compute_bounds(&icx,
                                     param_ty,
                                     &param.bounds,
                                     SizedByDefault::Yes,
                                     param.span);
-        predicates.extend(bounds.predicates(ccx.tcx, param_ty));
+        predicates.extend(bounds.predicates(tcx, param_ty));
     }
 
     // Add in the bounds that appear in the where-clause
@@ -1754,8 +1388,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
     for predicate in &where_clause.predicates {
         match predicate {
             &hir::WherePredicate::BoundPredicate(ref bound_pred) => {
-                let ty = AstConv::ast_ty_to_ty(&ccx.icx(&(base_predicates, ast_generics)),
-                                               &bound_pred.bounded_ty);
+                let ty = icx.to_ty(&bound_pred.bounded_ty);
 
                 for bound in bound_pred.bounds.iter() {
                     match bound {
@@ -1763,8 +1396,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                             let mut projections = Vec::new();
 
                             let trait_ref =
-                                AstConv::instantiate_poly_trait_ref(&ccx.icx(&(base_predicates,
-                                                                               ast_generics)),
+                                AstConv::instantiate_poly_trait_ref(&icx,
                                                                     poly_trait_ref,
                                                                     ty,
                                                                     &mut projections);
@@ -1777,7 +1409,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                         }
 
                         &hir::TyParamBound::RegionTyParamBound(ref lifetime) => {
-                            let region = AstConv::ast_region_to_region(&ccx.icx(&()),
+                            let region = AstConv::ast_region_to_region(&icx,
                                                                        lifetime,
                                                                        None);
                             let pred = ty::Binder(ty::OutlivesPredicate(ty, region));
@@ -1788,9 +1420,9 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
             }
 
             &hir::WherePredicate::RegionPredicate(ref region_pred) => {
-                let r1 = AstConv::ast_region_to_region(&ccx.icx(&()), &region_pred.lifetime, None);
+                let r1 = AstConv::ast_region_to_region(&icx, &region_pred.lifetime, None);
                 for bound in &region_pred.bounds {
-                    let r2 = AstConv::ast_region_to_region(&ccx.icx(&()), bound, None);
+                    let r2 = AstConv::ast_region_to_region(&icx, bound, None);
                     let pred = ty::Binder(ty::OutlivesPredicate(r1, r2));
                     predicates.push(ty::Predicate::RegionOutlives(pred))
                 }
@@ -1802,58 +1434,46 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         }
     }
 
-    ty::GenericPredicates {
-        parent: parent,
-        predicates: predicates
-    }
-}
-
-fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                                             index: u32,
-                                             param: &hir::TyParam,
-                                             allow_defaults: bool)
-                                             -> ty::TypeParameterDef<'tcx>
-{
-    let tcx = ccx.tcx;
-    match tcx.ty_param_defs.borrow().get(&param.id) {
-        Some(d) => { return d.clone(); }
-        None => { }
-    }
+    // Add predicates from associated type bounds.
+    if let Some((self_trait_ref, trait_items)) = is_trait {
+        predicates.extend(trait_items.iter().flat_map(|trait_item_ref| {
+            let trait_item = tcx.hir.trait_item(trait_item_ref.id);
+            let bounds = match trait_item.node {
+                hir::TraitItemKind::Type(ref bounds, _) => bounds,
+                _ => {
+                    return vec![].into_iter();
+                }
+            };
 
-    let default =
-        param.default.as_ref().map(|def| ccx.icx(&()).to_ty(def));
+            let assoc_ty = tcx.mk_projection(self_trait_ref, trait_item.name);
 
-    let parent = tcx.hir.get_parent(param.id);
+            let bounds = compute_bounds(&ItemCtxt::new(tcx, def_id),
+                                        assoc_ty,
+                                        bounds,
+                                        SizedByDefault::Yes,
+                                        trait_item.span);
 
-    if !allow_defaults && default.is_some() {
-        if !tcx.sess.features.borrow().default_type_parameter_fallback {
-            tcx.sess.add_lint(
-                lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
-                param.id,
-                param.span,
-                format!("defaults for type parameters are only allowed in `struct`, \
-                         `enum`, `type`, or `trait` definitions."));
-        }
+            bounds.predicates(tcx, assoc_ty).into_iter()
+        }))
     }
 
-    let def = ty::TypeParameterDef {
-        index: index,
-        name: param.name,
-        def_id: ccx.tcx.hir.local_def_id(param.id),
-        default_def_id: ccx.tcx.hir.local_def_id(parent),
-        default: default,
-        pure_wrt_drop: param.pure_wrt_drop,
-    };
-
-    if def.name == keywords::SelfType.name() {
-        span_bug!(param.span, "`Self` should not be the name of a regular parameter");
+    // Subtle: before we store the predicates into the tcx, we
+    // sort them so that predicates like `T: Foo<Item=U>` come
+    // before uses of `U`.  This avoids false ambiguity errors
+    // in trait checking. See `setup_constraining_predicates`
+    // for details.
+    if let NodeItem(&Item { node: ItemImpl(..), .. }) = node {
+        let self_ty = tcx.item_type(def_id);
+        let trait_ref = tcx.impl_trait_ref(def_id);
+        ctp::setup_constraining_predicates(&mut predicates,
+                                           trait_ref,
+                                           &mut ctp::parameters_for_impl(self_ty, trait_ref));
     }
 
-    tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone());
-
-    debug!("get_or_create_type_parameter_def: def for type param: {:?}", def);
-
-    def
+    ty::GenericPredicates {
+        parent: generics.parent,
+        predicates: predicates
+    }
 }
 
 pub enum SizedByDefault { Yes, No, }
@@ -1943,53 +1563,36 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
 }
 
 fn compute_type_of_foreign_fn_decl<'a, 'tcx>(
-    ccx: &CrateCtxt<'a, 'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     def_id: DefId,
     decl: &hir::FnDecl,
-    ast_generics: &hir::Generics,
     abi: abi::Abi)
     -> Ty<'tcx>
 {
-    let fty = AstConv::ty_of_fn(&ccx.icx(ast_generics), hir::Unsafety::Unsafe, abi, decl);
+    let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), hir::Unsafety::Unsafe, abi, decl);
 
     // feature gate SIMD types in FFI, since I (huonw) am not sure the
     // ABIs are handled at all correctly.
     if abi != abi::Abi::RustIntrinsic && abi != abi::Abi::PlatformIntrinsic
-            && !ccx.tcx.sess.features.borrow().simd_ffi {
+            && !tcx.sess.features.borrow().simd_ffi {
         let check = |ast_ty: &hir::Ty, ty: ty::Ty| {
             if ty.is_simd() {
-                ccx.tcx.sess.struct_span_err(ast_ty.span,
+                tcx.sess.struct_span_err(ast_ty.span,
                               &format!("use of SIMD type `{}` in FFI is highly experimental and \
                                         may result in invalid code",
-                                       ccx.tcx.hir.node_to_pretty_string(ast_ty.id)))
+                                       tcx.hir.node_to_pretty_string(ast_ty.id)))
                     .help("add #![feature(simd_ffi)] to the crate attributes to enable")
                     .emit();
             }
         };
-        for (input, ty) in decl.inputs.iter().zip(*fty.sig.inputs().skip_binder()) {
+        for (input, ty) in decl.inputs.iter().zip(*fty.inputs().skip_binder()) {
             check(&input, ty)
         }
         if let hir::Return(ref ty) = decl.output {
-            check(&ty, *fty.sig.output().skip_binder())
+            check(&ty, *fty.output().skip_binder())
         }
     }
 
-    let id = ccx.tcx.hir.as_local_node_id(def_id).unwrap();
-    let substs = mk_item_substs(&ccx.icx(ast_generics), ccx.tcx.hir.span(id), def_id);
-    ccx.tcx.mk_fn_def(def_id, substs, fty)
-}
-
-fn mk_item_substs<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
-                        span: Span,
-                        def_id: DefId)
-                        -> &'tcx Substs<'tcx> {
-    let tcx = astconv.tcx();
-    // FIXME(eddyb) Do this request from Substs::for_item in librustc.
-    if let Err(ErrorReported) = astconv.get_generics(span, def_id) {
-        // No convenient way to recover from a cycle here. Just bail. Sorry!
-        tcx.sess.abort_if_errors();
-        bug!("ErrorReported returned, but no errors reports?")
-    }
-
-    Substs::identity_for_item(tcx, def_id)
+    let substs = Substs::identity_for_item(tcx, def_id);
+    tcx.mk_fn_def(def_id, substs, fty)
 }
index 5bfc3a934af059ee7999a5904a8eb862f497a75a..644e323a8dbf2ce1d6d86cacf4912693d697c228 100644 (file)
@@ -1039,45 +1039,6 @@ struct Foo { x: Option<Box<Foo>> }
 ```
 "##,
 
-E0079: r##"
-Enum variants which contain no data can be given a custom integer
-representation. This error indicates that the value provided is not an integer
-literal and is therefore invalid.
-
-For example, in the following code:
-
-```compile_fail,E0079
-enum Foo {
-    Q = "32",
-}
-```
-
-We try to set the representation to a string.
-
-There's no general fix for this; if you can work with an integer then just set
-it to one:
-
-```
-enum Foo {
-    Q = 32,
-}
-```
-
-However if you actually wanted a mapping between variants and non-integer
-objects, it may be preferable to use a method with a match instead:
-
-```
-enum Foo { Q }
-impl Foo {
-    fn get_str(&self) -> &'static str {
-        match *self {
-            Foo::Q => "32",
-        }
-    }
-}
-```
-"##,
-
 E0081: r##"
 Enum discriminants are used to differentiate enum variants stored in memory.
 This error indicates that the same value was used for two or more variants,
@@ -1427,6 +1388,44 @@ struct Baz<'a> {
 ```
 "##,
 
+E0109: r##"
+You tried to give a type parameter to a type which doesn't need it. Erroneous
+code example:
+
+```compile_fail,E0109
+type X = u32<i32>; // error: type parameters are not allowed on this type
+```
+
+Please check that you used the correct type and recheck its definition. Perhaps
+it doesn't need the type parameter.
+
+Example:
+
+```
+type X = u32; // this compiles
+```
+
+Note that type parameters for enum-variant constructors go after the variant,
+not after the enum (Option::None::<u32>, not Option::<u32>::None).
+"##,
+
+E0110: r##"
+You tried to give a lifetime parameter to a type which doesn't need it.
+Erroneous code example:
+
+```compile_fail,E0110
+type X = u32<'static>; // error: lifetime parameters are not allowed on
+                       //        this type
+```
+
+Please check that the correct type was used and recheck its definition; perhaps
+it doesn't need the lifetime parameter. Example:
+
+```
+type X = u32; // ok!
+```
+"##,
+
 E0116: r##"
 You can only define an inherent implementation for a type in the same crate
 where the type was defined. For example, an `impl` block as below is not allowed
@@ -1701,33 +1700,6 @@ struct Foo {
 ```
 "##,
 
-E0128: r##"
-Type parameter defaults can only use parameters that occur before them.
-Erroneous code example:
-
-```compile_fail,E0128
-struct Foo<T=U, U=()> {
-    field1: T,
-    filed2: U,
-}
-// error: type parameters with a default cannot use forward declared
-// identifiers
-```
-
-Since type parameters are evaluated in-order, you may be able to fix this issue
-by doing:
-
-```
-struct Foo<U=(), T=U> {
-    field1: T,
-    filed2: U,
-}
-```
-
-Please also verify that this wasn't because of a name-clash and rename the type
-parameter if so.
-"##,
-
 E0131: r##"
 It is not possible to define `main` with type parameters, or even with function
 parameters. When `main` is present, it must take no arguments and return `()`.
@@ -2676,6 +2648,41 @@ fn main() {
 ```
 "##,
 
+E0229: r##"
+An associated type binding was done outside of the type parameter declaration
+and `where` clause. Erroneous code example:
+
+```compile_fail,E0229
+pub trait Foo {
+    type A;
+    fn boo(&self) -> <Self as Foo>::A;
+}
+
+struct Bar;
+
+impl Foo for isize {
+    type A = usize;
+    fn boo(&self) -> usize { 42 }
+}
+
+fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
+// error: associated type bindings are not allowed here
+```
+
+To solve this error, please move the type bindings in the type parameter
+declaration:
+
+```ignore
+fn baz<I: Foo<A=Bar>>(x: &<I as Foo>::A) {} // ok!
+```
+
+Or in the `where` clause:
+
+```ignore
+fn baz<I>(x: &<I as Foo>::A) where I: Foo<A=Bar> {}
+```
+"##,
+
 E0230: r##"
 The trait has more type parameters specified than appear in its definition.
 
@@ -3444,23 +3451,6 @@ fn bar() {} // ok!
 ```
 "##,
 
-E0391: r##"
-This error indicates that some types or traits depend on each other
-and therefore cannot be constructed.
-
-The following example contains a circular dependency between two traits:
-
-```compile_fail,E0391
-trait FirstTrait : SecondTrait {
-
-}
-
-trait SecondTrait : FirstTrait {
-
-}
-```
-"##,
-
 E0392: r##"
 This error indicates that a type or lifetime parameter has been declared
 but not actually used. Here is an example that demonstrates the error:
index 3a19b3579d5598b61bf275fc13f2db9b0eafa0f8..3df25825a71f66328f1a313d2969cd472cc3376b 100644 (file)
 use rustc::hir;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::def_id::DefId;
-use rustc::ty;
+use rustc::ty::{self, TyCtxt};
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 
 use syntax_pos::Span;
 
-use CrateCtxt;
-
 /// Checks that all the type/lifetime parameters on an impl also
 /// appear in the trait ref or self-type (or are constrained by a
 /// where-clause). These rules are needed to ensure that, given a
 /// impl<'a> Trait<Foo> for Bar { type X = &'a i32; }
 ///      ^ 'a is unused and appears in assoc type, error
 /// ```
-pub fn impl_wf_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>) {
+pub fn impl_wf_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     // We will tag this as part of the WF check -- logically, it is,
     // but it's one that we must perform earlier than the rest of
     // WfCheck.
-    ccx.tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut ImplWfCheck { ccx: ccx });
+    tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut ImplWfCheck { tcx: tcx });
 }
 
 struct ImplWfCheck<'a, 'tcx: 'a> {
-    ccx: &'a CrateCtxt<'a, 'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 impl<'a, 'tcx> ItemLikeVisitor<'tcx> for ImplWfCheck<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
             hir::ItemImpl(.., ref generics, _, _, ref impl_item_refs) => {
-                let impl_def_id = self.ccx.tcx.hir.local_def_id(item.id);
-                enforce_impl_params_are_constrained(self.ccx,
+                let impl_def_id = self.tcx.hir.local_def_id(item.id);
+                enforce_impl_params_are_constrained(self.tcx,
                                                     generics,
                                                     impl_def_id,
                                                     impl_item_refs);
-                enforce_impl_items_are_distinct(self.ccx, impl_item_refs);
+                enforce_impl_items_are_distinct(self.tcx, impl_item_refs);
             }
             _ => { }
         }
@@ -92,16 +90,16 @@ fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem) { }
     fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { }
 }
 
-fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                  impl_hir_generics: &hir::Generics,
                                                  impl_def_id: DefId,
                                                  impl_item_refs: &[hir::ImplItemRef])
 {
     // Every lifetime used in an associated type must be constrained.
-    let impl_self_ty = ccx.tcx.item_type(impl_def_id);
-    let impl_generics = ccx.tcx.item_generics(impl_def_id);
-    let impl_predicates = ccx.tcx.item_predicates(impl_def_id);
-    let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id);
+    let impl_self_ty = tcx.item_type(impl_def_id);
+    let impl_generics = tcx.item_generics(impl_def_id);
+    let impl_predicates = tcx.item_predicates(impl_def_id);
+    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
 
     let mut input_parameters = ctp::parameters_for_impl(impl_self_ty, impl_trait_ref);
     ctp::identify_constrained_type_params(
@@ -111,19 +109,19 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     for (ty_param, param) in impl_generics.types.iter().zip(&impl_hir_generics.ty_params) {
         let param_ty = ty::ParamTy::for_def(ty_param);
         if !input_parameters.contains(&ctp::Parameter::from(param_ty)) {
-            report_unused_parameter(ccx, param.span, "type", &param_ty.to_string());
+            report_unused_parameter(tcx, param.span, "type", &param_ty.to_string());
         }
     }
 
     // Disallow unconstrained lifetimes, but only if they appear in assoc types.
     let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs.iter()
-        .map(|item_ref|  ccx.tcx.hir.local_def_id(item_ref.id.node_id))
+        .map(|item_ref|  tcx.hir.local_def_id(item_ref.id.node_id))
         .filter(|&def_id| {
-            let item = ccx.tcx.associated_item(def_id);
+            let item = tcx.associated_item(def_id);
             item.kind == ty::AssociatedKind::Type && item.defaultness.has_value()
         })
         .flat_map(|def_id| {
-            ctp::parameters_for(&ccx.tcx.item_type(def_id), true)
+            ctp::parameters_for(&tcx.item_type(def_id), true)
         }).collect();
     for (ty_lifetime, lifetime) in impl_generics.regions.iter()
         .zip(&impl_hir_generics.lifetimes)
@@ -134,7 +132,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             lifetimes_in_associated_types.contains(&param) && // (*)
             !input_parameters.contains(&param)
         {
-            report_unused_parameter(ccx, lifetime.lifetime.span,
+            report_unused_parameter(tcx, lifetime.lifetime.span,
                                     "lifetime", &lifetime.lifetime.name.to_string());
         }
     }
@@ -159,13 +157,13 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     // used elsewhere are not projected back out.
 }
 
-fn report_unused_parameter(ccx: &CrateCtxt,
+fn report_unused_parameter(tcx: TyCtxt,
                            span: Span,
                            kind: &str,
                            name: &str)
 {
     struct_span_err!(
-        ccx.tcx.sess, span, E0207,
+        tcx.sess, span, E0207,
         "the {} parameter `{}` is not constrained by the \
         impl trait, self type, or predicates",
         kind, name)
@@ -174,10 +172,9 @@ impl trait, self type, or predicates",
 }
 
 /// Enforce that we do not have two items in an impl with the same name.
-fn enforce_impl_items_are_distinct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn enforce_impl_items_are_distinct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                              impl_item_refs: &[hir::ImplItemRef])
 {
-    let tcx = ccx.tcx;
     let mut seen_type_items = FxHashMap();
     let mut seen_value_items = FxHashMap();
     for impl_item_ref in impl_item_refs {
index 0bcf8ab7d6c2092079a822943aaa66222b20a895..2c325d46c0bc060ff3e8b1aa4c6ca90a4bfad11e 100644 (file)
 use rustc::infer::InferOk;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
+use rustc::ty::maps::Providers;
+use rustc::traits::{ObligationCause, ObligationCauseCode, Reveal};
 use session::config;
 use util::common::time;
 
 use syntax_pos::Span;
 
 use std::iter;
-use std::cell::RefCell;
-use util::nodemap::NodeMap;
-
 // NB: This module needs to be declared first so diagnostics are
 // registered before they are used.
 pub mod diagnostics;
@@ -140,27 +138,6 @@ pub struct TypeAndSubsts<'tcx> {
     pub ty: Ty<'tcx>,
 }
 
-pub struct CrateCtxt<'a, 'tcx: 'a> {
-    ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
-
-    /// A vector of every trait accessible in the whole crate
-    /// (i.e. including those from subcrates). This is used only for
-    /// error reporting, and so is lazily initialised and generally
-    /// shouldn't taint the common path (hence the RefCell).
-    pub all_traits: RefCell<Option<check::method::AllTraitsVec>>,
-
-    /// This stack is used to identify cycles in the user's source.
-    /// Note that these cycles can cross multiple items.
-    pub stack: RefCell<Vec<collect::AstConvRequest>>,
-
-    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
-
-    /// Obligations which will have to be checked at the end of
-    /// type-checking, after all functions have been inferred.
-    /// The key is the NodeId of the item the obligations were from.
-    pub deferred_obligations: RefCell<NodeMap<Vec<traits::DeferredObligation<'tcx>>>>,
-}
-
 fn require_c_abi_if_variadic(tcx: TyCtxt,
                              decl: &hir::FnDecl,
                              abi: Abi,
@@ -173,12 +150,12 @@ fn require_c_abi_if_variadic(tcx: TyCtxt,
     }
 }
 
-fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 cause: &ObligationCause<'tcx>,
                                 expected: Ty<'tcx>,
                                 actual: Ty<'tcx>)
                                 -> bool {
-    ccx.tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
+    tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
         match infcx.eq_types(false, &cause, expected, actual) {
             Ok(InferOk { obligations, .. }) => {
                 // FIXME(#32730) propagate obligations
@@ -193,10 +170,9 @@ fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     })
 }
 
-fn check_main_fn_ty(ccx: &CrateCtxt,
-                    main_id: ast::NodeId,
-                    main_span: Span) {
-    let tcx = ccx.tcx;
+fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                              main_id: ast::NodeId,
+                              main_span: Span) {
     let main_def_id = tcx.hir.local_def_id(main_id);
     let main_t = tcx.item_type(main_def_id);
     match main_t.sty {
@@ -206,7 +182,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                     match it.node {
                         hir::ItemFn(.., ref generics, _) => {
                             if generics.is_parameterized() {
-                                struct_span_err!(ccx.tcx.sess, generics.span, E0131,
+                                struct_span_err!(tcx.sess, generics.span, E0131,
                                          "main function is not allowed to have type parameters")
                                     .span_label(generics.span,
                                                 &format!("main cannot have type parameters"))
@@ -221,14 +197,17 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
             }
             let substs = tcx.intern_substs(&[]);
             let se_ty = tcx.mk_fn_def(main_def_id, substs,
-                                      tcx.mk_bare_fn(ty::BareFnTy {
-                unsafety: hir::Unsafety::Normal,
-                abi: Abi::Rust,
-                sig: ty::Binder(tcx.mk_fn_sig(iter::empty(), tcx.mk_nil(), false))
-            }));
+                ty::Binder(tcx.mk_fn_sig(
+                    iter::empty(),
+                    tcx.mk_nil(),
+                    false,
+                    hir::Unsafety::Normal,
+                    Abi::Rust
+                ))
+            );
 
             require_same_types(
-                ccx,
+                tcx,
                 &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
                 se_ty,
                 main_t);
@@ -241,11 +220,10 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
     }
 }
 
-fn check_start_fn_ty(ccx: &CrateCtxt,
-                     start_id: ast::NodeId,
-                     start_span: Span) {
-    let tcx = ccx.tcx;
-    let start_def_id = ccx.tcx.hir.local_def_id(start_id);
+fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                               start_id: ast::NodeId,
+                               start_span: Span) {
+    let start_def_id = tcx.hir.local_def_id(start_id);
     let start_t = tcx.item_type(start_def_id);
     match start_t.sty {
         ty::TyFnDef(..) => {
@@ -269,21 +247,20 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
 
             let substs = tcx.intern_substs(&[]);
             let se_ty = tcx.mk_fn_def(start_def_id, substs,
-                                      tcx.mk_bare_fn(ty::BareFnTy {
-                unsafety: hir::Unsafety::Normal,
-                abi: Abi::Rust,
-                sig: ty::Binder(tcx.mk_fn_sig(
+                ty::Binder(tcx.mk_fn_sig(
                     [
                         tcx.types.isize,
                         tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
                     ].iter().cloned(),
                     tcx.types.isize,
                     false,
-                )),
-            }));
+                    hir::Unsafety::Normal,
+                    Abi::Rust
+                ))
+            );
 
             require_same_types(
-                ccx,
+                tcx,
                 &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
                 se_ty,
                 start_t);
@@ -296,35 +273,33 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
     }
 }
 
-fn check_for_entry_fn(ccx: &CrateCtxt) {
-    let tcx = ccx.tcx;
+fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let _task = tcx.dep_graph.in_task(DepNode::CheckEntryFn);
     if let Some((id, sp)) = *tcx.sess.entry_fn.borrow() {
         match tcx.sess.entry_type.get() {
-            Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
-            Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
+            Some(config::EntryMain) => check_main_fn_ty(tcx, id, sp),
+            Some(config::EntryStart) => check_start_fn_ty(tcx, id, sp),
             Some(config::EntryNone) => {}
             None => bug!("entry function without a type")
         }
     }
 }
 
+pub fn provide(providers: &mut Providers) {
+    collect::provide(providers);
+    coherence::provide(providers);
+    check::provide(providers);
+}
+
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                             -> Result<NodeMap<Ty<'tcx>>, usize> {
+                             -> Result<(), usize> {
     let time_passes = tcx.sess.time_passes();
-    let ccx = CrateCtxt {
-        ast_ty_to_ty_cache: RefCell::new(NodeMap()),
-        all_traits: RefCell::new(None),
-        stack: RefCell::new(Vec::new()),
-        tcx: tcx,
-        deferred_obligations: RefCell::new(NodeMap()),
-    };
 
     // this ensures that later parts of type checking can assume that items
     // have valid types and not error
     tcx.sess.track_errors(|| {
         time(time_passes, "type collecting", ||
-             collect::collect_item_types(&ccx));
+             collect::collect_item_types(tcx));
 
     })?;
 
@@ -333,28 +308,28 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
 
     tcx.sess.track_errors(|| {
         time(time_passes, "impl wf inference", ||
-             impl_wf_check::impl_wf_check(&ccx));
+             impl_wf_check::impl_wf_check(tcx));
     })?;
 
     tcx.sess.track_errors(|| {
       time(time_passes, "coherence checking", ||
-          coherence::check_coherence(&ccx));
+          coherence::check_coherence(tcx));
     })?;
 
-    time(time_passes, "wf checking", || check::check_wf_new(&ccx))?;
+    time(time_passes, "wf checking", || check::check_wf_new(tcx))?;
 
-    time(time_passes, "item-types checking", || check::check_item_types(&ccx))?;
+    time(time_passes, "item-types checking", || check::check_item_types(tcx))?;
 
-    time(time_passes, "item-bodies checking", || check::check_item_bodies(&ccx))?;
+    time(time_passes, "item-bodies checking", || check::check_item_bodies(tcx))?;
 
-    time(time_passes, "drop-impl checking", || check::check_drop_impls(&ccx))?;
+    time(time_passes, "drop-impl checking", || check::check_drop_impls(tcx))?;
 
     check_unused::check_crate(tcx);
-    check_for_entry_fn(&ccx);
+    check_for_entry_fn(tcx);
 
     let err_count = tcx.sess.err_count();
     if err_count == 0 {
-        Ok(ccx.ast_ty_to_ty_cache.into_inner())
+        Ok(())
     } else {
         Err(err_count)
     }
index 860f6d98370ad1926a192e20b1c164c1f99f9c0b..f0f543fa6f23b7af8b774a5e5e8bbe72e0fd069d 100644 (file)
 //! The second pass over the AST determines the set of constraints.
 //! We walk the set of items and, for each member, generate new constraints.
 
-use dep_graph::DepTrackingMapConfig;
 use hir::def_id::DefId;
 use middle::resolve_lifetime as rl;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::maps::ItemVariances;
 use rustc::hir::map as hir_map;
 use syntax::ast;
 use rustc::hir;
@@ -28,6 +26,8 @@
 use super::terms::VarianceTerm::*;
 use super::xform::*;
 
+use dep_graph::DepNode::ItemSignature as VarianceDepNode;
+
 pub struct ConstraintContext<'a, 'tcx: 'a> {
     pub terms_cx: TermsContext<'a, 'tcx>,
 
@@ -65,8 +65,7 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
     };
 
     // See README.md for a discussion on dep-graph management.
-    tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id),
-                                      &mut constraint_cx);
+    tcx.visit_all_item_likes_in_krate(VarianceDepNode, &mut constraint_cx);
 
     constraint_cx
 }
@@ -279,7 +278,7 @@ fn xform(&mut self, v1: VarianceTermPtr<'a>, v2: VarianceTermPtr<'a>) -> Varianc
     }
 
     fn add_constraints_from_trait_ref(&mut self,
-                                      generics: &ty::Generics<'tcx>,
+                                      generics: &ty::Generics,
                                       trait_ref: ty::TraitRef<'tcx>,
                                       variance: VarianceTermPtr<'a>) {
         debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}",
@@ -291,7 +290,7 @@ fn add_constraints_from_trait_ref(&mut self,
         // This edge is actually implied by the call to
         // `lookup_trait_def`, but I'm trying to be future-proof. See
         // README.md for a discussion on dep-graph management.
-        self.tcx().dep_graph.read(ItemVariances::to_dep_node(&trait_ref.def_id));
+        self.tcx().dep_graph.read(VarianceDepNode(trait_ref.def_id));
 
         self.add_constraints_from_substs(generics,
                                          trait_ref.def_id,
@@ -305,7 +304,7 @@ fn add_constraints_from_trait_ref(&mut self,
     /// in a context with the generics defined in `generics` and
     /// ambient variance `variance`
     fn add_constraints_from_ty(&mut self,
-                               generics: &ty::Generics<'tcx>,
+                               generics: &ty::Generics,
                                ty: Ty<'tcx>,
                                variance: VarianceTermPtr<'a>) {
         debug!("add_constraints_from_ty(ty={:?}, variance={:?})",
@@ -350,7 +349,7 @@ fn add_constraints_from_ty(&mut self,
                 // This edge is actually implied by the call to
                 // `lookup_trait_def`, but I'm trying to be future-proof. See
                 // README.md for a discussion on dep-graph management.
-                self.tcx().dep_graph.read(ItemVariances::to_dep_node(&def.did));
+                self.tcx().dep_graph.read(VarianceDepNode(def.did));
 
                 self.add_constraints_from_substs(generics,
                                                  def.did,
@@ -367,7 +366,7 @@ fn add_constraints_from_ty(&mut self,
                 // This edge is actually implied by the call to
                 // `lookup_trait_def`, but I'm trying to be future-proof. See
                 // README.md for a discussion on dep-graph management.
-                self.tcx().dep_graph.read(ItemVariances::to_dep_node(&trait_ref.def_id));
+                self.tcx().dep_graph.read(VarianceDepNode(trait_ref.def_id));
 
                 self.add_constraints_from_substs(generics,
                                                  trait_ref.def_id,
@@ -412,8 +411,8 @@ fn add_constraints_from_ty(&mut self,
                 }
             }
 
-            ty::TyFnDef(.., &ty::BareFnTy { ref sig, .. }) |
-            ty::TyFnPtr(&ty::BareFnTy { ref sig, .. }) => {
+            ty::TyFnDef(.., sig) |
+            ty::TyFnPtr(sig) => {
                 self.add_constraints_from_sig(generics, sig, variance);
             }
 
@@ -433,9 +432,9 @@ fn add_constraints_from_ty(&mut self,
     /// Adds constraints appropriate for a nominal type (enum, struct,
     /// object, etc) appearing in a context with ambient variance `variance`
     fn add_constraints_from_substs(&mut self,
-                                   generics: &ty::Generics<'tcx>,
+                                   generics: &ty::Generics,
                                    def_id: DefId,
-                                   type_param_defs: &[ty::TypeParameterDef<'tcx>],
+                                   type_param_defs: &[ty::TypeParameterDef],
                                    region_param_defs: &[ty::RegionParameterDef],
                                    substs: &Substs<'tcx>,
                                    variance: VarianceTermPtr<'a>) {
@@ -465,8 +464,8 @@ fn add_constraints_from_substs(&mut self,
     /// Adds constraints appropriate for a function with signature
     /// `sig` appearing in a context with ambient variance `variance`
     fn add_constraints_from_sig(&mut self,
-                                generics: &ty::Generics<'tcx>,
-                                sig: &ty::PolyFnSig<'tcx>,
+                                generics: &ty::Generics,
+                                sig: ty::PolyFnSig<'tcx>,
                                 variance: VarianceTermPtr<'a>) {
         let contra = self.contravariant(variance);
         for &input in sig.0.inputs() {
@@ -478,7 +477,7 @@ fn add_constraints_from_sig(&mut self,
     /// Adds constraints appropriate for a region appearing in a
     /// context with ambient variance `variance`
     fn add_constraints_from_region(&mut self,
-                                   generics: &ty::Generics<'tcx>,
+                                   generics: &ty::Generics,
                                    region: &'tcx ty::Region,
                                    variance: VarianceTermPtr<'a>) {
         match *region {
@@ -518,7 +517,7 @@ fn add_constraints_from_region(&mut self,
     /// Adds constraints appropriate for a mutability-type pair
     /// appearing in a context with ambient variance `variance`
     fn add_constraints_from_mt(&mut self,
-                               generics: &ty::Generics<'tcx>,
+                               generics: &ty::Generics,
                                mt: &ty::TypeAndMut<'tcx>,
                                variance: VarianceTermPtr<'a>) {
         match mt.mutbl {
index 3ccec97d606ea3afa60a968ad831825c6a8edca6..6628c7c521fd103dec06ea7f5489b3f94d5dbecc 100644 (file)
@@ -137,7 +137,7 @@ fn write(&self) {
                           item_variances);
             }
 
-            tcx.item_variance_map
+            tcx.maps.variances
                .borrow_mut()
                .insert(item_def_id, Rc::new(item_variances));
         }
index 253d7a25b632f2fea0afd6a2e24b071b99b6cac8..36352f50e4406237115aa36abf42d55a53438c38 100644 (file)
@@ -20,9 +20,7 @@
 // a variable.
 
 use arena::TypedArena;
-use dep_graph::DepTrackingMapConfig;
 use rustc::ty::{self, TyCtxt};
-use rustc::ty::maps::ItemVariances;
 use std::fmt;
 use std::rc::Rc;
 use syntax::ast;
@@ -34,6 +32,8 @@
 
 pub type VarianceTermPtr<'a> = &'a VarianceTerm<'a>;
 
+use dep_graph::DepNode::ItemSignature as VarianceDepNode;
+
 #[derive(Copy, Clone, Debug)]
 pub struct InferredIndex(pub usize);
 
@@ -109,7 +109,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>
     };
 
     // See README.md for a discussion on dep-graph management.
-    tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), &mut terms_cx);
+    tcx.visit_all_item_likes_in_krate(|def_id| VarianceDepNode(def_id), &mut terms_cx);
 
     terms_cx
 }
@@ -178,8 +178,7 @@ fn add_inferreds_for_item(&mut self,
         // parameters".
         if self.num_inferred() == inferreds_on_entry {
             let item_def_id = self.tcx.hir.local_def_id(item_id);
-            self.tcx
-                .item_variance_map
+            self.tcx.maps.variances
                 .borrow_mut()
                 .insert(item_def_id, self.empty_variances.clone());
         }
index 93854193762fbcf2d2ef7a63e9f2c02250d846c2..c4476483186c7a35ed1de6bb20e9de0e52ff179f 100644 (file)
@@ -15,6 +15,7 @@
 use std::iter::once;
 
 use syntax::ast;
+use syntax_pos::DUMMY_SP;
 use rustc::hir;
 
 use rustc::hir::def::{Def, CtorKind};
@@ -164,11 +165,7 @@ pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait {
 }
 
 fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function {
-    let ty = cx.tcx.item_type(did);
-    let (decl, style, abi) = match ty.sty {
-        ty::TyFnDef(.., ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi),
-        _ => panic!("bad function"),
-    };
+    let sig = cx.tcx.item_type(did).fn_sig();
 
     let constness = if cx.tcx.sess.cstore.is_const_fn(did) {
         hir::Constness::Const
@@ -178,11 +175,11 @@ fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function {
 
     let predicates = cx.tcx.item_predicates(did);
     clean::Function {
-        decl: decl,
+        decl: (did, sig).clean(cx),
         generics: (cx.tcx.item_generics(did), &predicates).clean(cx),
-        unsafety: style,
+        unsafety: sig.unsafety(),
         constness: constness,
-        abi: abi,
+        abi: sig.abi(),
     }
 }
 
@@ -235,10 +232,10 @@ fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef {
 
 pub fn build_impls(cx: &DocContext, did: DefId) -> Vec<clean::Item> {
     let tcx = cx.tcx;
-    tcx.populate_inherent_implementations_for_type_if_necessary(did);
+    tcx.populate_inherent_implementations_for_type_if_necessary(DUMMY_SP, did);
     let mut impls = Vec::new();
 
-    if let Some(i) = tcx.inherent_impls.borrow().get(&did) {
+    if let Some(i) = tcx.maps.inherent_impls.borrow().get(&did) {
         for &did in i.iter() {
             build_impl(cx, did, &mut impls);
         }
index 751ed7d443d290bc04652de2c7c783a7999cb79e..1294296840ebd75b329bd6df6c81e1309883caf3 100644 (file)
@@ -596,14 +596,18 @@ fn clean(&self, cx: &DocContext) -> TyParam {
     }
 }
 
-impl<'tcx> Clean<TyParam> for ty::TypeParameterDef<'tcx> {
+impl<'tcx> Clean<TyParam> for ty::TypeParameterDef {
     fn clean(&self, cx: &DocContext) -> TyParam {
         cx.renderinfo.borrow_mut().external_typarams.insert(self.def_id, self.name.clean(cx));
         TyParam {
             name: self.name.clean(cx),
             did: self.def_id,
             bounds: vec![], // these are filled in from the where-clauses
-            default: self.default.clean(cx),
+            default: if self.has_default {
+                Some(cx.tcx.item_type(self.def_id).clean(cx))
+            } else {
+                None
+            }
         }
     }
 }
@@ -965,7 +969,7 @@ fn clean(&self, cx: &DocContext) -> Generics {
     }
 }
 
-impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>,
+impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
                                     &'a ty::GenericPredicates<'tcx>) {
     fn clean(&self, cx: &DocContext) -> Generics {
         use self::WherePredicate as WP;
@@ -1159,7 +1163,7 @@ fn clean(&self, cx: &DocContext) -> FnDecl {
     }
 }
 
-impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
+impl<'a, 'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
     fn clean(&self, cx: &DocContext) -> FnDecl {
         let (did, sig) = *self;
         let mut names = if cx.tcx.hir.as_local_node_id(did).is_some() {
@@ -1348,11 +1352,8 @@ fn clean(&self, cx: &DocContext) -> Item {
             ty::AssociatedKind::Method => {
                 let generics = (cx.tcx.item_generics(self.def_id),
                                 &cx.tcx.item_predicates(self.def_id)).clean(cx);
-                let fty = match cx.tcx.item_type(self.def_id).sty {
-                    ty::TyFnDef(_, _, f) => f,
-                    _ => unreachable!()
-                };
-                let mut decl = (self.def_id, &fty.sig).clean(cx);
+                let sig = cx.tcx.item_type(self.def_id).fn_sig();
+                let mut decl = (self.def_id, sig).clean(cx);
 
                 if self.method_has_self_argument {
                     let self_ty = match self.container {
@@ -1361,7 +1362,7 @@ fn clean(&self, cx: &DocContext) -> Item {
                         }
                         ty::TraitContainer(_) => cx.tcx.mk_self_type()
                     };
-                    let self_arg_ty = *fty.sig.input(0).skip_binder();
+                    let self_arg_ty = *sig.input(0).skip_binder();
                     if self_arg_ty == self_ty {
                         decl.inputs.values[0].type_ = Generic(String::from("Self"));
                     } else if let ty::TyRef(_, mt) = self_arg_ty.sty {
@@ -1382,20 +1383,20 @@ fn clean(&self, cx: &DocContext) -> Item {
                 };
                 if provided {
                     MethodItem(Method {
-                        unsafety: fty.unsafety,
+                        unsafety: sig.unsafety(),
                         generics: generics,
                         decl: decl,
-                        abi: fty.abi,
+                        abi: sig.abi(),
 
                         // trait methods canot (currently, at least) be const
                         constness: hir::Constness::NotConst,
                     })
                 } else {
                     TyMethodItem(TyMethod {
-                        unsafety: fty.unsafety,
+                        unsafety: sig.unsafety(),
                         generics: generics,
                         decl: decl,
-                        abi: fty.abi,
+                        abi: sig.abi(),
                     })
                 }
             }
@@ -1475,7 +1476,7 @@ pub struct PolyTrait {
 /// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
 /// type out of the AST/TyCtxt given one of these, if more information is needed. Most importantly
 /// it does not preserve mutability or boxes.
-#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
+#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq)]
 pub enum Type {
     /// structs/enums/traits (most that'd be an hir::TyPath)
     ResolvedPath {
@@ -1768,7 +1769,7 @@ fn clean(&self, cx: &DocContext) -> Type {
             }
             TyPath(hir::QPath::TypeRelative(ref qself, ref segment)) => {
                 let mut def = Def::Err;
-                if let Some(ty) = cx.hir_ty_to_ty.get(&self.id) {
+                if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&self.id) {
                     if let ty::TyProjection(proj) = ty.sty {
                         def = Def::Trait(proj.trait_ref.def_id);
                     }
@@ -1830,16 +1831,16 @@ fn clean(&self, cx: &DocContext) -> Type {
                 mutability: mt.mutbl.clean(cx),
                 type_: box mt.ty.clean(cx),
             },
-            ty::TyFnDef(.., ref fty) |
-            ty::TyFnPtr(ref fty) => BareFunction(box BareFunctionDecl {
-                unsafety: fty.unsafety,
+            ty::TyFnDef(.., sig) |
+            ty::TyFnPtr(sig) => BareFunction(box BareFunctionDecl {
+                unsafety: sig.unsafety(),
                 generics: Generics {
                     lifetimes: Vec::new(),
                     type_params: Vec::new(),
                     where_predicates: Vec::new()
                 },
-                decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), &fty.sig).clean(cx),
-                abi: fty.abi,
+                decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), sig).clean(cx),
+                abi: sig.abi(),
             }),
             ty::TyAdt(def, substs) => {
                 let did = def.did;
index 5393e395bbe43aad2e90af3c1e66729493742754..0a9db2c26464ce6370b4c4c573742e469bf55959 100644 (file)
 use rustc::hir::def_id::DefId;
 use rustc::hir::def::{Def, ExportMap};
 use rustc::middle::privacy::AccessLevels;
-use rustc::ty::{self, TyCtxt, GlobalArenas, Ty};
+use rustc::ty::{self, TyCtxt, GlobalArenas};
 use rustc::hir::map as hir_map;
 use rustc::lint;
-use rustc::util::nodemap::{FxHashMap, NodeMap};
+use rustc::util::nodemap::FxHashMap;
 use rustc_trans::back::link;
 use rustc_resolve as resolve;
 use rustc_metadata::cstore::CStore;
@@ -65,9 +65,6 @@ pub struct DocContext<'a, 'tcx: 'a> {
     /// Table node id of lifetime parameter definition -> substituted lifetime
     pub lt_substs: RefCell<FxHashMap<ast::NodeId, clean::Lifetime>>,
     pub export_map: ExportMap,
-
-    /// Table from HIR Ty nodes to their resolved Ty.
-    pub hir_ty_to_ty: NodeMap<Ty<'tcx>>,
 }
 
 impl<'a, 'tcx> DocContext<'a, 'tcx> {
@@ -183,7 +180,7 @@ pub fn run_core(search_paths: SearchPaths,
             sess.fatal("Compilation failed, aborting rustdoc");
         }
 
-        let ty::CrateAnalysis { access_levels, export_map, hir_ty_to_ty, .. } = analysis;
+        let ty::CrateAnalysis { access_levels, export_map, .. } = analysis;
 
         // Convert from a NodeId set to a DefId set since we don't always have easy access
         // to the map from defid -> nodeid
@@ -202,7 +199,6 @@ pub fn run_core(search_paths: SearchPaths,
             ty_substs: Default::default(),
             lt_substs: Default::default(),
             export_map: export_map,
-            hir_ty_to_ty: hir_ty_to_ty,
         };
         debug!("crate: {:?}", tcx.hir.krate());
 
index 6f8c6aa7094dde3b994234642e18748885f4bb73..23507dc889b710be084cb53985f9575d7ba87dc3 100644 (file)
@@ -90,6 +90,16 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
+impl<'a, T: fmt::Debug> fmt::Debug for CommaSep<'a, T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        for (i, item) in self.0.iter().enumerate() {
+            if i != 0 { write!(f, ", ")?; }
+            fmt::Debug::fmt(item, f)?;
+        }
+        Ok(())
+    }
+}
+
 impl<'a> fmt::Display for TyParamBounds<'a> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let &TyParamBounds(bounds) = self;
@@ -165,7 +175,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         if f.alternate() {
             clause.push_str(" where ");
         } else {
-            clause.push_str(" <span class='where fmt-newline'>where ");
+            clause.push_str(" <span class=\"where fmt-newline\">where ");
         }
         for (i, pred) in gens.where_predicates.iter().enumerate() {
             if i > 0 {
@@ -449,8 +459,8 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
                     } else {
                         root.push_str(&seg.name);
                         root.push_str("/");
-                        write!(w, "<a class='mod'
-                                       href='{}index.html'>{}</a>::",
+                        write!(w, "<a class=\"mod\"
+                                       href=\"{}index.html\">{}</a>::",
                                  root,
                                  seg.name)?;
                     }
@@ -491,7 +501,7 @@ fn primitive_link(f: &mut fmt::Formatter,
             Some(&def_id) if def_id.is_local() => {
                 let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
                 let len = if len == 0 {0} else {len - 1};
-                write!(f, "<a class='primitive' href='{}primitive.{}.html'>",
+                write!(f, "<a class=\"primitive\" href=\"{}primitive.{}.html\">",
                        repeat("../").take(len).collect::<String>(),
                        prim.to_url_str())?;
                 needs_termination = true;
@@ -508,7 +518,7 @@ fn primitive_link(f: &mut fmt::Formatter,
                     (.., render::Unknown) => None,
                 };
                 if let Some((cname, root)) = loc {
-                    write!(f, "<a class='primitive' href='{}{}/primitive.{}.html'>",
+                    write!(f, "<a class=\"primitive\" href=\"{}{}/primitive.{}.html\">",
                            root,
                            cname,
                            prim.to_url_str())?;
@@ -550,7 +560,7 @@ impl<'a> fmt::Display for HRef<'a> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match href(self.did) {
             Some((url, shortty, fqp)) => if !f.alternate() {
-                write!(f, "<a class='{}' href='{}' title='{} {}'>{}</a>",
+                write!(f, "<a class=\"{}\" href=\"{}\" title=\"{} {}\">{}</a>",
                        shortty, url, shortty, fqp.join("::"), self.text)
             } else {
                 write!(f, "{}", self.text)
@@ -560,7 +570,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt::Result {
+fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool,
+            is_not_debug: bool) -> fmt::Result {
     match *t {
         clean::Generic(ref name) => {
             f.write_str(name)
@@ -571,7 +582,8 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
             tybounds(f, typarams)
         }
         clean::Infer => write!(f, "_"),
-        clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
+        clean::Primitive(prim) if is_not_debug => primitive_link(f, prim, prim.as_str()),
+        clean::Primitive(prim) => write!(f, "{}", prim.as_str()),
         clean::BareFunction(ref decl) => {
             if f.alternate() {
                 write!(f, "{}{}fn{:#}{:#}",
@@ -589,26 +601,30 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
         }
         clean::Tuple(ref typs) => {
             match &typs[..] {
-                &[] => primitive_link(f, PrimitiveType::Tuple, "()"),
-                &[ref one] => {
+                &[] if is_not_debug => primitive_link(f, PrimitiveType::Tuple, "()"),
+                &[] => write!(f, "()"),
+                &[ref one] if is_not_debug => {
                     primitive_link(f, PrimitiveType::Tuple, "(")?;
                     //carry f.alternate() into this display w/o branching manually
                     fmt::Display::fmt(one, f)?;
                     primitive_link(f, PrimitiveType::Tuple, ",)")
                 }
-                many => {
+                &[ref one] => write!(f, "({:?},)", one),
+                many if is_not_debug => {
                     primitive_link(f, PrimitiveType::Tuple, "(")?;
                     fmt::Display::fmt(&CommaSep(&many), f)?;
                     primitive_link(f, PrimitiveType::Tuple, ")")
                 }
+                many => write!(f, "({:?})", &CommaSep(&many)),
             }
         }
-        clean::Vector(ref t) => {
+        clean::Vector(ref t) if is_not_debug => {
             primitive_link(f, PrimitiveType::Slice, &format!("["))?;
             fmt::Display::fmt(t, f)?;
             primitive_link(f, PrimitiveType::Slice, &format!("]"))
         }
-        clean::FixedVector(ref t, ref s) => {
+        clean::Vector(ref t) => write!(f, "[{:?}]", t),
+        clean::FixedVector(ref t, ref s) if is_not_debug => {
             primitive_link(f, PrimitiveType::Array, "[")?;
             fmt::Display::fmt(t, f)?;
             if f.alternate() {
@@ -619,10 +635,17 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
                                &format!("; {}]", Escape(s)))
             }
         }
+        clean::FixedVector(ref t, ref s) => {
+            if f.alternate() {
+                write!(f, "[{:?}; {}]", t, s)
+            } else {
+                write!(f, "[{:?}; {}]", t, Escape(s))
+            }
+        }
         clean::Never => f.write_str("!"),
         clean::RawPointer(m, ref t) => {
             match **t {
-                clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
+                clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} if is_not_debug => {
                     if f.alternate() {
                         primitive_link(f, clean::PrimitiveType::RawPointer,
                                        &format!("*{}{:#}", RawMutableSpace(m), t))
@@ -631,11 +654,21 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
                                        &format!("*{}{}", RawMutableSpace(m), t))
                     }
                 }
-                _ => {
+                clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
+                    if f.alternate() {
+                        write!(f, "*{}{:#?}", RawMutableSpace(m), t)
+                    } else {
+                        write!(f, "*{}{:?}", RawMutableSpace(m), t)
+                    }
+                }
+                _ if is_not_debug => {
                     primitive_link(f, clean::PrimitiveType::RawPointer,
                                    &format!("*{}", RawMutableSpace(m)))?;
                     fmt::Display::fmt(t, f)
                 }
+                _ => {
+                    write!(f, "*{}{:?}", RawMutableSpace(m), t)
+                }
             }
         }
         clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
@@ -647,15 +680,23 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
             match **ty {
                 clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
                     match **bt {
-                        clean::Generic(_) =>
+                        clean::Generic(_) if is_not_debug => {
                             if f.alternate() {
                                 primitive_link(f, PrimitiveType::Slice,
                                     &format!("&{}{}[{:#}]", lt, m, **bt))
                             } else {
                                 primitive_link(f, PrimitiveType::Slice,
                                     &format!("&amp;{}{}[{}]", lt, m, **bt))
-                            },
-                        _ => {
+                            }
+                        }
+                        clean::Generic(_) => {
+                            if f.alternate() {
+                                write!(f, "&{}{}[{:#?}]", lt, m, **bt)
+                            } else {
+                                write!(f, "&{}{}[{:?}]", lt, m, **bt)
+                            }
+                        }
+                        _ if is_not_debug => {
                             if f.alternate() {
                                 primitive_link(f, PrimitiveType::Slice,
                                                &format!("&{}{}[", lt, m))?;
@@ -667,15 +708,26 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
                             }
                             primitive_link(f, PrimitiveType::Slice, "]")
                         }
+                        _ => {
+                            if f.alternate() {
+                                write!(f, "&{}{}[{:#?}]", lt, m, **bt)
+                            } else {
+                                write!(f, "&{}{}[{:?}]", lt, m, **bt)
+                            }
+                        }
                     }
                 }
                 _ => {
                     if f.alternate() {
                         write!(f, "&{}{}", lt, m)?;
-                        fmt_type(&ty, f, use_absolute)
+                        fmt_type(&ty, f, use_absolute, is_not_debug)
                     } else {
-                        write!(f, "&amp;{}{}", lt, m)?;
-                        fmt_type(&ty, f, use_absolute)
+                        if is_not_debug {
+                            write!(f, "&amp;{}{}", lt, m)?;
+                        } else {
+                            write!(f, "&{}{}", lt, m)?;
+                        }
+                        fmt_type(&ty, f, use_absolute, is_not_debug)
                     }
                 }
             }
@@ -723,9 +775,17 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
         }
         clean::QPath { ref name, ref self_type, ref trait_ } => {
             if f.alternate() {
-                write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name)
+                if is_not_debug {
+                    write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name)
+                } else {
+                    write!(f, "<{:#?} as {:#?}>::{}", self_type, trait_, name)
+                }
             } else {
-                write!(f, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
+                if is_not_debug {
+                    write!(f, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
+                } else {
+                    write!(f, "<{:?} as {:?}>::{}", self_type, trait_, name)
+                }
             }
         }
         clean::Unique(..) => {
@@ -736,7 +796,13 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
 
 impl fmt::Display for clean::Type {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt_type(self, f, false)
+        fmt_type(self, f, false, true)
+    }
+}
+
+impl fmt::Debug for clean::Type {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt_type(self, f, false, false)
     }
 }
 
@@ -777,7 +843,7 @@ fn fmt_impl(i: &clean::Impl,
         plain.push_str(" for ");
     }
 
-    fmt_type(&i.for_, f, use_absolute)?;
+    fmt_type(&i.for_, f, use_absolute, true)?;
     plain.push_str(&format!("{:#}", i.for_));
 
     fmt::Display::fmt(&WhereClause(&i.generics, plain.len() + 1), f)?;
index 0629e93e7ef5d1f222dea269492fef4d150ad7e7..0dafc4225a3210653e6d9b445914c825db8c9a35 100644 (file)
@@ -144,12 +144,12 @@ fn string<T: Display>(&mut self,
                           -> io::Result<()> {
         match klass {
             Class::None => write!(self, "{}", text),
-            klass => write!(self, "<span class='{}'>{}</span>", klass.rustdoc_class(), text),
+            klass => write!(self, "<span class=\"{}\">{}</span>", klass.rustdoc_class(), text),
         }
     }
 
     fn enter_span(&mut self, klass: Class) -> io::Result<()> {
-        write!(self, "<span class='{}'>", klass.rustdoc_class())
+        write!(self, "<span class=\"{}\">", klass.rustdoc_class())
     }
 
     fn exit_span(&mut self) -> io::Result<()> {
@@ -315,7 +315,7 @@ fn write_token<W: Writer>(&mut self,
             token::Lifetime(..) => Class::Lifetime,
 
             token::Underscore | token::Eof | token::Interpolated(..) |
-            token::MatchNt(..) | token::SubstNt(..) | token::Tilde | token::At => Class::None,
+            token::SubstNt(..) | token::Tilde | token::At => Class::None,
         };
 
         // Anything that didn't return above is the simple case where we the
@@ -363,7 +363,7 @@ fn write_header(class: Option<&str>,
     if let Some(id) = id {
         write!(out, "id='{}' ", id)?;
     }
-    write!(out, "class='rust {}'>\n", class.unwrap_or(""))
+    write!(out, "class=\"rust {}\">\n", class.unwrap_or(""))
 }
 
 fn write_footer(out: &mut Write) -> io::Result<()> {
index ae4c94d4b38c096feb09e98b92b86a48c0528ae6..44f71d8952985b0098e482d561dad83d960969da 100644 (file)
@@ -1547,7 +1547,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                        component)?;
             }
         }
-        write!(fmt, "<a class='{}' href=''>{}</a>",
+        write!(fmt, "<a class=\"{}\" href=''>{}</a>",
                self.item.type_(), self.item.name.as_ref().unwrap())?;
 
         write!(fmt, "</span>")?; // in-band
@@ -1654,9 +1654,35 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin
     Ok(())
 }
 
+fn md_render_assoc_item(item: &clean::Item) -> String {
+    match item.inner {
+        clean::AssociatedConstItem(ref ty, ref default) => {
+            if let Some(default) = default.as_ref() {
+                format!("```\n{}: {:?} = {}\n```\n\n", item.name.as_ref().unwrap(), ty, default)
+            } else {
+                format!("```\n{}: {:?}\n```\n\n", item.name.as_ref().unwrap(), ty)
+            }
+        }
+        _ => String::new(),
+    }
+}
+
+fn get_doc_value(item: &clean::Item) -> Option<&str> {
+    let x = item.doc_value();
+    if x.is_none() {
+        match item.inner {
+            clean::AssociatedConstItem(_, _) => Some(""),
+            _ => None,
+        }
+    } else {
+        x
+    }
+}
+
 fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
-    if let Some(s) = item.doc_value() {
-        write!(w, "<div class='docblock'>{}</div>", Markdown(s))?;
+    if let Some(s) = get_doc_value(item) {
+        write!(w, "<div class='docblock'>{}</div>",
+               Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?;
     }
     Ok(())
 }
@@ -1817,7 +1843,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
                 let doc_value = myitem.doc_value().unwrap_or("");
                 write!(w, "
                        <tr class='{stab} module-item'>
-                           <td><a class='{class}' href='{href}'
+                           <td><a class=\"{class}\" href=\"{href}\"
                                   title='{title_type} {title}'>{name}</a>{unsafety_flag}</td>
                            <td class='docblock-short'>
                                {stab_docs} {docs}
@@ -1878,7 +1904,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
                                             &cx.shared.issue_tracker_base_url,
                                             stab.issue) {
                     (true, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
-                        format!(" (<code>{}</code> <a href=\"{}{}\">#{}</a>)",
+                        format!(" (<code>{} </code><a href=\"{}{}\">#{}</a>)",
                                 Escape(&stab.feature), tracker_url, issue_no, issue_no),
                     (false, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
                         format!(" (<a href=\"{}{}\">#{}</a>)", Escape(&tracker_url), issue_no,
@@ -1890,12 +1916,12 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
                 if stab.unstable_reason.is_empty() {
                     stability.push(format!("<div class='stab unstable'>\
                                             <span class=microscope>🔬</span> \
-                                            This is a nightly-only experimental API. &nbsp;{}\
+                                            This is a nightly-only experimental API. {}\
                                             </div>",
-                                   unstable_extra));
+                                           unstable_extra));
                 } else {
                     let text = format!("<summary><span class=microscope>🔬</span> \
-                                        This is a nightly-only experimental API. &nbsp;{}\
+                                        This is a nightly-only experimental API. {}\
                                         </summary>{}",
                                        unstable_extra, MarkdownHtml(&stab.unstable_reason));
                     stability.push(format!("<div class='stab unstable'><details>{}</details></div>",
@@ -2215,16 +2241,12 @@ fn naive_assoc_href(it: &clean::Item, link: AssocItemLink) -> String {
 fn assoc_const(w: &mut fmt::Formatter,
                it: &clean::Item,
                ty: &clean::Type,
-               default: Option<&String>,
+               _default: Option<&String>,
                link: AssocItemLink) -> fmt::Result {
-    write!(w, "const <a href='{}' class='constant'>{}</a>",
+    write!(w, "const <a href='{}' class=\"constant\"><b>{}</b></a>: {}",
            naive_assoc_href(it, link),
-           it.name.as_ref().unwrap())?;
-
-    write!(w, ": {}", ty)?;
-    if let Some(default) = default {
-        write!(w, " = {}", Escape(default))?;
-    }
+           it.name.as_ref().unwrap(),
+           ty)?;
     Ok(())
 }
 
@@ -2232,7 +2254,7 @@ fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
               bounds: &Vec<clean::TyParamBound>,
               default: Option<&clean::Type>,
               link: AssocItemLink) -> fmt::Result {
-    write!(w, "type <a href='{}' class='type'>{}</a>",
+    write!(w, "type <a href='{}' class=\"type\">{}</a>",
            naive_assoc_href(it, link),
            it.name.as_ref().unwrap())?;
     if !bounds.is_empty() {
@@ -2375,7 +2397,7 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                 let ns_id = derive_id(format!("{}.{}",
                                               field.name.as_ref().unwrap(),
                                               ItemType::StructField.name_space()));
-                write!(w, "<span id='{id}' class='{item_type}'>
+                write!(w, "<span id='{id}' class=\"{item_type}\">
                            <span id='{ns_id}' class='invisible'>
                            <code>{name}: {ty}</code>
                            </span></span>",
@@ -2417,7 +2439,7 @@ fn item_union(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     if fields.peek().is_some() {
         write!(w, "<h2 class='fields'>Fields</h2>")?;
         for (field, ty) in fields {
-            write!(w, "<span id='{shortty}.{name}' class='{shortty}'><code>{name}: {ty}</code>
+            write!(w, "<span id='{shortty}.{name}' class=\"{shortty}\"><code>{name}: {ty}</code>
                        </span>",
                    shortty = ItemType::StructField,
                    name = field.name.as_ref().unwrap(),
@@ -2902,7 +2924,7 @@ fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
                 if render_method_item {
                     let id = derive_id(format!("{}.{}", item_type, name));
                     let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
-                    write!(w, "<h4 id='{}' class='{}'>", id, item_type)?;
+                    write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
                     write!(w, "<span id='{}' class='invisible'>", ns_id)?;
                     write!(w, "<code>")?;
                     render_assoc_item(w, item, link.anchor(&id), ItemType::Impl)?;
@@ -2914,7 +2936,7 @@ fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
             clean::TypedefItem(ref tydef, _) => {
                 let id = derive_id(format!("{}.{}", ItemType::AssociatedType, name));
                 let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
-                write!(w, "<h4 id='{}' class='{}'>", id, item_type)?;
+                write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
                 write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
                 assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id))?;
                 write!(w, "</code></span></h4>\n")?;
@@ -2922,7 +2944,7 @@ fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
             clean::AssociatedConstItem(ref ty, ref default) => {
                 let id = derive_id(format!("{}.{}", item_type, name));
                 let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
-                write!(w, "<h4 id='{}' class='{}'>", id, item_type)?;
+                write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
                 write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
                 assoc_const(w, item, ty, default.as_ref(), link.anchor(&id))?;
                 write!(w, "</code></span></h4>\n")?;
@@ -2930,7 +2952,7 @@ fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
             clean::ConstantItem(ref c) => {
                 let id = derive_id(format!("{}.{}", item_type, name));
                 let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
-                write!(w, "<h4 id='{}' class='{}'>", id, item_type)?;
+                write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
                 write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
                 assoc_const(w, item, &c.type_, Some(&c.expr), link.anchor(&id))?;
                 write!(w, "</code></span></h4>\n")?;
@@ -2938,7 +2960,7 @@ fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
             clean::AssociatedTypeItem(ref bounds, ref default) => {
                 let id = derive_id(format!("{}.{}", item_type, name));
                 let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
-                write!(w, "<h4 id='{}' class='{}'>", id, item_type)?;
+                write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
                 write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
                 assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id))?;
                 write!(w, "</code></span></h4>\n")?;
@@ -2956,7 +2978,7 @@ fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
                         // We need the stability of the item from the trait
                         // because impls can't have a stability.
                         document_stability(w, cx, it)?;
-                        if item.doc_value().is_some() {
+                        if get_doc_value(item).is_some() {
                             document_full(w, item)?;
                         } else {
                             // In case the item isn't documented,
index c12e1e7d6080db8739e07db05e9744fd57aa745b..200285862276a5f8e63ea479e02fde2268a9538c 100644 (file)
             .html("[<span class='inner'></span>]");
         toggle.children(".inner").text(labelForToggleButton(false));
 
-        $(".method").each(function() {
+        $(".method, .impl-items > .associatedconstant").each(function() {
             if ($(this).next().is(".docblock") ||
                 ($(this).next().is(".stability") && $(this).next().next().is(".docblock"))) {
                     $(this).children().last().after(toggle.clone());
index 681d2354056f67b7257a71c933cd978f05decd29..b0bf69b0181f22ae2de2705e1a333788bda169d5 100644 (file)
@@ -89,7 +89,7 @@ h2 {
 h3 {
        font-size: 1.3em;
 }
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) {
+h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
        font-weight: 500;
        margin: 20px 0 15px 0;
        padding-bottom: 6px;
@@ -99,10 +99,10 @@ h1.fqn {
        margin-top: 0;
        position: relative;
 }
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) {
+h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
        border-bottom: 1px solid;
 }
-h3.impl, h3.method, h4.method, h3.type, h4.type {
+h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant {
        font-weight: 600;
        margin-top: 10px;
        margin-bottom: 10px;
@@ -382,7 +382,7 @@ h4 > code, h3 > code, .invisible > code {
 .content .impl-items .docblock, .content .impl-items .stability {
        margin-left: 40px;
 }
-.content .impl-items .method, .content .impl-items > .type {
+.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant {
        margin-left: 20px;
 }
 
index 1c37067d7f69d46f8914db8fd4ed496dec3eccd9..c7000ee1e40e764f5a79837cd2149cc24d891a71 100644 (file)
@@ -12,7 +12,7 @@
 use std::ffi::OsString;
 use std::io::prelude::*;
 use std::io;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use std::panic::{self, AssertUnwindSafe};
 use std::process::Command;
 use std::rc::Rc;
@@ -485,7 +485,15 @@ pub fn set_position(&mut self, position: Span) {
 
     pub fn get_filename(&self) -> String {
         if let Some(ref codemap) = self.codemap {
-            codemap.span_to_filename(self.position)
+            let filename = codemap.span_to_filename(self.position);
+            if let Ok(cur_dir) = env::current_dir() {
+                if let Ok(path) = Path::new(&filename).strip_prefix(&cur_dir) {
+                    if let Some(path) = path.to_str() {
+                        return path.to_owned();
+                    }
+                }
+            }
+            filename
         } else if let Some(ref filename) = self.filename {
             filename.clone()
         } else {
index 394eb4779898c1021b754a4612ca69e08658c501..236d9f230b5d470718467b351ed6ce75d16fafa5 100644 (file)
@@ -199,7 +199,7 @@ pub fn visit_mod_contents(&mut self, span: Span, attrs: hir::HirVec<ast::Attribu
         self.inside_public_path = orig_inside_public_path;
         if let Some(exports) = self.cx.export_map.get(&id) {
             for export in exports {
-                if let Def::Macro(def_id) = export.def {
+                if let Def::Macro(def_id, ..) = export.def {
                     if def_id.krate == LOCAL_CRATE {
                         continue // These are `krate.exported_macros`, handled in `self.visit()`.
                     }
@@ -211,7 +211,7 @@ pub fn visit_mod_contents(&mut self, span: Span, attrs: hir::HirVec<ast::Attribu
                     };
 
                     // FIXME(jseyfried) merge with `self.visit_macro()`
-                    let matchers = def.body.chunks(4).map(|arm| arm[0].get_span()).collect();
+                    let matchers = def.body.chunks(4).map(|arm| arm[0].span()).collect();
                     om.macros.push(Macro {
                         def_id: def_id,
                         attrs: def.attrs.clone().into(),
@@ -521,7 +521,7 @@ pub fn visit_item(&mut self, item: &hir::Item,
     // convert each exported_macro into a doc item
     fn visit_local_macro(&self, def: &hir::MacroDef) -> Macro {
         // Extract the spans of all matchers. They represent the "interface" of the macro.
-        let matchers = def.body.chunks(4).map(|arm| arm[0].get_span()).collect();
+        let matchers = def.body.chunks(4).map(|arm| arm[0].span()).collect();
 
         Macro {
             def_id: self.cx.tcx.hir.local_def_id(def.id),
index cee292f99153e4fc318463094d1633f8ac8e6074..852c98eb2fd52fcfb37e4cab0131f3aa415b6338 100644 (file)
@@ -24,7 +24,7 @@
 /// specific rustdoc annotations into account (i.e. `doc(hidden)`)
 pub struct LibEmbargoVisitor<'a, 'b: 'a, 'tcx: 'b> {
     cx: &'a ::core::DocContext<'b, 'tcx>,
-    cstore: &'a CrateStore<'tcx>,
+    cstore: &'a CrateStore,
     // Accessibility levels for reachable nodes
     access_levels: RefMut<'a, AccessLevels<DefId>>,
     // Previous accessibility level, None means unreachable
index 0fca374f6e6d1035381faf7ba96498965663378b..038dea77f3ead8d570483a299e02a99059ece819 100644 (file)
@@ -59,6 +59,10 @@ fn main() {
         println!("cargo:rustc-link-lib=userenv");
         println!("cargo:rustc-link-lib=shell32");
     } else if target.contains("fuchsia") {
+        // use system-provided libbacktrace
+        if cfg!(feature = "backtrace") {
+            println!("cargo:rustc-link-lib=backtrace");
+        }
         println!("cargo:rustc-link-lib=magenta");
         println!("cargo:rustc-link-lib=mxio");
         println!("cargo:rustc-link-lib=launchpad"); // for std::process
index fd5827b4c07537abeadc123e0550dfc61a135894..f0738fe9b7033fea50795eaccb0dbe33238f4760 100644 (file)
@@ -182,12 +182,12 @@ fn capacity(&self, raw_cap: usize) -> usize {
 // ----------------------
 // To protect against degenerate performance scenarios (including DOS attacks),
 // the implementation includes an adaptive behavior that can resize the map
-// early (before its capacity is exceeded) when suspiciously long probe or
-// forward shifts sequences are encountered.
+// early (before its capacity is exceeded) when suspiciously long probe sequences
+// are encountered.
 //
 // With this algorithm in place it would be possible to turn a CPU attack into
 // a memory attack due to the aggressive resizing. To prevent that the
-// adaptive behavior only triggers when the map occupancy is half the maximum occupancy.
+// adaptive behavior only triggers when the map is at least half full.
 // This reduces the effectiveness of the algorithm but also makes it completely safe.
 //
 // The previous safety measure also prevents degenerate interactions with
@@ -195,16 +195,11 @@ fn capacity(&self, raw_cap: usize) -> usize {
 // DOS attack.
 //
 const DISPLACEMENT_THRESHOLD: usize = 128;
-const FORWARD_SHIFT_THRESHOLD: usize = 512;
 //
-// The thresholds of 128 and 512 are chosen to minimize the chance of exceeding them.
+// The threshold of 128 is chosen to minimize the chance of exceeding it.
 // In particular, we want that chance to be less than 10^-8 with a load of 90%.
 // For displacement, the smallest constant that fits our needs is 90,
-// so we round that up to 128. For the number of forward-shifted buckets,
-// we choose k=512. Keep in mind that the run length is a sum of the displacement and
-// the number of forward-shifted buckets, so its threshold is 128+512=640.
-// Even though the probability of having a run length of more than 640 buckets may be
-// higher than the probability we want, it should be low enough.
+// so we round that up to 128.
 //
 // At a load factor of α, the odds of finding the target bucket after exactly n
 // unsuccesful probes[1] are
@@ -212,16 +207,12 @@ fn capacity(&self, raw_cap: usize) -> usize {
 // Pr_α{displacement = n} =
 // (1 - α) / α * ∑_{k≥1} e^(-kα) * (kα)^(k+n) / (k + n)! * (1 - kα / (k + n + 1))
 //
-// We use this formula to find the probability of loading half of triggering the adaptive behavior
+// We use this formula to find the probability of triggering the adaptive behavior
 //
 // Pr_0.909{displacement > 128} = 1.601 * 10^-11
 //
-// FIXME: Extend with math for shift threshold in [2]
-//
 // 1. Alfredo Viola (2005). Distributional analysis of Robin Hood linear probing
 //    hashing with buckets.
-// 2. http://www.cs.tau.ac.il/~zwick/Adv-Alg-2015/Linear-Probing.pdf
-
 
 /// A hash map implementation which uses linear probing with Robin Hood bucket
 /// stealing.
@@ -494,7 +485,7 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
                                 mut hash: SafeHash,
                                 mut key: K,
                                 mut val: V)
-                                -> (usize, &'a mut V) {
+                                -> &'a mut V {
     let start_index = bucket.index();
     let size = bucket.table().size();
     // Save the *starting point*.
@@ -519,7 +510,6 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
                 Empty(bucket) => {
                     // Found a hole!
                     let bucket = bucket.put(hash, key, val);
-                    let end_index = bucket.index();
                     // Now that it's stolen, just read the value's pointer
                     // right out of the table! Go back to the *starting point*.
                     //
@@ -527,7 +517,7 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
                     // bucket, which is a FullBucket on top of a
                     // FullBucketMut, into just one FullBucketMut. The "table"
                     // refers to the inner FullBucketMut in this context.
-                    return (end_index - start_index, bucket.into_table().into_mut_refs().1);
+                    return bucket.into_table().into_mut_refs().1;
                 }
                 Full(bucket) => bucket,
             };
@@ -2128,18 +2118,16 @@ pub fn into_key(self) -> K {
     pub fn insert(self, value: V) -> &'a mut V {
         match self.elem {
             NeqElem(bucket, disp) => {
-                let (shift, v_ref) = robin_hood(bucket, disp, self.hash, self.key, value);
-                if disp >= DISPLACEMENT_THRESHOLD || shift >= FORWARD_SHIFT_THRESHOLD {
+                if disp >= DISPLACEMENT_THRESHOLD {
                     *self.long_probes = true;
                 }
-                v_ref
+                robin_hood(bucket, disp, self.hash, self.key, value)
             },
             NoElem(bucket, disp) => {
                 if disp >= DISPLACEMENT_THRESHOLD {
                     *self.long_probes = true;
                 }
-                let bucket = bucket.put(self.hash, self.key, value);
-                bucket.into_mut_refs().1
+                bucket.put(self.hash, self.key, value).into_mut_refs().1
             },
         }
     }
index dc3855367ae271604b1d13935ca5cab8dc092b55..bc678fcb8385b0a9a640afdc285fe8de2eebf8e3 100644 (file)
@@ -455,6 +455,20 @@ fn from(_: NulError) -> io::Error {
     }
 }
 
+#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
+impl Error for FromBytesWithNulError {
+    fn description(&self) -> &str {
+        "data provided is not null terminated or contains an interior nul byte"
+    }
+}
+
+#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
+impl fmt::Display for FromBytesWithNulError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.description().fmt(f)
+    }
+}
+
 impl IntoStringError {
     /// Consumes this error, returning original `CString` which generated the
     /// error.
index ac0d0d2afb80328042a8a3109c7cffa366e520b5..f99634ecac23f4261405be0dc3d101cb8f8386a5 100644 (file)
@@ -198,7 +198,7 @@ impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {}
 #[stable(feature = "catch_unwind", since = "1.9.0")]
 impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {}
 #[unstable(feature = "unique", issue = "27730")]
-impl<T: UnwindSafe> UnwindSafe for Unique<T> {}
+impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {}
 #[unstable(feature = "shared", issue = "27730")]
 impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Shared<T> {}
 #[stable(feature = "catch_unwind", since = "1.9.0")]
index 3fba49345e63d1e5ee34cf8f63cc483f44492353..3b5a1cffc7a2203dd7b7c8b9a52c720652396166 100644 (file)
@@ -320,7 +320,11 @@ fn default_hook(info: &PanicInfo) {
     let log_backtrace = {
         let panics = update_panic_count(0);
 
-        panics >= 2 || backtrace::log_enabled()
+        if panics >= 2 {
+            Some(backtrace::PrintFormat::Full)
+        } else {
+            backtrace::log_enabled()
+        }
     };
 
     let file = info.location.file;
@@ -347,8 +351,8 @@ fn default_hook(info: &PanicInfo) {
 
             static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
 
-            if log_backtrace {
-                let _ = backtrace::write(err);
+            if let Some(format) = log_backtrace {
+                let _ = backtrace::print(err, format);
             } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
                 let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` for a backtrace.");
             }
index 4ff35738b50fbd085657154c517563fbab6e991c..f846ef3e69e093f24f0cb88422f62575c7bd327e 100644 (file)
 //!
 //! assert!(ecode.success());
 //! ```
+//!
+//! Calling a command with input and reading its output:
+//!
+//! ```no_run
+//! use std::process::{Command, Stdio};
+//! use std::io::Write;
+//!
+//! let mut child = Command::new("/bin/cat")
+//!     .stdin(Stdio::piped())
+//!     .stdout(Stdio::piped())
+//!     .spawn()
+//!     .expect("failed to execute child");
+//!
+//! {
+//!     // limited borrow of stdin
+//!     let stdin = child.stdin.as_mut().expect("failed to get stdin");
+//!     stdin.write_all(b"test").expect("failed to write to stdin");
+//! }
+//!
+//! let output = child
+//!     .wait_with_output()
+//!     .expect("failed to wait on child");
+//!
+//! assert_eq!(b"test", output.stdout.as_slice());
+//! ```
 
 #![stable(feature = "process", since = "1.0.0")]
 
index fc4fd4ce92b1b6fbe6f37e8fc3d998e90d68b8e4..f15e7ff891684ceee5c212d101666874614de53a 100644 (file)
@@ -14,6 +14,8 @@
 /// A barrier enables multiple threads to synchronize the beginning
 /// of some computation.
 ///
+/// # Examples
+///
 /// ```
 /// use std::sync::{Arc, Barrier};
 /// use std::thread;
@@ -50,8 +52,19 @@ struct BarrierState {
 
 /// A result returned from wait.
 ///
-/// Currently this opaque structure only has one method, `.is_leader()`. Only
+/// Currently this opaque structure only has one method, [`.is_leader()`]. Only
 /// one thread will receive a result that will return `true` from this function.
+///
+/// [`.is_leader()`]: #method.is_leader
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::Barrier;
+///
+/// let barrier = Barrier::new(1);
+/// let barrier_wait_result = barrier.wait();
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BarrierWaitResult(bool);
 
@@ -65,8 +78,18 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl Barrier {
     /// Creates a new barrier that can block a given number of threads.
     ///
-    /// A barrier will block `n`-1 threads which call `wait` and then wake up
-    /// all threads at once when the `n`th thread calls `wait`.
+    /// A barrier will block `n`-1 threads which call [`wait`] and then wake up
+    /// all threads at once when the `n`th thread calls [`wait`].
+    ///
+    /// [`wait`]: #method.wait
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::Barrier;
+    ///
+    /// let barrier = Barrier::new(10);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new(n: usize) -> Barrier {
         Barrier {
@@ -84,10 +107,37 @@ pub fn new(n: usize) -> Barrier {
     /// Barriers are re-usable after all threads have rendezvoused once, and can
     /// be used continuously.
     ///
-    /// A single (arbitrary) thread will receive a `BarrierWaitResult` that
-    /// returns `true` from `is_leader` when returning from this function, and
+    /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that
+    /// returns `true` from [`is_leader`] when returning from this function, and
     /// all other threads will receive a result that will return `false` from
-    /// `is_leader`
+    /// [`is_leader`].
+    ///
+    /// [`BarrierWaitResult`]: struct.BarrierWaitResult.html
+    /// [`is_leader`]: struct.BarrierWaitResult.html#method.is_leader
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Barrier};
+    /// use std::thread;
+    ///
+    /// let mut handles = Vec::with_capacity(10);
+    /// let barrier = Arc::new(Barrier::new(10));
+    /// for _ in 0..10 {
+    ///     let c = barrier.clone();
+    ///     // The same messages will be printed together.
+    ///     // You will NOT see any interleaving.
+    ///     handles.push(thread::spawn(move|| {
+    ///         println!("before wait");
+    ///         c.wait();
+    ///         println!("after wait");
+    ///     }));
+    /// }
+    /// // Wait for other threads to finish.
+    /// for handle in handles {
+    ///     handle.join().unwrap();
+    /// }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn wait(&self) -> BarrierWaitResult {
         let mut lock = self.lock.lock().unwrap();
@@ -120,10 +170,22 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 }
 
 impl BarrierWaitResult {
-    /// Returns whether this thread from `wait` is the "leader thread".
+    /// Returns whether this thread from [`wait`] is the "leader thread".
     ///
     /// Only one thread will have `true` returned from their result, all other
     /// threads will have `false` returned.
+    ///
+    /// [`wait`]: struct.Barrier.html#method.wait
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::Barrier;
+    ///
+    /// let barrier = Barrier::new(1);
+    /// let barrier_wait_result = barrier.wait();
+    /// println!("{:?}", barrier_wait_result.is_leader());
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_leader(&self) -> bool { self.0 }
 }
index 7ee1c98565cfd5525fd3afba2cdfba2e4743ac69..68c7e88f67fc56218f5f8fd557fc2a088ce1fe46 100644 (file)
 
 /// A type indicating whether a timed wait on a condition variable returned
 /// due to a time out or not.
+///
+/// It is returned by the [`wait_timeout`] method.
+///
+/// [`wait_timeout`]: struct.Condvar.html#method.wait_timeout
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
 #[stable(feature = "wait_timeout", since = "1.5.0")]
 pub struct WaitTimeoutResult(bool);
 
 impl WaitTimeoutResult {
     /// Returns whether the wait was known to have timed out.
+    ///
+    /// # Examples
+    ///
+    /// This example spawns a thread which will update the boolean value and
+    /// then wait 100 milliseconds before notifying the condvar.
+    ///
+    /// The main thread will wait with a timeout on the condvar and then leave
+    /// once the boolean has been updated and notified.
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex, Condvar};
+    /// use std::thread;
+    /// use std::time::Duration;
+    ///
+    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    /// let pair2 = pair.clone();
+    ///
+    /// thread::spawn(move|| {
+    ///     let &(ref lock, ref cvar) = &*pair2;
+    ///     let mut started = lock.lock().unwrap();
+    ///     // We update the boolean value.
+    ///     *started = true;
+    ///     // Let's wait 20 milliseconds before notifying the condvar.
+    ///     thread::sleep(Duration::from_millis(20));
+    ///     cvar.notify_one();
+    /// });
+    ///
+    /// // Wait for the thread to start up.
+    /// let &(ref lock, ref cvar) = &*pair;
+    /// let mut started = lock.lock().unwrap();
+    /// loop {
+    ///     // Let's put a timeout on the condvar's wait.
+    ///     let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
+    ///     // 10 milliseconds have passed, or maybe the value changed!
+    ///     started = result.0;
+    ///     if *started == true {
+    ///         // We received the notification and the value has been updated, we can leave.
+    ///         break
+    ///     }
+    /// }
+    /// ```
     #[stable(feature = "wait_timeout", since = "1.5.0")]
     pub fn timed_out(&self) -> bool {
         self.0
@@ -55,15 +100,16 @@ pub fn timed_out(&self) -> bool {
 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
 /// let pair2 = pair.clone();
 ///
-/// // Inside of our lock, spawn a new thread, and then wait for it to start
+/// // Inside of our lock, spawn a new thread, and then wait for it to start.
 /// thread::spawn(move|| {
 ///     let &(ref lock, ref cvar) = &*pair2;
 ///     let mut started = lock.lock().unwrap();
 ///     *started = true;
+///     // We notify the condvar that the value has changed.
 ///     cvar.notify_one();
 /// });
 ///
-/// // wait for the thread to start up
+/// // Wait for the thread to start up.
 /// let &(ref lock, ref cvar) = &*pair;
 /// let mut started = lock.lock().unwrap();
 /// while !*started {
@@ -79,6 +125,14 @@ pub struct Condvar {
 impl Condvar {
     /// Creates a new condition variable which is ready to be waited on and
     /// notified.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::Condvar;
+    ///
+    /// let condvar = Condvar::new();
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new() -> Condvar {
         let mut c = Condvar {
@@ -95,10 +149,10 @@ pub fn new() -> Condvar {
     /// notification.
     ///
     /// This function will atomically unlock the mutex specified (represented by
-    /// `mutex_guard`) and block the current thread. This means that any calls
-    /// to `notify_*()` which happen logically after the mutex is unlocked are
-    /// candidates to wake this thread up. When this function call returns, the
-    /// lock specified will have been re-acquired.
+    /// `guard`) and block the current thread. This means that any calls
+    /// to [`notify_one()`] or [`notify_all()`] which happen logically after the
+    /// mutex is unlocked are candidates to wake this thread up. When this
+    /// function call returns, the lock specified will have been re-acquired.
     ///
     /// Note that this function is susceptible to spurious wakeups. Condition
     /// variables normally have a boolean predicate associated with them, and
@@ -109,14 +163,46 @@ pub fn new() -> Condvar {
     ///
     /// This function will return an error if the mutex being waited on is
     /// poisoned when this thread re-acquires the lock. For more information,
-    /// see information about poisoning on the Mutex type.
+    /// see information about [poisoning] on the [`Mutex`] type.
     ///
     /// # Panics
     ///
-    /// This function will `panic!()` if it is used with more than one mutex
+    /// This function will [`panic!()`] if it is used with more than one mutex
     /// over time. Each condition variable is dynamically bound to exactly one
     /// mutex to ensure defined behavior across platforms. If this functionality
     /// is not desired, then unsafe primitives in `sys` are provided.
+    ///
+    /// [`notify_one()`]: #method.notify_one
+    /// [`notify_all()`]: #method.notify_all
+    /// [poisoning]: ../sync/struct.Mutex.html#poisoning
+    /// [`Mutex`]: ../sync/struct.Mutex.html
+    /// [`panic!()`]: ../../std/macro.panic.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex, Condvar};
+    /// use std::thread;
+    ///
+    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    /// let pair2 = pair.clone();
+    ///
+    /// thread::spawn(move|| {
+    ///     let &(ref lock, ref cvar) = &*pair2;
+    ///     let mut started = lock.lock().unwrap();
+    ///     *started = true;
+    ///     // We notify the condvar that the value has changed.
+    ///     cvar.notify_one();
+    /// });
+    ///
+    /// // Wait for the thread to start up.
+    /// let &(ref lock, ref cvar) = &*pair;
+    /// let mut started = lock.lock().unwrap();
+    /// // As long as the value inside the `Mutex` is false, we wait.
+    /// while !*started {
+    ///     started = cvar.wait(started).unwrap();
+    /// }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>)
                        -> LockResult<MutexGuard<'a, T>> {
@@ -136,7 +222,7 @@ pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>)
     /// Waits on this condition variable for a notification, timing out after a
     /// specified duration.
     ///
-    /// The semantics of this function are equivalent to `wait()`
+    /// The semantics of this function are equivalent to [`wait`]
     /// except that the thread will be blocked for roughly no longer
     /// than `ms` milliseconds. This method should not be used for
     /// precise timing due to anomalies such as preemption or platform
@@ -150,8 +236,42 @@ pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>)
     /// The returned boolean is `false` only if the timeout is known
     /// to have elapsed.
     ///
-    /// Like `wait`, the lock specified will be re-acquired when this function
+    /// Like [`wait`], the lock specified will be re-acquired when this function
     /// returns, regardless of whether the timeout elapsed or not.
+    ///
+    /// [`wait`]: #method.wait
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex, Condvar};
+    /// use std::thread;
+    ///
+    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    /// let pair2 = pair.clone();
+    ///
+    /// thread::spawn(move|| {
+    ///     let &(ref lock, ref cvar) = &*pair2;
+    ///     let mut started = lock.lock().unwrap();
+    ///     *started = true;
+    ///     // We notify the condvar that the value has changed.
+    ///     cvar.notify_one();
+    /// });
+    ///
+    /// // Wait for the thread to start up.
+    /// let &(ref lock, ref cvar) = &*pair;
+    /// let mut started = lock.lock().unwrap();
+    /// // As long as the value inside the `Mutex` is false, we wait.
+    /// loop {
+    ///     let result = cvar.wait_timeout_ms(started, 10).unwrap();
+    ///     // 10 milliseconds have passed, or maybe the value changed!
+    ///     started = result.0;
+    ///     if *started == true {
+    ///         // We received the notification and the value has been updated, we can leave.
+    ///         break
+    ///     }
+    /// }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::sync::Condvar::wait_timeout`")]
     pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32)
@@ -165,7 +285,7 @@ pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32)
     /// Waits on this condition variable for a notification, timing out after a
     /// specified duration.
     ///
-    /// The semantics of this function are equivalent to `wait()` except that
+    /// The semantics of this function are equivalent to [`wait`] except that
     /// the thread will be blocked for roughly no longer than `dur`. This
     /// method should not be used for precise timing due to anomalies such as
     /// preemption or platform differences that may not cause the maximum
@@ -175,11 +295,47 @@ pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32)
     /// 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
+    /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
     /// known to have elapsed.
     ///
-    /// Like `wait`, the lock specified will be re-acquired when this function
+    /// Like [`wait`], the lock specified will be re-acquired when this function
     /// returns, regardless of whether the timeout elapsed or not.
+    ///
+    /// [`wait`]: #method.wait
+    /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex, Condvar};
+    /// use std::thread;
+    /// use std::time::Duration;
+    ///
+    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    /// let pair2 = pair.clone();
+    ///
+    /// thread::spawn(move|| {
+    ///     let &(ref lock, ref cvar) = &*pair2;
+    ///     let mut started = lock.lock().unwrap();
+    ///     *started = true;
+    ///     // We notify the condvar that the value has changed.
+    ///     cvar.notify_one();
+    /// });
+    ///
+    /// // wait for the thread to start up
+    /// let &(ref lock, ref cvar) = &*pair;
+    /// let mut started = lock.lock().unwrap();
+    /// // as long as the value inside the `Mutex` is false, we wait
+    /// loop {
+    ///     let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
+    ///     // 10 milliseconds have passed, or maybe the value changed!
+    ///     started = result.0;
+    ///     if *started == true {
+    ///         // We received the notification and the value has been updated, we can leave.
+    ///         break
+    ///     }
+    /// }
+    /// ```
     #[stable(feature = "wait_timeout", since = "1.5.0")]
     pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
                                dur: Duration)
@@ -200,10 +356,40 @@ pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
     /// Wakes up one blocked thread on this condvar.
     ///
     /// If there is a blocked thread on this condition variable, then it will
-    /// be woken up from its call to `wait` or `wait_timeout`. Calls to
+    /// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to
     /// `notify_one` are not buffered in any way.
     ///
-    /// To wake up all threads, see `notify_all()`.
+    /// To wake up all threads, see [`notify_all()`].
+    ///
+    /// [`wait`]: #method.wait
+    /// [`wait_timeout`]: #method.wait_timeout
+    /// [`notify_all()`]: #method.notify_all
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex, Condvar};
+    /// use std::thread;
+    ///
+    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    /// let pair2 = pair.clone();
+    ///
+    /// thread::spawn(move|| {
+    ///     let &(ref lock, ref cvar) = &*pair2;
+    ///     let mut started = lock.lock().unwrap();
+    ///     *started = true;
+    ///     // We notify the condvar that the value has changed.
+    ///     cvar.notify_one();
+    /// });
+    ///
+    /// // Wait for the thread to start up.
+    /// let &(ref lock, ref cvar) = &*pair;
+    /// let mut started = lock.lock().unwrap();
+    /// // As long as the value inside the `Mutex` is false, we wait.
+    /// while !*started {
+    ///     started = cvar.wait(started).unwrap();
+    /// }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn notify_one(&self) {
         unsafe { self.inner.notify_one() }
@@ -215,7 +401,35 @@ pub fn notify_one(&self) {
     /// variable are awoken. Calls to `notify_all()` are not buffered in any
     /// way.
     ///
-    /// To wake up only one thread, see `notify_one()`.
+    /// To wake up only one thread, see [`notify_one()`].
+    ///
+    /// [`notify_one()`]: #method.notify_one
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex, Condvar};
+    /// use std::thread;
+    ///
+    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    /// let pair2 = pair.clone();
+    ///
+    /// thread::spawn(move|| {
+    ///     let &(ref lock, ref cvar) = &*pair2;
+    ///     let mut started = lock.lock().unwrap();
+    ///     *started = true;
+    ///     // We notify the condvar that the value has changed.
+    ///     cvar.notify_all();
+    /// });
+    ///
+    /// // Wait for the thread to start up.
+    /// let &(ref lock, ref cvar) = &*pair;
+    /// let mut started = lock.lock().unwrap();
+    /// // As long as the value inside the `Mutex` is false, we wait.
+    /// while !*started {
+    ///     started = cvar.wait(started).unwrap();
+    /// }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn notify_all(&self) {
         unsafe { self.inner.notify_all() }
index 0d6ad5e38e98b0bcdec7b57e691a3675359e546f..97b84d59218ac290de902b451f7ccfbfb9ffea58 100644 (file)
@@ -133,11 +133,13 @@ unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { }
 /// dropped (falls out of scope), the lock will be unlocked.
 ///
 /// The data protected by the mutex can be access through this guard via its
-/// `Deref` and `DerefMut` implementations.
+/// [`Deref`] and [`DerefMut`] implementations.
 ///
 /// This structure is created by the [`lock()`] and [`try_lock()`] methods on
 /// [`Mutex`].
 ///
+/// [`Deref`]: ../../std/ops/trait.Deref.html
+/// [`DerefMut`]: ../../std/ops/trait.DerefMut.html
 /// [`lock()`]: struct.Mutex.html#method.lock
 /// [`try_lock()`]: struct.Mutex.html#method.try_lock
 /// [`Mutex`]: struct.Mutex.html
index 6f53841502ad23dc451283e4f16b0bda6b75feee..961148fb6b4a8f11544f494b181f6ae4df33b6cd 100644 (file)
 
 use libc;
 use io;
-use sys_common::backtrace::output;
+use sys_common::backtrace::Frame;
+
+pub use sys_common::gnu::libbacktrace::*;
+pub struct BacktraceContext;
 
 #[inline(never)]
-pub fn write(w: &mut io::Write) -> io::Result<()> {
-    output(w, 0, 0 as *mut libc::c_void, None)
+pub fn unwind_backtrace(frames: &mut [Frame])
+    -> io::Result<(usize, BacktraceContext)>
+{
+    Ok((0, BacktraceContext))
 }
index 5982bdd6549ca46a131810c60a4305851bc9a493..31c40ea58b1de103a979647e24b66034798c1858 100644 (file)
@@ -13,7 +13,7 @@
 use io::{self, ErrorKind};
 
 pub mod args;
-#[cfg(any(not(cargobuild), feature = "backtrace"))]
+#[cfg(feature = "backtrace")]
 pub mod backtrace;
 pub mod condvar;
 pub mod env;
index a3f202ccd97cbc492c2692c0692bb8e8448f7197..936097d7fb2a602264f32294bd343170bf67326a 100644 (file)
@@ -63,6 +63,10 @@ pub fn socket_addr(&self) -> Result<SocketAddr> {
         Ok(path_to_local_addr(path.to_str().unwrap_or("")))
     }
 
+    pub fn peek(&self, _buf: &mut [u8]) -> Result<usize> {
+        Err(Error::new(ErrorKind::Other, "TcpStream::peek not implemented"))
+    }
+
     pub fn shutdown(&self, _how: Shutdown) -> Result<()> {
         Err(Error::new(ErrorKind::Other, "TcpStream::shutdown not implemented"))
     }
index 36f0819d308849cb8c087919fe0f4b8ee4fa46d4..93ebcc95fd0f87e0c70fa6584678ec2cab778a8a 100644 (file)
@@ -87,6 +87,14 @@ pub fn socket_addr(&self) -> Result<SocketAddr> {
         Ok(path_to_local_addr(path.to_str().unwrap_or("")))
     }
 
+    pub fn peek(&self, _buf: &mut [u8]) -> Result<usize> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::peek not implemented"))
+    }
+
+    pub fn peek_from(&self, _buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
+        Err(Error::new(ErrorKind::Other, "UdpSocket::peek_from not implemented"))
+    }
+
     pub fn broadcast(&self) -> Result<bool> {
         Err(Error::new(ErrorKind::Other, "UdpSocket::broadcast not implemented"))
     }
index 1eef89bf66f74af2eac1eedd7dc06e9db508a023..29d4012dcdf9890150e8e9f50d09f117b2ddffeb 100644 (file)
@@ -83,7 +83,8 @@
 /// to symbols. This is a bit of a hokey implementation as-is, but it works for
 /// all unix platforms we support right now, so it at least gets the job done.
 
-pub use self::tracing::write;
+pub use self::tracing::unwind_backtrace;
+pub use self::printing::{foreach_symbol_fileline, resolve_symname};
 
 // tracing impls:
 mod tracing;
@@ -100,3 +101,5 @@ pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
         Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
     }
 }
+
+pub struct BacktraceContext;
index d9b759dc673948351b0e7b33b64d158879979b9e..05a071a79783841072bd20c7bf505e5197cf8b1b 100644 (file)
@@ -9,33 +9,45 @@
 // except according to those terms.
 
 use io;
-use io::prelude::*;
+use intrinsics;
+use ffi::CStr;
 use libc;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
 
-pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void,
-             _symaddr: *mut libc::c_void) -> io::Result<()> {
-    use sys_common::backtrace::{output};
-    use intrinsics;
-    use ffi::CStr;
-
-    #[repr(C)]
-    struct Dl_info {
-        dli_fname: *const libc::c_char,
-        dli_fbase: *mut libc::c_void,
-        dli_sname: *const libc::c_char,
-        dli_saddr: *mut libc::c_void,
-    }
-    extern {
-        fn dladdr(addr: *const libc::c_void,
-                  info: *mut Dl_info) -> libc::c_int;
+pub fn resolve_symname<F>(frame: Frame,
+                          callback: F,
+                          _: &BacktraceContext) -> io::Result<()>
+    where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+    unsafe {
+        let mut info: Dl_info = intrinsics::init();
+        let symname = if dladdr(frame.exact_position, &mut info) == 0 {
+            None
+        } else {
+            CStr::from_ptr(info.dli_sname).to_str().ok()
+        };
+        callback(symname)
     }
+}
 
-    let mut info: Dl_info = unsafe { intrinsics::init() };
-    if unsafe { dladdr(addr, &mut info) == 0 } {
-        output(w, idx,addr, None)
-    } else {
-        output(w, idx, addr, Some(unsafe {
-            CStr::from_ptr(info.dli_sname).to_bytes()
-        }))
-    }
+pub fn foreach_symbol_fileline<F>(_symbol_addr: Frame,
+                                  _f: F,
+                                  _: &BacktraceContext) -> io::Result<bool>
+    where F: FnMut(&[u8], libc::c_int) -> io::Result<()>
+{
+    Ok(false)
+}
+
+#[repr(C)]
+struct Dl_info {
+    dli_fname: *const libc::c_char,
+    dli_fbase: *mut libc::c_void,
+    dli_sname: *const libc::c_char,
+    dli_saddr: *mut libc::c_void,
+}
+
+extern {
+    fn dladdr(addr: *const libc::c_void,
+              info: *mut Dl_info) -> libc::c_int;
 }
diff --git a/src/libstd/sys/unix/backtrace/printing/gnu.rs b/src/libstd/sys/unix/backtrace/printing/gnu.rs
deleted file mode 100644 (file)
index fb06fbe..0000000
+++ /dev/null
@@ -1,11 +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.
-
-pub use sys_common::gnu::libbacktrace::print;
index 02e53854727f7dc25a470cab20742c473fea961a..1ae82e01100169e5cd451f317ce4eb944547e4b7 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub use self::imp::print;
+pub use self::imp::{foreach_symbol_fileline, resolve_symname};
 
 #[cfg(any(target_os = "macos", target_os = "ios",
           target_os = "emscripten"))]
@@ -17,5 +17,6 @@
 
 #[cfg(not(any(target_os = "macos", target_os = "ios",
               target_os = "emscripten")))]
-#[path = "gnu.rs"]
-mod imp;
+mod imp {
+    pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
+}
index ca2e70b5003a12bced9cec8c489be47118a5418e..ecd32aa9462a904d5dea1ca929328892ed3dcebe 100644 (file)
 /// simple to use it should be used only on iOS devices as the only viable
 /// option.
 
-use io::prelude::*;
 use io;
 use libc;
-use mem;
-use sys::mutex::Mutex;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
 
-use super::super::printing::print;
-
-#[inline(never)]
-pub fn write(w: &mut Write) -> io::Result<()> {
-    extern {
-        fn backtrace(buf: *mut *mut libc::c_void,
-                     sz: libc::c_int) -> libc::c_int;
+#[inline(never)] // if we know this is a function call, we can skip it when
+                 // tracing
+pub fn unwind_backtrace(frames: &mut [Frame])
+    -> io::Result<(usize, BacktraceContext)>
+{
+    const FRAME_LEN: usize = 100;
+    assert!(FRAME_LEN >= frames.len());
+    let mut raw_frames = [::ptr::null_mut(); FRAME_LEN];
+    let nb_frames = unsafe {
+        backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int)
+    } as usize;
+    for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) {
+        *to = Frame {
+            exact_position: *from,
+            symbol_addr: *from,
+        };
     }
+    Ok((nb_frames as usize, BacktraceContext))
+}
 
-    // while it doesn't requires lock for work as everything is
-    // local, it still displays much nicer backtraces when a
-    // couple of threads panic simultaneously
-    static LOCK: Mutex = Mutex::new();
-    unsafe {
-        LOCK.lock();
-
-        writeln!(w, "stack backtrace:")?;
-        // 100 lines should be enough
-        const SIZE: usize = 100;
-        let mut buf: [*mut libc::c_void; SIZE] = mem::zeroed();
-        let cnt = backtrace(buf.as_mut_ptr(), SIZE as libc::c_int) as usize;
-
-        // skipping the first one as it is write itself
-        for i in 1..cnt {
-            print(w, i as isize, buf[i], buf[i])?
-        }
-        LOCK.unlock();
-    }
-    Ok(())
+extern {
+    fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int;
 }
index c1b45620ab04a8aa4e69836f9813f754bd42b90c..cfeabaddda9859fea27aa88a3da3da5d40d7d50d 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use error::Error;
 use io;
-use io::prelude::*;
 use libc;
-use mem;
-use sys_common::mutex::Mutex;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
 
-use super::super::printing::print;
 use unwind as uw;
 
-#[inline(never)] // if we know this is a function call, we can skip it when
-                 // tracing
-pub fn write(w: &mut Write) -> io::Result<()> {
-    struct Context<'a> {
-        idx: isize,
-        writer: &'a mut (Write+'a),
-        last_error: Option<io::Error>,
-    }
+struct Context<'a> {
+    idx: usize,
+    frames: &'a mut [Frame],
+}
 
-    // When using libbacktrace, we use some necessary global state, so we
-    // need to prevent more than one thread from entering this block. This
-    // is semi-reasonable in terms of printing anyway, and we know that all
-    // I/O done here is blocking I/O, not green I/O, so we don't have to
-    // worry about this being a native vs green mutex.
-    static LOCK: Mutex = Mutex::new();
-    unsafe {
-        LOCK.lock();
+#[derive(Debug)]
+struct UnwindError(uw::_Unwind_Reason_Code);
 
-        writeln!(w, "stack backtrace:")?;
+impl Error for UnwindError {
+    fn description(&self) -> &'static str {
+        "unexpected return value while unwinding"
+    }
+}
 
-        let mut cx = Context { writer: w, last_error: None, idx: 0 };
-        let ret = match {
-            uw::_Unwind_Backtrace(trace_fn,
-                                  &mut cx as *mut Context as *mut libc::c_void)
-        } {
-            uw::_URC_NO_REASON => {
-                match cx.last_error {
-                    Some(err) => Err(err),
-                    None => Ok(())
-                }
-            }
-            _ => Ok(()),
-        };
-        LOCK.unlock();
-        return ret
+impl ::fmt::Display for UnwindError {
+    fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
+        write!(f, "{}: {:?}", self.description(), self.0)
     }
+}
 
-    extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
-                       arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
-        let cx: &mut Context = unsafe { mem::transmute(arg) };
-        let mut ip_before_insn = 0;
-        let mut ip = unsafe {
-            uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
-        };
-        if !ip.is_null() && ip_before_insn == 0 {
-            // this is a non-signaling frame, so `ip` refers to the address
-            // after the calling instruction. account for that.
-            ip = (ip as usize - 1) as *mut _;
+#[inline(never)] // if we know this is a function call, we can skip it when
+                 // tracing
+pub fn unwind_backtrace(frames: &mut [Frame])
+    -> io::Result<(usize, BacktraceContext)>
+{
+    let mut cx = Context {
+        idx: 0,
+        frames: frames,
+    };
+    let result_unwind = unsafe {
+        uw::_Unwind_Backtrace(trace_fn,
+                              &mut cx as *mut Context
+                              as *mut libc::c_void)
+    };
+    // See libunwind:src/unwind/Backtrace.c for the return values.
+    // No, there is no doc.
+    match result_unwind {
+        // These return codes seem to be benign and need to be ignored for backtraces
+        // to show up properly on all tested platforms.
+        uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
+            Ok((cx.idx, BacktraceContext))
         }
-
-        // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
-        // it appears to work fine without it, so we only use
-        // FindEnclosingFunction on non-osx platforms. In doing so, we get a
-        // slightly more accurate stack trace in the process.
-        //
-        // This is often because panic involves the last instruction of a
-        // function being "call std::rt::begin_unwind", with no ret
-        // instructions after it. This means that the return instruction
-        // pointer points *outside* of the calling function, and by
-        // unwinding it we go back to the original function.
-        let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
-            ip
-        } else {
-            unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
-        };
-
-        // Don't print out the first few frames (they're not user frames)
-        cx.idx += 1;
-        if cx.idx <= 0 { return uw::_URC_NO_REASON }
-        // Don't print ginormous backtraces
-        if cx.idx > 100 {
-            match write!(cx.writer, " ... <frames omitted>\n") {
-                Ok(()) => {}
-                Err(e) => { cx.last_error = Some(e); }
-            }
-            return uw::_URC_FAILURE
+        _ => {
+            Err(io::Error::new(io::ErrorKind::Other,
+                               UnwindError(result_unwind)))
         }
+    }
+}
 
-        // Once we hit an error, stop trying to print more frames
-        if cx.last_error.is_some() { return uw::_URC_FAILURE }
+extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
+                   arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
+    let cx = unsafe { &mut *(arg as *mut Context) };
+    let mut ip_before_insn = 0;
+    let mut ip = unsafe {
+        uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
+    };
+    if !ip.is_null() && ip_before_insn == 0 {
+        // this is a non-signaling frame, so `ip` refers to the address
+        // after the calling instruction. account for that.
+        ip = (ip as usize - 1) as *mut _;
+    }
 
-        match print(cx.writer, cx.idx, ip, symaddr) {
-            Ok(()) => {}
-            Err(e) => { cx.last_error = Some(e); }
-        }
+    // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
+    // it appears to work fine without it, so we only use
+    // FindEnclosingFunction on non-osx platforms. In doing so, we get a
+    // slightly more accurate stack trace in the process.
+    //
+    // This is often because panic involves the last instruction of a
+    // function being "call std::rt::begin_unwind", with no ret
+    // instructions after it. This means that the return instruction
+    // pointer points *outside* of the calling function, and by
+    // unwinding it we go back to the original function.
+    let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
+        ip
+    } else {
+        unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
+    };
 
-        // keep going
-        uw::_URC_NO_REASON
+    if cx.idx < cx.frames.len() {
+        cx.frames[cx.idx] = Frame {
+            symbol_addr: symaddr,
+            exact_position: ip,
+        };
+        cx.idx += 1;
     }
+
+    uw::_URC_NO_REASON
 }
index 8b5c0c04276b164882604cf195bedcd30adab4e0..d0fb96b1ff15dffe98412dd745c32e9821669d2c 100644 (file)
@@ -35,7 +35,8 @@
            ftruncate as ftruncate64, lseek as lseek64, dirent as dirent64, open as open64};
 #[cfg(not(any(target_os = "linux",
               target_os = "emscripten",
-              target_os = "solaris")))]
+              target_os = "solaris",
+              target_os = "fuchsia")))]
 use libc::{readdir_r as readdir64_r};
 
 pub struct File(FileDesc);
@@ -59,10 +60,10 @@ pub struct DirEntry {
     entry: dirent64,
     root: Arc<PathBuf>,
     // We need to store an owned copy of the directory name
-    // on Solaris because a) it uses a zero-length array to
-    // store the name, b) its lifetime between readdir calls
-    // is not guaranteed.
-    #[cfg(target_os = "solaris")]
+    // on Solaris and Fuchsia because a) it uses a zero-length
+    // array to store the name, b) its lifetime between readdir
+    // calls is not guaranteed.
+    #[cfg(any(target_os = "solaris", target_os = "fuchsia"))]
     name: Box<[u8]>
 }
 
@@ -205,14 +206,14 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl Iterator for ReadDir {
     type Item = io::Result<DirEntry>;
 
-    #[cfg(target_os = "solaris")]
+    #[cfg(any(target_os = "solaris", target_os = "fuchsia"))]
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
         unsafe {
             loop {
                 // Although readdir_r(3) would be a correct function to use here because
-                // of the thread safety, on Illumos the readdir(3C) function is safe to use
-                // in threaded applications and it is generally preferred over the
-                // readdir_r(3C) function.
+                // of the thread safety, on Illumos and Fuchsia the readdir(3C) function
+                // is safe to use in threaded applications and it is generally preferred
+                // over the readdir_r(3C) function.
                 super::os::set_errno(0);
                 let entry_ptr = libc::readdir(self.dirp.0);
                 if entry_ptr.is_null() {
@@ -240,7 +241,7 @@ fn next(&mut self) -> Option<io::Result<DirEntry>> {
         }
     }
 
-    #[cfg(not(target_os = "solaris"))]
+    #[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))]
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
         unsafe {
             let mut ret = DirEntry {
@@ -344,14 +345,14 @@ fn name_bytes(&self) -> &[u8] {
     #[cfg(any(target_os = "android",
               target_os = "linux",
               target_os = "emscripten",
-              target_os = "haiku",
-              target_os = "fuchsia"))]
+              target_os = "haiku"))]
     fn name_bytes(&self) -> &[u8] {
         unsafe {
             CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes()
         }
     }
-    #[cfg(target_os = "solaris")]
+    #[cfg(any(target_os = "solaris",
+              target_os = "fuchsia"))]
     fn name_bytes(&self) -> &[u8] {
         &*self.name
     }
index e78928c266792adb7006cab1b1857ac318aab0e8..36928696c4059089bfffcbbca9c4e72a1e989c2a 100644 (file)
@@ -64,7 +64,7 @@ pub fn errno() -> i32 {
 }
 
 /// Sets the platform-specific value of errno
-#[cfg(target_os = "solaris")] // only needed for readdir so far
+#[cfg(any(target_os = "solaris", target_os = "fuchsia"))] // only needed for readdir so far
 pub fn set_errno(e: i32) {
     unsafe {
         *errno_location() = e as c_int
index a81bedcad22ff6034b3b0261ec5bb761a80d9722..07f29784df607eb5ff56e14b3e32c5d26b32c2ba 100644 (file)
@@ -111,7 +111,7 @@ pub struct mx_info_process_t {
     pub fn mx_handle_duplicate(handle: mx_handle_t, rights: mx_rights_t,
                                out: *const mx_handle_t) -> mx_handle_t;
 
-    pub fn mx_handle_wait_one(handle: mx_handle_t, signals: mx_signals_t, timeout: mx_time_t,
+    pub fn mx_object_wait_one(handle: mx_handle_t, signals: mx_signals_t, timeout: mx_time_t,
                               pending: *mut mx_signals_t) -> mx_status_t;
 
     pub fn mx_object_get_info(handle: mx_handle_t, topic: u32, buffer: *mut c_void,
@@ -156,18 +156,18 @@ pub struct launchpad_t {
     pub fn launchpad_create(job: mx_handle_t, name: *const c_char,
                             lp: *mut *mut launchpad_t) -> mx_status_t;
 
-    pub fn launchpad_start(lp: *mut launchpad_t) -> mx_status_t;
+    pub fn launchpad_go(lp: *mut launchpad_t,
+                        proc_handle: *mut mx_handle_t,
+                        err_msg: *mut *const c_char) -> mx_status_t;
 
     pub fn launchpad_destroy(lp: *mut launchpad_t);
 
-    pub fn launchpad_arguments(lp: *mut launchpad_t, argc: c_int,
+    pub fn launchpad_set_args(lp: *mut launchpad_t, argc: c_int,
                                argv: *const *const c_char) -> mx_status_t;
 
-    pub fn launchpad_environ(lp: *mut launchpad_t, envp: *const *const c_char) -> mx_status_t;
+    pub fn launchpad_set_environ(lp: *mut launchpad_t, envp: *const *const c_char) -> mx_status_t;
 
-    pub fn launchpad_clone_mxio_root(lp: *mut launchpad_t) -> mx_status_t;
-
-    pub fn launchpad_clone_mxio_cwd(lp: *mut launchpad_t) -> mx_status_t;
+    pub fn launchpad_clone(lp: *mut launchpad_t, what: u32) -> mx_status_t;
 
     pub fn launchpad_clone_fd(lp: *mut launchpad_t, fd: c_int, target_fd: c_int) -> mx_status_t;
 
@@ -182,6 +182,16 @@ pub fn launchpad_arguments(lp: *mut launchpad_t, argc: c_int,
     pub fn launchpad_vmo_from_file(filename: *const c_char) -> mx_handle_t;
 }
 
+// Launchpad clone constants
+
+pub const LP_CLONE_MXIO_ROOT: u32 = 0x0001;
+pub const LP_CLONE_MXIO_CWD: u32 = 0x0002;
+// LP_CLONE_MXIO_STDIO = 0x0004
+// LP_CLONE_MXIO_ALL = 0x00FF
+// LP_CLONE_ENVIRON = 0x0100
+// LP_CLONE_DEFAULT_JOB = 0x0200
+// LP_CLONE_ALL = 0xFFFF
+
 // Errors
 
 #[allow(unused)] pub const ERR_INTERNAL: mx_status_t = -1;
index 0bb2e0c1a83d4469a534469b83ef8c363a08d901..7d583cb3dfce31f016d65f06d5e55efbecda459a 100644 (file)
@@ -13,7 +13,7 @@
 use mem;
 use ptr;
 
-use sys::process::magenta::{Handle, launchpad_t, mx_handle_t};
+use sys::process::magenta::{Handle, mx_handle_t};
 use sys::process::process_common::*;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -30,9 +30,9 @@ pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
 
         let (ours, theirs) = self.setup_io(default, needs_stdin)?;
 
-        let (launchpad, process_handle) = unsafe { self.do_exec(theirs)? };
+        let process_handle = unsafe { self.do_exec(theirs)? };
 
-        Ok((Process { launchpad: launchpad, handle: Handle::new(process_handle) }, ours))
+        Ok((Process { handle: Handle::new(process_handle) }, ours))
     }
 
     pub fn exec(&mut self, default: Stdio) -> io::Error {
@@ -51,7 +51,7 @@ pub fn exec(&mut self, default: Stdio) -> io::Error {
     }
 
     unsafe fn do_exec(&mut self, stdio: ChildPipes)
-                      -> io::Result<(*mut launchpad_t, mx_handle_t)> {
+                      -> io::Result<mx_handle_t> {
         use sys::process::magenta::*;
 
         let job_handle = mx_job_default();
@@ -75,16 +75,15 @@ impl Drop for LaunchpadDestructor {
         let launchpad_destructor = LaunchpadDestructor(launchpad);
 
         // Set the process argv
-        mx_cvt(launchpad_arguments(launchpad, self.get_argv().len() as i32 - 1,
-                                   self.get_argv().as_ptr()))?;
+        mx_cvt(launchpad_set_args(launchpad, self.get_argv().len() as i32 - 1,
+                                  self.get_argv().as_ptr()))?;
         // Setup the environment vars
-        mx_cvt(launchpad_environ(launchpad, envp))?;
+        mx_cvt(launchpad_set_environ(launchpad, envp))?;
         mx_cvt(launchpad_add_vdso_vmo(launchpad))?;
-        mx_cvt(launchpad_clone_mxio_root(launchpad))?;
         // Load the executable
         mx_cvt(launchpad_elf_load(launchpad, launchpad_vmo_from_file(self.get_argv()[0])))?;
         mx_cvt(launchpad_load_vdso(launchpad, MX_HANDLE_INVALID))?;
-        mx_cvt(launchpad_clone_mxio_cwd(launchpad))?;
+        mx_cvt(launchpad_clone(launchpad, LP_CLONE_MXIO_ROOT | LP_CLONE_MXIO_CWD))?;
 
         // Clone stdin, stdout, and stderr
         if let Some(fd) = stdio.stdin.fd() {
@@ -111,12 +110,15 @@ impl Drop for LaunchpadDestructor {
             callback()?;
         }
 
-        let process_handle = mx_cvt(launchpad_start(launchpad))?;
-
-        // Successfully started the launchpad
+        // `launchpad_go` destroys the launchpad, so we must not
         mem::forget(launchpad_destructor);
 
-        Ok((launchpad, process_handle))
+        let mut process_handle: mx_handle_t = 0;
+        let mut err_msg: *const libc::c_char = ptr::null();
+        mx_cvt(launchpad_go(launchpad, &mut process_handle, &mut err_msg))?;
+        // FIXME: See if we want to do something with that err_msg
+
+        Ok(process_handle)
     }
 }
 
@@ -125,7 +127,6 @@ impl Drop for LaunchpadDestructor {
 ////////////////////////////////////////////////////////////////////////////////
 
 pub struct Process {
-    launchpad: *mut launchpad_t,
     handle: Handle,
 }
 
@@ -151,7 +152,7 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
         let mut avail: mx_size_t = 0;
 
         unsafe {
-            mx_cvt(mx_handle_wait_one(self.handle.raw(), MX_TASK_TERMINATED,
+            mx_cvt(mx_object_wait_one(self.handle.raw(), MX_TASK_TERMINATED,
                                       MX_TIME_INFINITE, ptr::null_mut()))?;
             mx_cvt(mx_object_get_info(self.handle.raw(), MX_INFO_PROCESS,
                                       &mut proc_info as *mut _ as *mut libc::c_void,
@@ -174,7 +175,7 @@ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
         let mut avail: mx_size_t = 0;
 
         unsafe {
-            let status = mx_handle_wait_one(self.handle.raw(), MX_TASK_TERMINATED,
+            let status = mx_object_wait_one(self.handle.raw(), MX_TASK_TERMINATED,
                                             0, ptr::null_mut());
             match status {
                 0 => { }, // Success
@@ -195,10 +196,3 @@ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
         Ok(Some(ExitStatus::new(proc_info.rec.return_code)))
     }
 }
-
-impl Drop for Process {
-    fn drop(&mut self) {
-        use sys::process::magenta::launchpad_destroy;
-        unsafe { launchpad_destroy(self.launchpad); }
-    }
-}
diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs
deleted file mode 100644 (file)
index 94aaf43..0000000
+++ /dev/null
@@ -1,163 +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.
-
-//! As always, windows has something very different than unix, we mainly want
-//! to avoid having to depend too much on libunwind for windows.
-//!
-//! If you google around, you'll find a fair bit of references to built-in
-//! functions to get backtraces on windows. It turns out that most of these are
-//! in an external library called dbghelp. I was unable to find this library
-//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
-//! of it.
-//!
-//! You'll also find that there's a function called CaptureStackBackTrace
-//! mentioned frequently (which is also easy to use), but sadly I didn't have a
-//! copy of that function in my mingw install (maybe it was broken?). Instead,
-//! this takes the route of using StackWalk64 in order to walk the stack.
-
-#![allow(deprecated)] // dynamic_lib
-
-use io::prelude::*;
-
-use io;
-use libc::c_void;
-use mem;
-use ptr;
-use sys::c;
-use sys::dynamic_lib::DynamicLibrary;
-use sys::mutex::Mutex;
-
-macro_rules! sym {
-    ($lib:expr, $e:expr, $t:ident) => (
-        match $lib.symbol($e) {
-            Ok(f) => $crate::mem::transmute::<usize, $t>(f),
-            Err(..) => return Ok(())
-        }
-    )
-}
-
-#[cfg(target_env = "msvc")]
-#[path = "printing/msvc.rs"]
-mod printing;
-
-#[cfg(target_env = "gnu")]
-#[path = "printing/gnu.rs"]
-mod printing;
-
-#[cfg(target_env = "gnu")]
-#[path = "backtrace_gnu.rs"]
-pub mod gnu;
-
-type SymInitializeFn =
-    unsafe extern "system" fn(c::HANDLE, *mut c_void,
-                              c::BOOL) -> c::BOOL;
-type SymCleanupFn =
-    unsafe extern "system" fn(c::HANDLE) -> c::BOOL;
-
-type StackWalk64Fn =
-    unsafe extern "system" fn(c::DWORD, c::HANDLE, c::HANDLE,
-                              *mut c::STACKFRAME64, *mut c::CONTEXT,
-                              *mut c_void, *mut c_void,
-                              *mut c_void, *mut c_void) -> c::BOOL;
-
-#[cfg(target_arch = "x86")]
-pub fn init_frame(frame: &mut c::STACKFRAME64,
-                  ctx: &c::CONTEXT) -> c::DWORD {
-    frame.AddrPC.Offset = ctx.Eip as u64;
-    frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
-    frame.AddrStack.Offset = ctx.Esp as u64;
-    frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
-    frame.AddrFrame.Offset = ctx.Ebp as u64;
-    frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
-    c::IMAGE_FILE_MACHINE_I386
-}
-
-#[cfg(target_arch = "x86_64")]
-pub fn init_frame(frame: &mut c::STACKFRAME64,
-                  ctx: &c::CONTEXT) -> c::DWORD {
-    frame.AddrPC.Offset = ctx.Rip as u64;
-    frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
-    frame.AddrStack.Offset = ctx.Rsp as u64;
-    frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
-    frame.AddrFrame.Offset = ctx.Rbp as u64;
-    frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
-    c::IMAGE_FILE_MACHINE_AMD64
-}
-
-struct Cleanup {
-    handle: c::HANDLE,
-    SymCleanup: SymCleanupFn,
-}
-
-impl Drop for Cleanup {
-    fn drop(&mut self) {
-        unsafe { (self.SymCleanup)(self.handle); }
-    }
-}
-
-pub fn write(w: &mut Write) -> io::Result<()> {
-    // According to windows documentation, all dbghelp functions are
-    // single-threaded.
-    static LOCK: Mutex = Mutex::new();
-    unsafe {
-        LOCK.lock();
-        let res = _write(w);
-        LOCK.unlock();
-        return res
-    }
-}
-
-unsafe fn _write(w: &mut Write) -> io::Result<()> {
-    let dbghelp = match DynamicLibrary::open("dbghelp.dll") {
-        Ok(lib) => lib,
-        Err(..) => return Ok(()),
-    };
-
-    // Fetch the symbols necessary from dbghelp.dll
-    let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn);
-    let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn);
-    let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn);
-
-    // Allocate necessary structures for doing the stack walk
-    let process = c::GetCurrentProcess();
-    let thread = c::GetCurrentThread();
-    let mut context: c::CONTEXT = mem::zeroed();
-    c::RtlCaptureContext(&mut context);
-    let mut frame: c::STACKFRAME64 = mem::zeroed();
-    let image = init_frame(&mut frame, &context);
-
-    // Initialize this process's symbols
-    let ret = SymInitialize(process, ptr::null_mut(), c::TRUE);
-    if ret != c::TRUE { return Ok(()) }
-    let _c = Cleanup { handle: process, SymCleanup: SymCleanup };
-
-    // And now that we're done with all the setup, do the stack walking!
-    // Start from -1 to avoid printing this stack frame, which will
-    // always be exactly the same.
-    let mut i = -1;
-    write!(w, "stack backtrace:\n")?;
-    while StackWalk64(image, process, thread, &mut frame, &mut context,
-                      ptr::null_mut(),
-                      ptr::null_mut(),
-                      ptr::null_mut(),
-                      ptr::null_mut()) == c::TRUE {
-        let addr = frame.AddrPC.Offset;
-        if addr == frame.AddrReturn.Offset || addr == 0 ||
-           frame.AddrReturn.Offset == 0 { break }
-
-        i += 1;
-
-        if i >= 0 {
-            printing::print(w, i, addr - 1, process, &dbghelp)?;
-        }
-    }
-
-    Ok(())
-}
diff --git a/src/libstd/sys/windows/backtrace/backtrace_gnu.rs b/src/libstd/sys/windows/backtrace/backtrace_gnu.rs
new file mode 100644 (file)
index 0000000..f0d29dd
--- /dev/null
@@ -0,0 +1,62 @@
+// 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 io;
+use sys::c;
+use libc::c_char;
+use path::PathBuf;
+use fs::{OpenOptions, File};
+use sys::ext::fs::OpenOptionsExt;
+use sys::handle::Handle;
+use super::super::{fill_utf16_buf, os2path, to_u16s, wide_char_to_multi_byte};
+
+fn query_full_process_image_name() -> io::Result<PathBuf> {
+    unsafe {
+        let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION,
+                                                        c::FALSE,
+                                                        c::GetCurrentProcessId()));
+        fill_utf16_buf(|buf, mut sz| {
+            if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 {
+                0
+            } else {
+                sz
+            }
+        }, os2path)
+    }
+}
+
+fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> {
+    // We query the current image name, open the file without FILE_SHARE_DELETE so it
+    // can't be moved and then get the current image name again. If the names are the
+    // same than we have successfully locked the file
+    let image_name1 = query_full_process_image_name()?;
+    let file = OpenOptions::new()
+                .read(true)
+                .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE)
+                .open(&image_name1)?;
+    let image_name2 = query_full_process_image_name()?;
+
+    if image_name1 != image_name2 {
+        return Err(io::Error::new(io::ErrorKind::Other,
+                                  "executable moved while trying to lock it"));
+    }
+
+    Ok((image_name1, file))
+}
+
+// Get the executable filename for libbacktrace
+// This returns the path in the ANSI code page and a File which should remain open
+// for as long as the path should remain valid
+pub fn get_executable_filename() -> io::Result<(Vec<c_char>, File)> {
+    let (executable, file) = lock_and_get_executable_filename()?;
+    let u16_executable = to_u16s(executable.into_os_string())?;
+    Ok((wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS,
+                                &u16_executable, true)?, file))
+}
diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs
new file mode 100644 (file)
index 0000000..3c3fd8d
--- /dev/null
@@ -0,0 +1,156 @@
+// 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.
+
+//! As always, windows has something very different than unix, we mainly want
+//! to avoid having to depend too much on libunwind for windows.
+//!
+//! If you google around, you'll find a fair bit of references to built-in
+//! functions to get backtraces on windows. It turns out that most of these are
+//! in an external library called dbghelp. I was unable to find this library
+//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
+//! of it.
+//!
+//! You'll also find that there's a function called CaptureStackBackTrace
+//! mentioned frequently (which is also easy to use), but sadly I didn't have a
+//! copy of that function in my mingw install (maybe it was broken?). Instead,
+//! this takes the route of using StackWalk64 in order to walk the stack.
+
+#![allow(deprecated)] // dynamic_lib
+
+use io;
+use libc::c_void;
+use mem;
+use ptr;
+use sys::c;
+use sys::dynamic_lib::DynamicLibrary;
+use sys_common::backtrace::Frame;
+
+macro_rules! sym {
+    ($lib:expr, $e:expr, $t:ident) => (
+        $lib.symbol($e).map(|f| unsafe {
+            $crate::mem::transmute::<usize, $t>(f)
+        })
+    )
+}
+
+mod printing;
+
+#[cfg(target_env = "gnu")]
+#[path = "backtrace_gnu.rs"]
+pub mod gnu;
+
+pub use self::printing::{resolve_symname, foreach_symbol_fileline};
+
+pub fn unwind_backtrace(frames: &mut [Frame])
+    -> io::Result<(usize, BacktraceContext)>
+{
+    let dbghelp = DynamicLibrary::open("dbghelp.dll")?;
+
+    // Fetch the symbols necessary from dbghelp.dll
+    let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
+    let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;
+    let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn)?;
+
+    // Allocate necessary structures for doing the stack walk
+    let process = unsafe { c::GetCurrentProcess() };
+    let thread = unsafe { c::GetCurrentThread() };
+    let mut context: c::CONTEXT = unsafe { mem::zeroed() };
+    unsafe { c::RtlCaptureContext(&mut context) };
+    let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() };
+    let image = init_frame(&mut frame, &context);
+
+    let backtrace_context = BacktraceContext {
+        handle: process,
+        SymCleanup: SymCleanup,
+        dbghelp: dbghelp,
+    };
+
+    // Initialize this process's symbols
+    let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) };
+    if ret != c::TRUE {
+        return Ok((0, backtrace_context))
+    }
+
+    // And now that we're done with all the setup, do the stack walking!
+    // Start from -1 to avoid printing this stack frame, which will
+    // always be exactly the same.
+    let mut i = 0;
+    unsafe {
+        while i < frames.len() &&
+              StackWalk64(image, process, thread, &mut frame, &mut context,
+                          ptr::null_mut(),
+                          ptr::null_mut(),
+                          ptr::null_mut(),
+                          ptr::null_mut()) == c::TRUE
+        {
+            let addr = frame.AddrPC.Offset;
+            if addr == frame.AddrReturn.Offset || addr == 0 ||
+               frame.AddrReturn.Offset == 0 { break }
+
+            frames[i] = Frame {
+                symbol_addr: (addr - 1) as *const c_void,
+                exact_position: (addr - 1) as *const c_void,
+            };
+            i += 1;
+        }
+    }
+
+    Ok((i, backtrace_context))
+}
+
+type SymInitializeFn =
+    unsafe extern "system" fn(c::HANDLE, *mut c_void,
+                              c::BOOL) -> c::BOOL;
+type SymCleanupFn =
+    unsafe extern "system" fn(c::HANDLE) -> c::BOOL;
+
+type StackWalk64Fn =
+    unsafe extern "system" fn(c::DWORD, c::HANDLE, c::HANDLE,
+                              *mut c::STACKFRAME64, *mut c::CONTEXT,
+                              *mut c_void, *mut c_void,
+                              *mut c_void, *mut c_void) -> c::BOOL;
+
+#[cfg(target_arch = "x86")]
+fn init_frame(frame: &mut c::STACKFRAME64,
+              ctx: &c::CONTEXT) -> c::DWORD {
+    frame.AddrPC.Offset = ctx.Eip as u64;
+    frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+    frame.AddrStack.Offset = ctx.Esp as u64;
+    frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+    frame.AddrFrame.Offset = ctx.Ebp as u64;
+    frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+    c::IMAGE_FILE_MACHINE_I386
+}
+
+#[cfg(target_arch = "x86_64")]
+fn init_frame(frame: &mut c::STACKFRAME64,
+              ctx: &c::CONTEXT) -> c::DWORD {
+    frame.AddrPC.Offset = ctx.Rip as u64;
+    frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+    frame.AddrStack.Offset = ctx.Rsp as u64;
+    frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+    frame.AddrFrame.Offset = ctx.Rbp as u64;
+    frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+    c::IMAGE_FILE_MACHINE_AMD64
+}
+
+pub struct BacktraceContext {
+    handle: c::HANDLE,
+    SymCleanup: SymCleanupFn,
+    // Only used in printing for msvc and not gnu
+    #[allow(dead_code)]
+    dbghelp: DynamicLibrary,
+}
+
+impl Drop for BacktraceContext {
+    fn drop(&mut self) {
+        unsafe { (self.SymCleanup)(self.handle); }
+    }
+}
diff --git a/src/libstd/sys/windows/backtrace/printing/mod.rs b/src/libstd/sys/windows/backtrace/printing/mod.rs
new file mode 100644 (file)
index 0000000..3e566f6
--- /dev/null
@@ -0,0 +1,20 @@
+// 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.
+
+#[cfg(target_env = "msvc")]
+#[path = "msvc.rs"]
+mod printing;
+
+#[cfg(target_env = "gnu")]
+mod printing {
+    pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
+}
+
+pub use self::printing::{foreach_symbol_fileline, resolve_symname};
diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs
new file mode 100644 (file)
index 0000000..3107d78
--- /dev/null
@@ -0,0 +1,83 @@
+// 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 ffi::CStr;
+use io;
+use libc::{c_ulong, c_int, c_char};
+use mem;
+use sys::c;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
+
+type SymFromAddrFn =
+    unsafe extern "system" fn(c::HANDLE, u64, *mut u64,
+                              *mut c::SYMBOL_INFO) -> c::BOOL;
+type SymGetLineFromAddr64Fn =
+    unsafe extern "system" fn(c::HANDLE, u64, *mut u32,
+                              *mut c::IMAGEHLP_LINE64) -> c::BOOL;
+
+/// Converts a pointer to symbol to its string value.
+pub fn resolve_symname<F>(frame: Frame,
+                          callback: F,
+                          context: &BacktraceContext) -> io::Result<()>
+    where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+    let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?;
+
+    unsafe {
+        let mut info: c::SYMBOL_INFO = mem::zeroed();
+        info.MaxNameLen = c::MAX_SYM_NAME as c_ulong;
+        // the struct size in C.  the value is different to
+        // `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81)
+        // due to struct alignment.
+        info.SizeOfStruct = 88;
+
+        let mut displacement = 0u64;
+        let ret = SymFromAddr(context.handle,
+                              frame.symbol_addr as u64,
+                              &mut displacement,
+                              &mut info);
+
+        let symname = if ret == c::TRUE {
+            let ptr = info.Name.as_ptr() as *const c_char;
+            CStr::from_ptr(ptr).to_str().ok()
+        } else {
+            None
+        };
+        callback(symname)
+    }
+}
+
+pub fn foreach_symbol_fileline<F>(frame: Frame,
+                                  mut f: F,
+                                  context: &BacktraceContext)
+    -> io::Result<bool>
+    where F: FnMut(&[u8], c_int) -> io::Result<()>
+{
+    let SymGetLineFromAddr64 = sym!(&context.dbghelp,
+                                    "SymGetLineFromAddr64",
+                                    SymGetLineFromAddr64Fn)?;
+
+    unsafe {
+        let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
+        line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
+
+        let mut displacement = 0u32;
+        let ret = SymGetLineFromAddr64(context.handle,
+                                       frame.exact_position as u64,
+                                       &mut displacement,
+                                       &mut line);
+        if ret == c::TRUE {
+            let name = CStr::from_ptr(line.Filename).to_bytes();
+            f(name, line.LineNumber as c_int)?;
+        }
+        Ok(false)
+    }
+}
diff --git a/src/libstd/sys/windows/backtrace_gnu.rs b/src/libstd/sys/windows/backtrace_gnu.rs
deleted file mode 100644 (file)
index f0d29dd..0000000
+++ /dev/null
@@ -1,62 +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 io;
-use sys::c;
-use libc::c_char;
-use path::PathBuf;
-use fs::{OpenOptions, File};
-use sys::ext::fs::OpenOptionsExt;
-use sys::handle::Handle;
-use super::super::{fill_utf16_buf, os2path, to_u16s, wide_char_to_multi_byte};
-
-fn query_full_process_image_name() -> io::Result<PathBuf> {
-    unsafe {
-        let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION,
-                                                        c::FALSE,
-                                                        c::GetCurrentProcessId()));
-        fill_utf16_buf(|buf, mut sz| {
-            if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 {
-                0
-            } else {
-                sz
-            }
-        }, os2path)
-    }
-}
-
-fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> {
-    // We query the current image name, open the file without FILE_SHARE_DELETE so it
-    // can't be moved and then get the current image name again. If the names are the
-    // same than we have successfully locked the file
-    let image_name1 = query_full_process_image_name()?;
-    let file = OpenOptions::new()
-                .read(true)
-                .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE)
-                .open(&image_name1)?;
-    let image_name2 = query_full_process_image_name()?;
-
-    if image_name1 != image_name2 {
-        return Err(io::Error::new(io::ErrorKind::Other,
-                                  "executable moved while trying to lock it"));
-    }
-
-    Ok((image_name1, file))
-}
-
-// Get the executable filename for libbacktrace
-// This returns the path in the ANSI code page and a File which should remain open
-// for as long as the path should remain valid
-pub fn get_executable_filename() -> io::Result<(Vec<c_char>, File)> {
-    let (executable, file) = lock_and_get_executable_filename()?;
-    let u16_executable = to_u16s(executable.into_os_string())?;
-    Ok((wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS,
-                                &u16_executable, true)?, file))
-}
diff --git a/src/libstd/sys/windows/printing/gnu.rs b/src/libstd/sys/windows/printing/gnu.rs
deleted file mode 100644 (file)
index be2d527..0000000
+++ /dev/null
@@ -1,26 +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 io::prelude::*;
-use io;
-use libc::c_void;
-use sys::c;
-use sys::dynamic_lib::DynamicLibrary;
-use sys_common::gnu::libbacktrace;
-
-pub fn print(w: &mut Write,
-             i: isize,
-             addr: u64,
-             _process: c::HANDLE,
-             _dbghelp: &DynamicLibrary)
-              -> io::Result<()> {
-    let addr = addr as usize as *mut c_void;
-    libbacktrace::print(w, i, addr, addr)
-}
diff --git a/src/libstd/sys/windows/printing/msvc.rs b/src/libstd/sys/windows/printing/msvc.rs
deleted file mode 100644 (file)
index 9c29ac4..0000000
+++ /dev/null
@@ -1,73 +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 ffi::CStr;
-use io::prelude::*;
-use io;
-use libc::{c_ulong, c_int, c_char, c_void};
-use mem;
-use sys::c;
-use sys::dynamic_lib::DynamicLibrary;
-use sys_common::backtrace::{output, output_fileline};
-
-type SymFromAddrFn =
-    unsafe extern "system" fn(c::HANDLE, u64, *mut u64,
-                              *mut c::SYMBOL_INFO) -> c::BOOL;
-type SymGetLineFromAddr64Fn =
-    unsafe extern "system" fn(c::HANDLE, u64, *mut u32,
-                              *mut c::IMAGEHLP_LINE64) -> c::BOOL;
-
-pub fn print(w: &mut Write,
-             i: isize,
-             addr: u64,
-             process: c::HANDLE,
-             dbghelp: &DynamicLibrary)
-              -> io::Result<()> {
-    unsafe {
-        let SymFromAddr = sym!(dbghelp, "SymFromAddr", SymFromAddrFn);
-        let SymGetLineFromAddr64 = sym!(dbghelp,
-                                        "SymGetLineFromAddr64",
-                                        SymGetLineFromAddr64Fn);
-
-        let mut info: c::SYMBOL_INFO = mem::zeroed();
-        info.MaxNameLen = c::MAX_SYM_NAME as c_ulong;
-        // the struct size in C.  the value is different to
-        // `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81)
-        // due to struct alignment.
-        info.SizeOfStruct = 88;
-
-        let mut displacement = 0u64;
-        let ret = SymFromAddr(process, addr, &mut displacement, &mut info);
-
-        let name = if ret == c::TRUE {
-            let ptr = info.Name.as_ptr() as *const c_char;
-            Some(CStr::from_ptr(ptr).to_bytes())
-        } else {
-            None
-        };
-
-        output(w, i, addr as usize as *mut c_void, name)?;
-
-        // Now find out the filename and line number
-        let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
-        line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
-
-        let mut displacement = 0u32;
-        let ret = SymGetLineFromAddr64(process, addr, &mut displacement, &mut line);
-        if ret == c::TRUE {
-            output_fileline(w,
-                            CStr::from_ptr(line.Filename).to_bytes(),
-                            line.LineNumber as c_int,
-                            false)
-        } else {
-            Ok(())
-        }
-    }
-}
index a8540fed9286f1aaae8f9843c25ec5f293d301e7..99297b781e4431dc7992d8f943ef4795d8855103 100644 (file)
 
 #![cfg_attr(target_os = "nacl", allow(dead_code))]
 
+/// Common code for printing the backtrace in the same way across the different
+/// supported platforms.
+
 use env;
 use io::prelude::*;
 use io;
 use libc;
 use str;
 use sync::atomic::{self, Ordering};
+use path::Path;
+use sys::mutex::Mutex;
+use ptr;
 
-pub use sys::backtrace::write;
+pub use sys::backtrace::{
+    unwind_backtrace,
+    resolve_symname,
+    foreach_symbol_fileline,
+    BacktraceContext
+};
 
 #[cfg(target_pointer_width = "64")]
 pub const HEX_WIDTH: usize = 18;
 #[cfg(target_pointer_width = "32")]
 pub const HEX_WIDTH: usize = 10;
 
+/// Represents an item in the backtrace list. See `unwind_backtrace` for how
+/// it is created.
+#[derive(Debug, Copy, Clone)]
+pub struct Frame {
+    /// Exact address of the call that failed.
+    pub exact_position: *const libc::c_void,
+    /// Address of the enclosing function.
+    pub symbol_addr: *const libc::c_void,
+}
+
+/// Max number of frames to print.
+const MAX_NB_FRAMES: usize = 100;
+
+/// Prints the current backtrace.
+pub fn print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
+    static LOCK: Mutex = Mutex::new();
+
+    // Use a lock to prevent mixed output in multithreading context.
+    // Some platforms also requires it, like `SymFromAddr` on Windows.
+    unsafe {
+        LOCK.lock();
+        let res = _print(w, format);
+        LOCK.unlock();
+        res
+    }
+}
+
+fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
+    let mut frames = [Frame {
+        exact_position: ptr::null(),
+        symbol_addr: ptr::null(),
+    }; MAX_NB_FRAMES];
+    let (nb_frames, context) = unwind_backtrace(&mut frames)?;
+    let (skipped_before, skipped_after) =
+        filter_frames(&frames[..nb_frames], format, &context);
+    if skipped_before + skipped_after > 0 {
+        writeln!(w, "note: Some details are omitted, \
+                     run with `RUST_BACKTRACE=full` for a verbose backtrace.")?;
+    }
+    writeln!(w, "stack backtrace:")?;
+
+    let filtered_frames = &frames[..nb_frames - skipped_after];
+    for (index, frame) in filtered_frames.iter().skip(skipped_before).enumerate() {
+        resolve_symname(*frame, |symname| {
+            output(w, index, *frame, symname, format)
+        }, &context)?;
+        let has_more_filenames = foreach_symbol_fileline(*frame, |file, line| {
+            output_fileline(w, file, line, format)
+        }, &context)?;
+        if has_more_filenames {
+            w.write_all(b" <... and possibly more>")?;
+        }
+    }
+
+    Ok(())
+}
+
+fn filter_frames(frames: &[Frame],
+                 format: PrintFormat,
+                 context: &BacktraceContext) -> (usize, usize)
+{
+    if format == PrintFormat::Full {
+        return (0, 0);
+    }
+
+    // We want to filter out frames with some prefixes
+    // from both top and bottom of the call stack.
+    static BAD_PREFIXES_TOP: &'static [&'static str] = &[
+        "_ZN3std3sys3imp9backtrace",
+        "ZN3std3sys3imp9backtrace",
+        "std::sys::imp::backtrace",
+        "_ZN3std10sys_common9backtrace",
+        "ZN3std10sys_common9backtrace",
+        "std::sys_common::backtrace",
+        "_ZN3std9panicking",
+        "ZN3std9panicking",
+        "std::panicking",
+        "_ZN4core9panicking",
+        "ZN4core9panicking",
+        "core::panicking",
+        "_ZN4core6result13unwrap_failed",
+        "ZN4core6result13unwrap_failed",
+        "core::result::unwrap_failed",
+        "rust_begin_unwind",
+        "_ZN4drop",
+        "mingw_set_invalid_parameter_handler",
+    ];
+    static BAD_PREFIXES_BOTTOM: &'static [&'static str] = &[
+        "_ZN3std9panicking",
+        "ZN3std9panicking",
+        "std::panicking",
+        "_ZN3std5panic",
+        "ZN3std5panic",
+        "std::panic",
+        "_ZN4core9panicking",
+        "ZN4core9panicking",
+        "core::panicking",
+        "_ZN3std2rt10lang_start",
+        "ZN3std2rt10lang_start",
+        "std::rt::lang_start",
+        "panic_unwind::__rust_maybe_catch_panic",
+        "__rust_maybe_catch_panic",
+        "_rust_maybe_catch_panic",
+        "__libc_start_main",
+        "__rust_try",
+        "_start",
+        "main",
+        "BaseThreadInitThunk",
+        "RtlInitializeExceptionChain",
+        "__scrt_common_main_seh",
+        "_ZN4drop",
+        "mingw_set_invalid_parameter_handler",
+    ];
+
+    let is_good_frame = |frame: Frame, bad_prefixes: &[&str]| {
+        resolve_symname(frame, |symname| {
+            if let Some(mangled_symbol_name) = symname {
+                if !bad_prefixes.iter().any(|s| mangled_symbol_name.starts_with(s)) {
+                    return Ok(())
+                }
+            }
+            Err(io::Error::from(io::ErrorKind::Other))
+        }, context).is_ok()
+    };
+
+    let skipped_before = frames.iter().position(|frame| {
+        is_good_frame(*frame, BAD_PREFIXES_TOP)
+    }).unwrap_or(frames.len());
+    let skipped_after = frames[skipped_before..].iter().rev().position(|frame| {
+        is_good_frame(*frame, BAD_PREFIXES_BOTTOM)
+    }).unwrap_or(frames.len() - skipped_before);
+
+    if skipped_before + skipped_after == frames.len() {
+        // Avoid showing completely empty backtraces
+        return (0, 0);
+    }
+
+    (skipped_before, skipped_after)
+}
+
+/// Controls how the backtrace should be formated.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum PrintFormat {
+    /// Show all the frames with absolute path for files.
+    Full = 2,
+    /// Show only relevant data from the backtrace.
+    Short = 3,
+}
+
 // For now logging is turned off by default, and this function checks to see
 // whether the magical environment variable is present to see if it's turned on.
-pub fn log_enabled() -> bool {
+pub fn log_enabled() -> Option<PrintFormat> {
     static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
     match ENABLED.load(Ordering::SeqCst) {
-        1 => return false,
-        2 => return true,
-        _ => {}
+        0 => {},
+        1 => return None,
+        2 => return Some(PrintFormat::Full),
+        3 => return Some(PrintFormat::Short),
+        _ => unreachable!(),
     }
 
     let val = match env::var_os("RUST_BACKTRACE") {
-        Some(x) => if &x == "0" { 1 } else { 2 },
-        None => 1,
+        Some(x) => if &x == "0" {
+            None
+        } else if &x == "full" {
+            Some(PrintFormat::Full)
+        } else {
+            Some(PrintFormat::Short)
+        },
+        None => None,
     };
-    ENABLED.store(val, Ordering::SeqCst);
-    val == 2
+    ENABLED.store(match val {
+        Some(v) => v as isize,
+        None => 1,
+    }, Ordering::SeqCst);
+    val
 }
 
-// These output functions should now be used everywhere to ensure consistency.
-pub fn output(w: &mut Write, idx: isize, addr: *mut libc::c_void,
-              s: Option<&[u8]>) -> io::Result<()> {
-    write!(w, "  {:2}: {:2$?} - ", idx, addr, HEX_WIDTH)?;
-    match s.and_then(|s| str::from_utf8(s).ok()) {
-        Some(string) => demangle(w, string)?,
-        None => write!(w, "<unknown>")?,
+/// Print the symbol of the backtrace frame.
+///
+/// These output functions should now be used everywhere to ensure consistency.
+/// You may want to also use `output_fileline`.
+fn output(w: &mut Write, idx: usize, frame: Frame,
+              s: Option<&str>, format: PrintFormat) -> io::Result<()> {
+    // Remove the `17: 0x0 - <unknown>` line.
+    if format == PrintFormat::Short && frame.exact_position == ptr::null() {
+        return Ok(());
+    }
+    match format {
+        PrintFormat::Full => write!(w,
+                                    "  {:2}: {:2$?} - ",
+                                    idx,
+                                    frame.exact_position,
+                                    HEX_WIDTH)?,
+        PrintFormat::Short => write!(w, "  {:2}: ", idx)?,
     }
-    w.write_all(&['\n' as u8])
+    match s {
+        Some(string) => demangle(w, string, format)?,
+        None => w.write_all(b"<unknown>")?,
+    }
+    w.write_all(b"\n")
 }
 
+/// Print the filename and line number of the backtrace frame.
+///
+/// See also `output`.
 #[allow(dead_code)]
-pub fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int,
-                       more: bool) -> io::Result<()> {
-    let file = str::from_utf8(file).unwrap_or("<unknown>");
+fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int,
+                       format: PrintFormat) -> io::Result<()> {
     // prior line: "  ##: {:2$} - func"
-    write!(w, "      {:3$}at {}:{}", "", file, line, HEX_WIDTH)?;
-    if more {
-        write!(w, " <... and possibly more>")?;
+    w.write_all(b"")?;
+    match format {
+        PrintFormat::Full => write!(w,
+                                    "           {:1$}",
+                                    "",
+                                    HEX_WIDTH)?,
+        PrintFormat::Short => write!(w, "           ")?,
+    }
+
+    let file = str::from_utf8(file).unwrap_or("<unknown>");
+    let file_path = Path::new(file);
+    let mut already_printed = false;
+    if format == PrintFormat::Short && file_path.is_absolute() {
+        if let Ok(cwd) = env::current_dir() {
+            if let Ok(stripped) = file_path.strip_prefix(&cwd) {
+                if let Some(s) = stripped.to_str() {
+                    write!(w, "  at ./{}:{}", s, line)?;
+                    already_printed = true;
+                }
+            }
+        }
+    }
+    if !already_printed {
+        write!(w, "  at {}:{}", file, line)?;
     }
-    w.write_all(&['\n' as u8])
+
+    w.write_all(b"\n")
 }
 
 
@@ -84,7 +293,7 @@ pub fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int,
 // Note that this demangler isn't quite as fancy as it could be. We have lots
 // of other information in our symbols like hashes, version, type information,
 // etc. Additionally, this doesn't handle glue symbols at all.
-pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> {
+pub fn demangle(writer: &mut Write, s: &str, format: PrintFormat) -> io::Result<()> {
     // First validate the symbol. If it doesn't look like anything we're
     // expecting, we just print it literally. Note that we must handle non-rust
     // symbols because we could have any function in the backtrace.
@@ -123,6 +332,22 @@ pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> {
     if !valid {
         writer.write_all(s.as_bytes())?;
     } else {
+        // remove the `::hfc2edb670e5eda97` part at the end of the symbol.
+        if format == PrintFormat::Short {
+            // The symbol in still mangled.
+            let mut split = inner.rsplitn(2, "17h");
+            match (split.next(), split.next()) {
+                (Some(addr), rest) => {
+                    if addr.len() == 16 &&
+                       addr.chars().all(|c| c.is_digit(16))
+                    {
+                        inner = rest.unwrap_or("");
+                    }
+                }
+                _ => (),
+            }
+        }
+
         let mut first = true;
         while !inner.is_empty() {
             if !first {
@@ -208,7 +433,9 @@ mod tests {
     use sys_common;
     macro_rules! t { ($a:expr, $b:expr) => ({
         let mut m = Vec::new();
-        sys_common::backtrace::demangle(&mut m, $a).unwrap();
+        sys_common::backtrace::demangle(&mut m,
+                                        $a,
+                                        super::PrintFormat::Full).unwrap();
         assert_eq!(String::from_utf8(m).unwrap(), $b);
     }) }
 
index 0bdbeddb112121b0a015925bc83fc866e4dd0b31..1ea5cca44c7e40154f383bce344187a8b703a94e 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use io;
-use io::prelude::*;
 use libc;
-use sys_common::backtrace::{output, output_fileline};
-
-pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void,
-             symaddr: *mut libc::c_void) -> io::Result<()> {
-    use ffi::CStr;
-    use mem;
-    use ptr;
-
-    ////////////////////////////////////////////////////////////////////////
-    // libbacktrace.h API
-    ////////////////////////////////////////////////////////////////////////
-    type backtrace_syminfo_callback =
-        extern "C" fn(data: *mut libc::c_void,
-                      pc: libc::uintptr_t,
-                      symname: *const libc::c_char,
-                      symval: libc::uintptr_t,
-                      symsize: libc::uintptr_t);
-    type backtrace_full_callback =
-        extern "C" fn(data: *mut libc::c_void,
-                      pc: libc::uintptr_t,
-                      filename: *const libc::c_char,
-                      lineno: libc::c_int,
-                      function: *const libc::c_char) -> libc::c_int;
-    type backtrace_error_callback =
-        extern "C" fn(data: *mut libc::c_void,
-                      msg: *const libc::c_char,
-                      errnum: libc::c_int);
-    enum backtrace_state {}
-
-    extern {
-        fn backtrace_create_state(filename: *const libc::c_char,
-                                  threaded: libc::c_int,
-                                  error: backtrace_error_callback,
-                                  data: *mut libc::c_void)
-                                  -> *mut backtrace_state;
-        fn backtrace_syminfo(state: *mut backtrace_state,
-                             addr: libc::uintptr_t,
-                             cb: backtrace_syminfo_callback,
-                             error: backtrace_error_callback,
-                             data: *mut libc::c_void) -> libc::c_int;
-        fn backtrace_pcinfo(state: *mut backtrace_state,
-                            addr: libc::uintptr_t,
-                            cb: backtrace_full_callback,
-                            error: backtrace_error_callback,
-                            data: *mut libc::c_void) -> libc::c_int;
-    }
-
-    ////////////////////////////////////////////////////////////////////////
-    // helper callbacks
-    ////////////////////////////////////////////////////////////////////////
-
-    type FileLine = (*const libc::c_char, libc::c_int);
-
-    extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
-                       _errnum: libc::c_int) {
-        // do nothing for now
-    }
-    extern fn syminfo_cb(data: *mut libc::c_void,
-                         _pc: libc::uintptr_t,
-                         symname: *const libc::c_char,
-                         _symval: libc::uintptr_t,
-                         _symsize: libc::uintptr_t) {
-        let slot = data as *mut *const libc::c_char;
-        unsafe { *slot = symname; }
-    }
-    extern fn pcinfo_cb(data: *mut libc::c_void,
-                        _pc: libc::uintptr_t,
-                        filename: *const libc::c_char,
-                        lineno: libc::c_int,
-                        _function: *const libc::c_char) -> libc::c_int {
-        if !filename.is_null() {
-            let slot = data as *mut &mut [FileLine];
-            let buffer = unsafe {ptr::read(slot)};
-
-            // if the buffer is not full, add file:line to the buffer
-            // and adjust the buffer for next possible calls to pcinfo_cb.
-            if !buffer.is_empty() {
-                buffer[0] = (filename, lineno);
-                unsafe { ptr::write(slot, &mut buffer[1..]); }
-            }
-        }
-
-        0
-    }
-
-    // The libbacktrace API supports creating a state, but it does not
-    // support destroying a state. I personally take this to mean that a
-    // state is meant to be created and then live forever.
-    //
-    // I would love to register an at_exit() handler which cleans up this
-    // state, but libbacktrace provides no way to do so.
-    //
-    // With these constraints, this function has a statically cached state
-    // that is calculated the first time this is requested. Remember that
-    // backtracing all happens serially (one global lock).
-    //
-    // Things don't work so well on not-Linux since libbacktrace can't track
-    // down that executable this is. We at one point used env::current_exe but
-    // it turns out that there are some serious security issues with that
-    // approach.
-    //
-    // Specifically, on certain platforms like BSDs, a malicious actor can cause
-    // an arbitrary file to be placed at the path returned by current_exe.
-    // libbacktrace does not behave defensively in the presence of ill-formed
-    // DWARF information, and has been demonstrated to segfault in at least one
-    // case. There is no evidence at the moment to suggest that a more carefully
-    // constructed file can't cause arbitrary code execution. As a result of all
-    // of this, we don't hint libbacktrace with the path to the current process.
-    unsafe fn init_state() -> *mut backtrace_state {
-        static mut STATE: *mut backtrace_state = ptr::null_mut();
-        if !STATE.is_null() { return STATE }
-
-        let filename = match ::sys::backtrace::gnu::get_executable_filename() {
-            Ok((filename, file)) => {
-                // filename is purposely leaked here since libbacktrace requires
-                // it to stay allocated permanently, file is also leaked so that
-                // the file stays locked
-                let filename_ptr = filename.as_ptr();
-                mem::forget(filename);
-                mem::forget(file);
-                filename_ptr
-            },
-            Err(_) => ptr::null(),
-        };
-
-        STATE = backtrace_create_state(filename, 0, error_cb,
-                                       ptr::null_mut());
-        STATE
-    }
-
-    ////////////////////////////////////////////////////////////////////////
-    // translation
-    ////////////////////////////////////////////////////////////////////////
-
-    // backtrace errors are currently swept under the rug, only I/O
-    // errors are reported
-    let state = unsafe { init_state() };
-    if state.is_null() {
-        return output(w, idx, addr, None)
-    }
-    let mut data = ptr::null();
-    let data_addr = &mut data as *mut *const libc::c_char;
-    let ret = unsafe {
-        backtrace_syminfo(state, symaddr as libc::uintptr_t,
-                          syminfo_cb, error_cb,
-                          data_addr as *mut libc::c_void)
-    };
-    if ret == 0 || data.is_null() {
-        output(w, idx, addr, None)?;
-    } else {
-        output(w, idx, addr, Some(unsafe { CStr::from_ptr(data).to_bytes() }))?;
-    }
 
+use ffi::CStr;
+use io;
+use mem;
+use ptr;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
+
+pub fn foreach_symbol_fileline<F>(frame: Frame,
+                                  mut f: F,
+                                  _: &BacktraceContext) -> io::Result<bool>
+where F: FnMut(&[u8], libc::c_int) -> io::Result<()>
+{
     // pcinfo may return an arbitrary number of file:line pairs,
     // in the order of stack trace (i.e. inlined calls first).
     // in order to avoid allocation, we stack-allocate a fixed size of entries.
     const FILELINE_SIZE: usize = 32;
     let mut fileline_buf = [(ptr::null(), -1); FILELINE_SIZE];
     let ret;
-    let fileline_count;
-    {
+    let fileline_count = {
+        let state = unsafe { init_state() };
         let mut fileline_win: &mut [FileLine] = &mut fileline_buf;
         let fileline_addr = &mut fileline_win as *mut &mut [FileLine];
         ret = unsafe {
-            backtrace_pcinfo(state, addr as libc::uintptr_t,
-                             pcinfo_cb, error_cb,
+            backtrace_pcinfo(state,
+                             frame.exact_position as libc::uintptr_t,
+                             pcinfo_cb,
+                             error_cb,
                              fileline_addr as *mut libc::c_void)
         };
-        fileline_count = FILELINE_SIZE - fileline_win.len();
-    }
+        FILELINE_SIZE - fileline_win.len()
+    };
     if ret == 0 {
-        for (i, &(file, line)) in fileline_buf[..fileline_count].iter().enumerate() {
+        for &(file, line) in &fileline_buf[..fileline_count] {
             if file.is_null() { continue; } // just to be sure
             let file = unsafe { CStr::from_ptr(file).to_bytes() };
-            output_fileline(w, file, line, i == FILELINE_SIZE - 1)?;
+            f(file, line)?;
+        }
+        Ok(fileline_count == FILELINE_SIZE)
+    } else {
+        Ok(false)
+    }
+}
+
+/// Converts a pointer to symbol to its string value.
+pub fn resolve_symname<F>(frame: Frame,
+                          callback: F,
+                          _: &BacktraceContext) -> io::Result<()>
+    where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+    let symname = {
+        let state = unsafe { init_state() };
+        if state.is_null() {
+            None
+        } else {
+            let mut data = ptr::null();
+            let data_addr = &mut data as *mut *const libc::c_char;
+            let ret = unsafe {
+                backtrace_syminfo(state,
+                                  frame.symbol_addr as libc::uintptr_t,
+                                  syminfo_cb,
+                                  error_cb,
+                                  data_addr as *mut libc::c_void)
+            };
+            if ret == 0 || data.is_null() {
+                None
+            } else {
+                unsafe {
+                    CStr::from_ptr(data).to_str().ok()
+                }
+            }
+        }
+    };
+    callback(symname)
+}
+
+////////////////////////////////////////////////////////////////////////
+// libbacktrace.h API
+////////////////////////////////////////////////////////////////////////
+type backtrace_syminfo_callback =
+extern "C" fn(data: *mut libc::c_void,
+              pc: libc::uintptr_t,
+              symname: *const libc::c_char,
+              symval: libc::uintptr_t,
+              symsize: libc::uintptr_t);
+type backtrace_full_callback =
+extern "C" fn(data: *mut libc::c_void,
+              pc: libc::uintptr_t,
+              filename: *const libc::c_char,
+              lineno: libc::c_int,
+              function: *const libc::c_char) -> libc::c_int;
+type backtrace_error_callback =
+extern "C" fn(data: *mut libc::c_void,
+              msg: *const libc::c_char,
+              errnum: libc::c_int);
+enum backtrace_state {}
+#[link(name = "backtrace", kind = "static")]
+#[cfg(all(not(test), not(cargobuild)))]
+extern {}
+
+extern {
+    fn backtrace_create_state(filename: *const libc::c_char,
+                              threaded: libc::c_int,
+                              error: backtrace_error_callback,
+                              data: *mut libc::c_void)
+        -> *mut backtrace_state;
+    fn backtrace_syminfo(state: *mut backtrace_state,
+                         addr: libc::uintptr_t,
+                         cb: backtrace_syminfo_callback,
+                         error: backtrace_error_callback,
+                         data: *mut libc::c_void) -> libc::c_int;
+    fn backtrace_pcinfo(state: *mut backtrace_state,
+                        addr: libc::uintptr_t,
+                        cb: backtrace_full_callback,
+                        error: backtrace_error_callback,
+                        data: *mut libc::c_void) -> libc::c_int;
+}
+
+////////////////////////////////////////////////////////////////////////
+// helper callbacks
+////////////////////////////////////////////////////////////////////////
+
+type FileLine = (*const libc::c_char, libc::c_int);
+
+extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
+                   _errnum: libc::c_int) {
+    // do nothing for now
+}
+extern fn syminfo_cb(data: *mut libc::c_void,
+                     _pc: libc::uintptr_t,
+                     symname: *const libc::c_char,
+                     _symval: libc::uintptr_t,
+                     _symsize: libc::uintptr_t) {
+    let slot = data as *mut *const libc::c_char;
+    unsafe { *slot = symname; }
+}
+extern fn pcinfo_cb(data: *mut libc::c_void,
+                    _pc: libc::uintptr_t,
+                    filename: *const libc::c_char,
+                    lineno: libc::c_int,
+                    _function: *const libc::c_char) -> libc::c_int {
+    if !filename.is_null() {
+        let slot = data as *mut &mut [FileLine];
+        let buffer = unsafe {ptr::read(slot)};
+
+        // if the buffer is not full, add file:line to the buffer
+        // and adjust the buffer for next possible calls to pcinfo_cb.
+        if !buffer.is_empty() {
+            buffer[0] = (filename, lineno);
+            unsafe { ptr::write(slot, &mut buffer[1..]); }
         }
     }
 
-    Ok(())
+    0
+}
+
+// The libbacktrace API supports creating a state, but it does not
+// support destroying a state. I personally take this to mean that a
+// state is meant to be created and then live forever.
+//
+// I would love to register an at_exit() handler which cleans up this
+// state, but libbacktrace provides no way to do so.
+//
+// With these constraints, this function has a statically cached state
+// that is calculated the first time this is requested. Remember that
+// backtracing all happens serially (one global lock).
+//
+// Things don't work so well on not-Linux since libbacktrace can't track
+// down that executable this is. We at one point used env::current_exe but
+// it turns out that there are some serious security issues with that
+// approach.
+//
+// Specifically, on certain platforms like BSDs, a malicious actor can cause
+// an arbitrary file to be placed at the path returned by current_exe.
+// libbacktrace does not behave defensively in the presence of ill-formed
+// DWARF information, and has been demonstrated to segfault in at least one
+// case. There is no evidence at the moment to suggest that a more carefully
+// constructed file can't cause arbitrary code execution. As a result of all
+// of this, we don't hint libbacktrace with the path to the current process.
+unsafe fn init_state() -> *mut backtrace_state {
+    static mut STATE: *mut backtrace_state = ptr::null_mut();
+    if !STATE.is_null() { return STATE  }
+
+    let filename = match ::sys::backtrace::gnu::get_executable_filename() {
+        Ok((filename, file)) => {
+            // filename is purposely leaked here since libbacktrace requires
+            // it to stay allocated permanently, file is also leaked so that
+            // the file stays locked
+            let filename_ptr = filename.as_ptr();
+            mem::forget(filename);
+            mem::forget(file);
+            filename_ptr
+        },
+        Err(_) => ptr::null(),
+    };
+
+    STATE = backtrace_create_state(filename, 0, error_cb,
+                                   ptr::null_mut());
+    STATE
 }
index bdc727f1dfcfe0f20536ce50054f7ec5e6cff3e7..d9d13240fcc3acc9a7ec9e4c27138182152cc215 100644 (file)
@@ -60,10 +60,13 @@ pub struct Guard {
 
 /// A type of error which can be returned whenever a lock is acquired.
 ///
-/// Both Mutexes and RwLocks are poisoned whenever a thread fails while the lock
+/// Both [`Mutex`]es and [`RwLock`]s are poisoned whenever a thread fails while the lock
 /// is held. The precise semantics for when a lock is poisoned is documented on
 /// each lock, but once a lock is poisoned then all future acquisitions will
 /// return this error.
+///
+/// [`Mutex`]: ../../std/sync/struct.Mutex.html
+/// [`RwLock`]: ../../std/sync/struct.RwLock.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct PoisonError<T> {
     guard: T,
@@ -85,19 +88,26 @@ pub enum TryLockError<T> {
 
 /// A type alias for the result of a lock method which can be poisoned.
 ///
-/// The `Ok` variant of this result indicates that the primitive was not
-/// poisoned, and the `Guard` is contained within. The `Err` variant indicates
-/// that the primitive was poisoned. Note that the `Err` variant *also* carries
-/// the associated guard, and it can be acquired through the `into_inner`
+/// The [`Ok`] variant of this result indicates that the primitive was not
+/// poisoned, and the `Guard` is contained within. The [`Err`] variant indicates
+/// that the primitive was poisoned. Note that the [`Err`] variant *also* carries
+/// the associated guard, and it can be acquired through the [`into_inner`]
 /// method.
+///
+/// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+/// [`into_inner`]: ../../std/sync/struct.Mutex.html#method.into_inner
 #[stable(feature = "rust1", since = "1.0.0")]
 pub type LockResult<Guard> = Result<Guard, PoisonError<Guard>>;
 
 /// A type alias for the result of a nonblocking locking method.
 ///
-/// For more information, see `LockResult`. A `TryLockResult` doesn't
-/// necessarily hold the associated guard in the `Err` type as the lock may not
+/// For more information, see [`LockResult`]. A `TryLockResult` doesn't
+/// necessarily hold the associated guard in the [`Err`] type as the lock may not
 /// have been acquired for other reasons.
+///
+/// [`LockResult`]: ../../std/sync/type.LockResult.html
+/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
 #[stable(feature = "rust1", since = "1.0.0")]
 pub type TryLockResult<Guard> = Result<Guard, TryLockError<Guard>>;
 
@@ -124,6 +134,11 @@ fn description(&self) -> &str {
 
 impl<T> PoisonError<T> {
     /// Creates a `PoisonError`.
+    ///
+    /// This is generally created by methods like [`Mutex::lock`] or [`RwLock::read`].
+    ///
+    /// [`Mutex::lock`]: ../../std/sync/struct.Mutex.html#method.lock
+    /// [`RwLock::read`]: ../../std/sync/struct.RwLock.html#method.read
     #[stable(feature = "sync_poison", since = "1.2.0")]
     pub fn new(guard: T) -> PoisonError<T> {
         PoisonError { guard: guard }
index 93e320c45223c5978b06f523002e01be941b889b..2bc066d3fea55c3c203525a08317a3e1cd609aa5 100644 (file)
 pub struct Builder {
     // A name for the thread-to-be, for identification in panic messages
     name: Option<String>,
-    // The size of the stack for the spawned thread
+    // The size of the stack for the spawned thread in bytes
     stack_size: Option<usize>,
 }
 
@@ -289,14 +289,17 @@ pub fn name(mut self, name: String) -> Builder {
         self
     }
 
-    /// Sets the size of the stack for the new thread.
+    /// Sets the size of the stack (in bytes) for the new thread.
+    ///
+    /// The actual stack size may be greater than this value if
+    /// the platform specifies minimal stack size.
     ///
     /// # Examples
     ///
     /// ```
     /// use std::thread;
     ///
-    /// let builder = thread::Builder::new().stack_size(10);
+    /// let builder = thread::Builder::new().stack_size(32 * 1024);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn stack_size(mut self, size: usize) -> Builder {
index 42f3aa5ffd6bd2a531017871d91721a15e936f30..30641515a41dd0ca3e3400ba7911bbd2cce70a15 100644 (file)
@@ -25,6 +25,7 @@ pub enum Abi {
     SysV64,
     PtxKernel,
     Msp430Interrupt,
+    X86Interrupt,
 
     // Multiplatform / generic ABIs
     Rust,
@@ -59,6 +60,7 @@ pub struct AbiData {
     AbiData {abi: Abi::SysV64, name: "sysv64", generic: false },
     AbiData {abi: Abi::PtxKernel, name: "ptx-kernel", generic: false },
     AbiData {abi: Abi::Msp430Interrupt, name: "msp430-interrupt", generic: false },
+    AbiData {abi: Abi::X86Interrupt, name: "x86-interrupt", generic: false },
 
     // Cross-platform ABIs
     AbiData {abi: Abi::Rust, name: "Rust", generic: true },
index 455a6a0fb32e21ae736fd81a50579dabdb09f976..096657a6e7ac82e0e213c586e03f5a71a1b97815 100644 (file)
@@ -909,25 +909,12 @@ fn int_type_of_word(s: &str) -> Option<IntType> {
 
 #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
 pub enum ReprAttr {
-    ReprAny,
     ReprInt(IntType),
     ReprExtern,
     ReprPacked,
     ReprSimd,
 }
 
-impl ReprAttr {
-    pub fn is_ffi_safe(&self) -> bool {
-        match *self {
-            ReprAny => false,
-            ReprInt(ity) => ity.is_ffi_safe(),
-            ReprExtern => true,
-            ReprPacked => false,
-            ReprSimd => true,
-        }
-    }
-}
-
 #[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
 pub enum IntType {
     SignedInt(ast::IntTy),
@@ -942,16 +929,6 @@ pub fn is_signed(self) -> bool {
             UnsignedInt(..) => false
         }
     }
-    fn is_ffi_safe(self) -> bool {
-        match self {
-            SignedInt(ast::IntTy::I8) | UnsignedInt(ast::UintTy::U8) |
-            SignedInt(ast::IntTy::I16) | UnsignedInt(ast::UintTy::U16) |
-            SignedInt(ast::IntTy::I32) | UnsignedInt(ast::UintTy::U32) |
-            SignedInt(ast::IntTy::I64) | UnsignedInt(ast::UintTy::U64) |
-            SignedInt(ast::IntTy::I128) | UnsignedInt(ast::UintTy::U128) => true,
-            SignedInt(ast::IntTy::Is) | UnsignedInt(ast::UintTy::Us) => false
-        }
-    }
 }
 
 pub trait HasAttrs: Sized {
index b61ab74687bb79c3f15eacbad1d569e995956783..666e2205b4a2680722ef2d340cb0f2b54dd98253 100644 (file)
@@ -475,7 +475,7 @@ fn make_ty(self: Box<DummyResult>) -> Option<P<ast::Ty>> {
     for<'cx> fn(&'cx mut ExtCtxt, Span, &MetaItem, &Annotatable, &mut FnMut(Annotatable));
 
 /// Represents different kinds of macro invocations that can be resolved.
-#[derive(Clone, Copy, PartialEq, Eq)]
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum MacroKind {
     /// A bang macro - foo!()
     Bang,
index 6c46f90f3d4b95abdd791772314e5c8155218d8c..b1b69c80f4d0016c790c4554d0df6cc73350fd7b 100644 (file)
 use ext::base;
 use ext::build::AstBuilder;
 use parse::parser::{Parser, PathStyle};
-use parse::token::*;
 use parse::token;
 use ptr::P;
-use tokenstream::{self, TokenTree};
+use tokenstream::TokenTree;
 
 
 /// Quasiquoting works via token trees.
@@ -356,14 +355,35 @@ fn parse_expr(&self, s: String) -> P<ast::Expr> {
         }
 
         fn parse_tts(&self, s: String) -> Vec<TokenTree> {
-            panictry!(parse::parse_tts_from_source_str(
-                "<quote expansion>".to_string(),
-                s,
-                self.parse_sess()))
+            parse::parse_tts_from_source_str("<quote expansion>".to_string(), s, self.parse_sess())
         }
     }
 }
 
+// Replaces `Token::OpenDelim .. Token::CloseDelim` with `TokenTree::Delimited(..)`.
+pub fn unflatten(tts: Vec<TokenTree>) -> Vec<TokenTree> {
+    use std::rc::Rc;
+    use tokenstream::Delimited;
+
+    let mut results = Vec::new();
+    let mut result = Vec::new();
+    for tree in tts {
+        match tree {
+            TokenTree::Token(_, token::OpenDelim(..)) => {
+                results.push(::std::mem::replace(&mut result, Vec::new()));
+            }
+            TokenTree::Token(span, token::CloseDelim(delim)) => {
+                let tree =
+                    TokenTree::Delimited(span, Rc::new(Delimited { delim: delim, tts: result }));
+                result = results.pop().unwrap();
+                result.push(tree);
+            }
+            tree @ _ => result.push(tree),
+        }
+    }
+    result
+}
+
 // These panicking parsing functions are used by the quote_*!() syntax extensions,
 // but shouldn't be used otherwise.
 pub fn parse_expr_panic(parser: &mut Parser) -> P<Expr> {
@@ -510,20 +530,6 @@ pub fn expand_quote_path(cx: &mut ExtCtxt,
     base::MacEager::expr(expanded)
 }
 
-pub fn expand_quote_matcher(cx: &mut ExtCtxt,
-                            sp: Span,
-                            tts: &[TokenTree])
-                            -> Box<base::MacResult+'static> {
-    let (cx_expr, tts) = parse_arguments_to_quote(cx, tts);
-    let mut vector = mk_stmts_let(cx, sp);
-    vector.extend(statements_mk_tts(cx, &tts[..], true));
-    vector.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
-    let block = cx.expr_block(cx.block(sp, vector));
-
-    let expanded = expand_wrapper(cx, sp, cx_expr, block, &[&["syntax", "ext", "quote", "rt"]]);
-    base::MacEager::expr(expanded)
-}
-
 fn ids_ext(strs: Vec<String>) -> Vec<ast::Ident> {
     strs.iter().map(|s| ast::Ident::from_str(s)).collect()
 }
@@ -669,12 +675,6 @@ macro_rules! mk_lit {
                                 vec![mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident))]);
         }
 
-        token::MatchNt(name, kind) => {
-            return cx.expr_call(sp,
-                                mk_token_path(cx, sp, "MatchNt"),
-                                vec![mk_ident(cx, sp, name), mk_ident(cx, sp, kind)]);
-        }
-
         token::Interpolated(_) => panic!("quote! with interpolated token"),
 
         _ => ()
@@ -712,9 +712,9 @@ macro_rules! mk_lit {
     mk_token_path(cx, sp, name)
 }
 
-fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec<ast::Stmt> {
+fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, quoted: bool) -> Vec<ast::Stmt> {
     match *tt {
-        TokenTree::Token(sp, SubstNt(ident)) => {
+        TokenTree::Token(sp, token::Ident(ident)) if quoted => {
             // tt.extend($ident.to_tokens(ext_cx))
 
             let e_to_toks =
@@ -733,13 +733,6 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec<ast::Stm
 
             vec![cx.stmt_expr(e_push)]
         }
-        ref tt @ TokenTree::Token(_, MatchNt(..)) if !matcher => {
-            let mut seq = vec![];
-            for i in 0..tt.len() {
-                seq.push(tt.get_tt(i));
-            }
-            statements_mk_tts(cx, &seq[..], matcher)
-        }
         TokenTree::Token(sp, ref tok) => {
             let e_sp = cx.expr_ident(sp, id_ext("_sp"));
             let e_tok = cx.expr_call(sp,
@@ -753,77 +746,17 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec<ast::Stm
             vec![cx.stmt_expr(e_push)]
         },
         TokenTree::Delimited(span, ref delimed) => {
-            statements_mk_tt(cx, &delimed.open_tt(span), matcher).into_iter()
-                .chain(delimed.tts.iter()
-                                  .flat_map(|tt| statements_mk_tt(cx, tt, matcher)))
-                .chain(statements_mk_tt(cx, &delimed.close_tt(span), matcher))
-                .collect()
-        },
-        TokenTree::Sequence(sp, ref seq) => {
-            if !matcher {
-                panic!("TokenTree::Sequence in quote!");
-            }
-
-            let e_sp = cx.expr_ident(sp, id_ext("_sp"));
-
-            let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp));
-            let mut tts_stmts = vec![stmt_let_tt];
-            tts_stmts.extend(statements_mk_tts(cx, &seq.tts[..], matcher));
-            tts_stmts.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
-            let e_tts = cx.expr_block(cx.block(sp, tts_stmts));
-
-            let e_separator = match seq.separator {
-                Some(ref sep) => cx.expr_some(sp, expr_mk_token(cx, sp, sep)),
-                None => cx.expr_none(sp),
-            };
-            let e_op = match seq.op {
-                tokenstream::KleeneOp::ZeroOrMore => "ZeroOrMore",
-                tokenstream::KleeneOp::OneOrMore => "OneOrMore",
-            };
-            let e_op_idents = vec![
-                id_ext("syntax"),
-                id_ext("tokenstream"),
-                id_ext("KleeneOp"),
-                id_ext(e_op),
-            ];
-            let e_op = cx.expr_path(cx.path_global(sp, e_op_idents));
-            let fields = vec![cx.field_imm(sp, id_ext("tts"), e_tts),
-                              cx.field_imm(sp, id_ext("separator"), e_separator),
-                              cx.field_imm(sp, id_ext("op"), e_op),
-                              cx.field_imm(sp, id_ext("num_captures"),
-                                               cx.expr_usize(sp, seq.num_captures))];
-            let seq_path = vec![id_ext("syntax"),
-                                id_ext("tokenstream"),
-                                id_ext("SequenceRepetition")];
-            let e_seq_struct = cx.expr_struct(sp, cx.path_global(sp, seq_path), fields);
-            let e_rc_new = cx.expr_call_global(sp, vec![id_ext("std"),
-                                                        id_ext("rc"),
-                                                        id_ext("Rc"),
-                                                        id_ext("new")],
-                                                   vec![e_seq_struct]);
-            let e_tok = cx.expr_call(sp,
-                                     mk_tt_path(cx, sp, "Sequence"),
-                                     vec![e_sp, e_rc_new]);
-            let e_push =
-                cx.expr_method_call(sp,
-                                    cx.expr_ident(sp, id_ext("tt")),
-                                    id_ext("push"),
-                                    vec![e_tok]);
-            vec![cx.stmt_expr(e_push)]
+            let mut stmts = statements_mk_tt(cx, &delimed.open_tt(span), false);
+            stmts.extend(statements_mk_tts(cx, &delimed.tts));
+            stmts.extend(statements_mk_tt(cx, &delimed.close_tt(span), false));
+            stmts
         }
     }
 }
 
 fn parse_arguments_to_quote(cx: &ExtCtxt, tts: &[TokenTree])
                             -> (P<ast::Expr>, Vec<TokenTree>) {
-    // NB: It appears that the main parser loses its mind if we consider
-    // $foo as a SubstNt during the main parse, so we have to re-parse
-    // under quote_depth > 0. This is silly and should go away; the _guess_ is
-    // it has to do with transition away from supporting old-style macros, so
-    // try removing it when enough of them are gone.
-
     let mut p = cx.new_parser_from_tts(tts);
-    p.quote_depth += 1;
 
     let cx_expr = panictry!(p.parse_expr());
     if !p.eat(&token::Comma) {
@@ -877,24 +810,31 @@ fn mk_stmts_let(cx: &ExtCtxt, sp: Span) -> Vec<ast::Stmt> {
     vec![stmt_let_sp, stmt_let_tt]
 }
 
-fn statements_mk_tts(cx: &ExtCtxt, tts: &[TokenTree], matcher: bool) -> Vec<ast::Stmt> {
+fn statements_mk_tts(cx: &ExtCtxt, tts: &[TokenTree]) -> Vec<ast::Stmt> {
     let mut ss = Vec::new();
+    let mut quoted = false;
     for tt in tts {
-        ss.extend(statements_mk_tt(cx, tt, matcher));
+        quoted = match *tt {
+            TokenTree::Token(_, token::Dollar) if !quoted => true,
+            _ => {
+                ss.extend(statements_mk_tt(cx, tt, quoted));
+                false
+            }
+        }
     }
     ss
 }
 
-fn expand_tts(cx: &ExtCtxt, sp: Span, tts: &[TokenTree])
-              -> (P<ast::Expr>, P<ast::Expr>) {
+fn expand_tts(cx: &ExtCtxt, sp: Span, tts: &[TokenTree]) -> (P<ast::Expr>, P<ast::Expr>) {
     let (cx_expr, tts) = parse_arguments_to_quote(cx, tts);
 
     let mut vector = mk_stmts_let(cx, sp);
-    vector.extend(statements_mk_tts(cx, &tts[..], false));
+    vector.extend(statements_mk_tts(cx, &tts[..]));
     vector.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
     let block = cx.expr_block(cx.block(sp, vector));
+    let unflatten = vec![id_ext("syntax"), id_ext("ext"), id_ext("quote"), id_ext("unflatten")];
 
-    (cx_expr, block)
+    (cx_expr, cx.expr_call_global(sp, unflatten, vec![block]))
 }
 
 fn expand_wrapper(cx: &ExtCtxt,
index 089c35c694a78e3eb9e9c79f0268a80d27a59dc2..6ab5123bc87b16b799aa6630843dfd08accd9af1 100644 (file)
 use syntax_pos::{self, BytePos, mk_sp, Span};
 use codemap::Spanned;
 use errors::FatalError;
+use ext::tt::quoted;
 use parse::{Directory, ParseSess};
 use parse::parser::{PathStyle, Parser};
-use parse::token::{DocComment, MatchNt, SubstNt};
-use parse::token::{Token, Nonterminal};
-use parse::token;
+use parse::token::{self, DocComment, Token, Nonterminal};
 use print::pprust;
-use tokenstream::{self, TokenTree};
+use symbol::keywords;
+use tokenstream::TokenTree;
 use util::small_vector::SmallVector;
 
 use std::mem;
 
 #[derive(Clone)]
 enum TokenTreeOrTokenTreeVec {
-    Tt(tokenstream::TokenTree),
-    TtSeq(Vec<tokenstream::TokenTree>),
+    Tt(quoted::TokenTree),
+    TtSeq(Vec<quoted::TokenTree>),
 }
 
 impl TokenTreeOrTokenTreeVec {
@@ -113,7 +113,7 @@ fn len(&self) -> usize {
         }
     }
 
-    fn get_tt(&self, index: usize) -> TokenTree {
+    fn get_tt(&self, index: usize) -> quoted::TokenTree {
         match *self {
             TtSeq(ref v) => v[index].clone(),
             Tt(ref tt) => tt.get_tt(index),
@@ -144,7 +144,9 @@ struct MatcherPos {
 
 pub type NamedParseResult = ParseResult<HashMap<Ident, Rc<NamedMatch>>>;
 
-pub fn count_names(ms: &[TokenTree]) -> usize {
+pub fn count_names(ms: &[quoted::TokenTree]) -> usize {
+    use self::quoted::TokenTree;
+
     ms.iter().fold(0, |count, elt| {
         count + match *elt {
             TokenTree::Sequence(_, ref seq) => {
@@ -153,7 +155,7 @@ pub fn count_names(ms: &[TokenTree]) -> usize {
             TokenTree::Delimited(_, ref delim) => {
                 count_names(&delim.tts)
             }
-            TokenTree::Token(_, MatchNt(..)) => {
+            TokenTree::MetaVarDecl(..) => {
                 1
             }
             TokenTree::Token(..) => 0,
@@ -161,7 +163,7 @@ pub fn count_names(ms: &[TokenTree]) -> usize {
     })
 }
 
-fn initial_matcher_pos(ms: Vec<TokenTree>, lo: BytePos) -> Box<MatcherPos> {
+fn initial_matcher_pos(ms: Vec<quoted::TokenTree>, lo: BytePos) -> Box<MatcherPos> {
     let match_idx_hi = count_names(&ms[..]);
     let matches = create_matches(match_idx_hi);
     Box::new(MatcherPos {
@@ -200,22 +202,30 @@ pub enum NamedMatch {
     MatchedNonterminal(Rc<Nonterminal>)
 }
 
-fn nameize<I: Iterator<Item=Rc<NamedMatch>>>(ms: &[TokenTree], mut res: I) -> NamedParseResult {
-    fn n_rec<I: Iterator<Item=Rc<NamedMatch>>>(m: &TokenTree, mut res: &mut I,
+fn nameize<I: Iterator<Item=Rc<NamedMatch>>>(sess: &ParseSess, ms: &[quoted::TokenTree], mut res: I)
+                                             -> NamedParseResult {
+    use self::quoted::TokenTree;
+
+    fn n_rec<I: Iterator<Item=Rc<NamedMatch>>>(sess: &ParseSess, m: &TokenTree, mut res: &mut I,
              ret_val: &mut HashMap<Ident, Rc<NamedMatch>>)
              -> Result<(), (syntax_pos::Span, String)> {
         match *m {
             TokenTree::Sequence(_, ref seq) => {
                 for next_m in &seq.tts {
-                    n_rec(next_m, res.by_ref(), ret_val)?
+                    n_rec(sess, next_m, res.by_ref(), ret_val)?
                 }
             }
             TokenTree::Delimited(_, ref delim) => {
                 for next_m in &delim.tts {
-                    n_rec(next_m, res.by_ref(), ret_val)?;
+                    n_rec(sess, next_m, res.by_ref(), ret_val)?;
                 }
             }
-            TokenTree::Token(sp, MatchNt(bind_name, _)) => {
+            TokenTree::MetaVarDecl(span, _, id) if id.name == keywords::Invalid.name() => {
+                if sess.missing_fragment_specifiers.borrow_mut().remove(&span) {
+                    return Err((span, "missing fragment specifier".to_string()));
+                }
+            }
+            TokenTree::MetaVarDecl(sp, bind_name, _) => {
                 match ret_val.entry(bind_name) {
                     Vacant(spot) => {
                         spot.insert(res.next().unwrap());
@@ -225,9 +235,6 @@ fn n_rec<I: Iterator<Item=Rc<NamedMatch>>>(m: &TokenTree, mut res: &mut I,
                     }
                 }
             }
-            TokenTree::Token(sp, SubstNt(..)) => {
-                return Err((sp, "missing fragment specifier".to_string()))
-            }
             TokenTree::Token(..) => (),
         }
 
@@ -236,7 +243,7 @@ fn n_rec<I: Iterator<Item=Rc<NamedMatch>>>(m: &TokenTree, mut res: &mut I,
 
     let mut ret_val = HashMap::new();
     for m in ms {
-        match n_rec(m, res.by_ref(), &mut ret_val) {
+        match n_rec(sess, m, res.by_ref(), &mut ret_val) {
             Ok(_) => {},
             Err((sp, msg)) => return Error(sp, msg),
         }
@@ -276,11 +283,15 @@ fn create_matches(len: usize) -> Vec<Vec<Rc<NamedMatch>>> {
     (0..len).into_iter().map(|_| Vec::new()).collect()
 }
 
-fn inner_parse_loop(cur_eis: &mut SmallVector<Box<MatcherPos>>,
+fn inner_parse_loop(sess: &ParseSess,
+                    cur_eis: &mut SmallVector<Box<MatcherPos>>,
                     next_eis: &mut Vec<Box<MatcherPos>>,
                     eof_eis: &mut SmallVector<Box<MatcherPos>>,
                     bb_eis: &mut SmallVector<Box<MatcherPos>>,
-                    token: &Token, span: &syntax_pos::Span) -> ParseResult<()> {
+                    token: &Token,
+                    span: &syntax_pos::Span) -> ParseResult<()> {
+    use self::quoted::TokenTree;
+
     while let Some(mut ei) = cur_eis.pop() {
         // When unzipped trees end, remove them
         while ei.idx >= ei.top_elts.len() {
@@ -346,7 +357,7 @@ fn inner_parse_loop(cur_eis: &mut SmallVector<Box<MatcherPos>>,
             match ei.top_elts.get_tt(idx) {
                 /* need to descend into sequence */
                 TokenTree::Sequence(sp, seq) => {
-                    if seq.op == tokenstream::KleeneOp::ZeroOrMore {
+                    if seq.op == quoted::KleeneOp::ZeroOrMore {
                         // Examine the case where there are 0 matches of this sequence
                         let mut new_ei = ei.clone();
                         new_ei.match_cur += seq.num_captures;
@@ -372,7 +383,12 @@ fn inner_parse_loop(cur_eis: &mut SmallVector<Box<MatcherPos>>,
                         top_elts: Tt(TokenTree::Sequence(sp, seq)),
                     }));
                 }
-                TokenTree::Token(_, MatchNt(..)) => {
+                TokenTree::MetaVarDecl(span, _, id) if id.name == keywords::Invalid.name() => {
+                    if sess.missing_fragment_specifiers.borrow_mut().remove(&span) {
+                        return Error(span, "missing fragment specifier".to_string());
+                    }
+                }
+                TokenTree::MetaVarDecl(..) => {
                     // Built-in nonterminals never start with these tokens,
                     // so we can eliminate them from consideration.
                     match *token {
@@ -380,9 +396,6 @@ fn inner_parse_loop(cur_eis: &mut SmallVector<Box<MatcherPos>>,
                         _ => bb_eis.push(ei),
                     }
                 }
-                TokenTree::Token(sp, SubstNt(..)) => {
-                    return Error(sp, "missing fragment specifier".to_string())
-                }
                 seq @ TokenTree::Delimited(..) | seq @ TokenTree::Token(_, DocComment(..)) => {
                     let lower_elts = mem::replace(&mut ei.top_elts, Tt(seq));
                     let idx = ei.idx;
@@ -406,8 +419,13 @@ fn inner_parse_loop(cur_eis: &mut SmallVector<Box<MatcherPos>>,
     Success(())
 }
 
-pub fn parse(sess: &ParseSess, tts: Vec<TokenTree>, ms: &[TokenTree], directory: Option<Directory>)
+pub fn parse(sess: &ParseSess,
+             tts: Vec<TokenTree>,
+             ms: &[quoted::TokenTree],
+             directory: Option<Directory>)
              -> NamedParseResult {
+    use self::quoted::TokenTree;
+
     let mut parser = Parser::new(sess, tts, directory, true);
     let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), parser.span.lo));
     let mut next_eis = Vec::new(); // or proceed normally
@@ -417,7 +435,7 @@ pub fn parse(sess: &ParseSess, tts: Vec<TokenTree>, ms: &[TokenTree], directory:
         let mut eof_eis = SmallVector::new();
         assert!(next_eis.is_empty());
 
-        match inner_parse_loop(&mut cur_eis, &mut next_eis, &mut eof_eis, &mut bb_eis,
+        match inner_parse_loop(sess, &mut cur_eis, &mut next_eis, &mut eof_eis, &mut bb_eis,
                                &parser.token, &parser.span) {
             Success(_) => {},
             Failure(sp, tok) => return Failure(sp, tok),
@@ -430,7 +448,8 @@ pub fn parse(sess: &ParseSess, tts: Vec<TokenTree>, ms: &[TokenTree], directory:
         /* error messages here could be improved with links to orig. rules */
         if token_name_eq(&parser.token, &token::Eof) {
             if eof_eis.len() == 1 {
-                return nameize(ms, eof_eis[0].matches.iter_mut().map(|mut dv| dv.pop().unwrap()));
+                let matches = eof_eis[0].matches.iter_mut().map(|mut dv| dv.pop().unwrap());
+                return nameize(sess, ms, matches);
             } else if eof_eis.len() > 1 {
                 return Error(parser.span, "ambiguity: multiple successful parses".to_string());
             } else {
@@ -438,7 +457,7 @@ pub fn parse(sess: &ParseSess, tts: Vec<TokenTree>, ms: &[TokenTree], directory:
             }
         } else if (!bb_eis.is_empty() && !next_eis.is_empty()) || bb_eis.len() > 1 {
             let nts = bb_eis.iter().map(|ei| match ei.top_elts.get_tt(ei.idx) {
-                TokenTree::Token(_, MatchNt(bind, name)) => {
+                TokenTree::MetaVarDecl(_, bind, name) => {
                     format!("{} ('{}')", name, bind)
                 }
                 _ => panic!()
@@ -460,7 +479,7 @@ pub fn parse(sess: &ParseSess, tts: Vec<TokenTree>, ms: &[TokenTree], directory:
             parser.bump();
         } else /* bb_eis.len() == 1 */ {
             let mut ei = bb_eis.pop().unwrap();
-            if let TokenTree::Token(span, MatchNt(_, ident)) = ei.top_elts.get_tt(ei.idx) {
+            if let TokenTree::MetaVarDecl(span, _, ident) = ei.top_elts.get_tt(ei.idx) {
                 let match_cur = ei.match_cur;
                 ei.matches[match_cur].push(Rc::new(MatchedNonterminal(
                             Rc::new(parse_nt(&mut parser, span, &ident.name.as_str())))));
@@ -479,10 +498,7 @@ pub fn parse(sess: &ParseSess, tts: Vec<TokenTree>, ms: &[TokenTree], directory:
 fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
     match name {
         "tt" => {
-            p.quote_depth += 1; //but in theory, non-quoted tts might be useful
-            let tt = panictry!(p.parse_token_tree());
-            p.quote_depth -= 1;
-            return token::NtTT(tt);
+            return token::NtTT(panictry!(p.parse_token_tree()));
         }
         _ => {}
     }
index d0c1c0efea7a399e4496e8b24c9e732d5a06e6dc..193c06707c7a6860a2bb794aa01946f2fcc94442 100644 (file)
 use ext::tt::macro_parser::{Success, Error, Failure};
 use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
 use ext::tt::macro_parser::{parse, parse_failure_msg};
+use ext::tt::quoted;
 use ext::tt::transcribe::transcribe;
 use parse::{Directory, ParseSess};
 use parse::parser::Parser;
-use parse::token::{self, NtTT, Token};
+use parse::token::{self, NtTT};
 use parse::token::Token::*;
 use print;
 use symbol::Symbol;
-use tokenstream::{self, TokenTree};
+use tokenstream::TokenTree;
 
 use std::collections::{HashMap};
 use std::collections::hash_map::{Entry};
@@ -58,8 +59,8 @@ pub fn make(mut self: Box<ParserAnyMacro<'a>>, kind: ExpansionKind) -> Expansion
 
 struct MacroRulesMacroExpander {
     name: ast::Ident,
-    lhses: Vec<TokenTree>,
-    rhses: Vec<TokenTree>,
+    lhses: Vec<quoted::TokenTree>,
+    rhses: Vec<quoted::TokenTree>,
     valid: bool,
 }
 
@@ -86,8 +87,8 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                           sp: Span,
                           name: ast::Ident,
                           arg: &[TokenTree],
-                          lhses: &[TokenTree],
-                          rhses: &[TokenTree])
+                          lhses: &[quoted::TokenTree],
+                          rhses: &[quoted::TokenTree])
                           -> Box<MacResult+'cx> {
     if cx.trace_macros() {
         println!("{}! {{ {} }}",
@@ -101,7 +102,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
 
     for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers
         let lhs_tt = match *lhs {
-            TokenTree::Delimited(_, ref delim) => &delim.tts[..],
+            quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
             _ => cx.span_bug(sp, "malformed macro lhs")
         };
 
@@ -109,7 +110,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
             Success(named_matches) => {
                 let rhs = match rhses[i] {
                     // ignore delimiters
-                    TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
+                    quoted::TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
                     _ => cx.span_bug(sp, "malformed macro rhs"),
                 };
                 // rhs has holes ( `$id` and `$(...)` that need filled)
@@ -164,24 +165,22 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
     // $( $lhs:tt => $rhs:tt );+
     // ...quasiquoting this would be nice.
     // These spans won't matter, anyways
-    let match_lhs_tok = MatchNt(lhs_nm, ast::Ident::from_str("tt"));
-    let match_rhs_tok = MatchNt(rhs_nm, ast::Ident::from_str("tt"));
     let argument_gram = vec![
-        TokenTree::Sequence(DUMMY_SP, Rc::new(tokenstream::SequenceRepetition {
+        quoted::TokenTree::Sequence(DUMMY_SP, Rc::new(quoted::SequenceRepetition {
             tts: vec![
-                TokenTree::Token(DUMMY_SP, match_lhs_tok),
-                TokenTree::Token(DUMMY_SP, token::FatArrow),
-                TokenTree::Token(DUMMY_SP, match_rhs_tok),
+                quoted::TokenTree::MetaVarDecl(DUMMY_SP, lhs_nm, ast::Ident::from_str("tt")),
+                quoted::TokenTree::Token(DUMMY_SP, token::FatArrow),
+                quoted::TokenTree::MetaVarDecl(DUMMY_SP, rhs_nm, ast::Ident::from_str("tt")),
             ],
             separator: Some(token::Semi),
-            op: tokenstream::KleeneOp::OneOrMore,
+            op: quoted::KleeneOp::OneOrMore,
             num_captures: 2,
         })),
         // to phase into semicolon-termination instead of semicolon-separation
-        TokenTree::Sequence(DUMMY_SP, Rc::new(tokenstream::SequenceRepetition {
-            tts: vec![TokenTree::Token(DUMMY_SP, token::Semi)],
+        quoted::TokenTree::Sequence(DUMMY_SP, Rc::new(quoted::SequenceRepetition {
+            tts: vec![quoted::TokenTree::Token(DUMMY_SP, token::Semi)],
             separator: None,
-            op: tokenstream::KleeneOp::ZeroOrMore,
+            op: quoted::KleeneOp::ZeroOrMore,
             num_captures: 0
         })),
     ];
@@ -206,12 +205,13 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
             s.iter().map(|m| {
                 if let MatchedNonterminal(ref nt) = **m {
                     if let NtTT(ref tt) = **nt {
-                        valid &= check_lhs_nt_follows(sess, tt);
-                        return (*tt).clone();
+                        let tt = quoted::parse(&[tt.clone()], true, sess).pop().unwrap();
+                        valid &= check_lhs_nt_follows(sess, &tt);
+                        return tt;
                     }
                 }
                 sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
-            }).collect::<Vec<TokenTree>>()
+            }).collect::<Vec<quoted::TokenTree>>()
         }
         _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
     };
@@ -221,11 +221,11 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
             s.iter().map(|m| {
                 if let MatchedNonterminal(ref nt) = **m {
                     if let NtTT(ref tt) = **nt {
-                        return (*tt).clone();
+                        return quoted::parse(&[tt.clone()], false, sess).pop().unwrap();
                     }
                 }
                 sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
-            }).collect()
+            }).collect::<Vec<quoted::TokenTree>>()
         }
         _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs")
     };
@@ -249,14 +249,14 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
     NormalTT(exp, Some(def.span), attr::contains_name(&def.attrs, "allow_internal_unstable"))
 }
 
-fn check_lhs_nt_follows(sess: &ParseSess, lhs: &TokenTree) -> bool {
+fn check_lhs_nt_follows(sess: &ParseSess, lhs: &quoted::TokenTree) -> bool {
     // lhs is going to be like TokenTree::Delimited(...), where the
     // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
     match lhs {
-        &TokenTree::Delimited(_, ref tts) => check_matcher(sess, &tts.tts),
+        &quoted::TokenTree::Delimited(_, ref tts) => check_matcher(sess, &tts.tts),
         _ => {
             let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
-            sess.span_diagnostic.span_err(lhs.get_span(), msg);
+            sess.span_diagnostic.span_err(lhs.span(), msg);
             false
         }
     }
@@ -266,10 +266,11 @@ fn check_lhs_nt_follows(sess: &ParseSess, lhs: &TokenTree) -> bool {
 
 /// Check that the lhs contains no repetition which could match an empty token
 /// tree, because then the matcher would hang indefinitely.
-fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[TokenTree]) -> bool {
+fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool {
+    use self::quoted::TokenTree;
     for tt in tts {
         match *tt {
-            TokenTree::Token(_, _) => (),
+            TokenTree::Token(..) | TokenTree::MetaVarDecl(..) => (),
             TokenTree::Delimited(_, ref del) => if !check_lhs_no_empty_seq(sess, &del.tts) {
                 return false;
             },
@@ -278,7 +279,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[TokenTree]) -> bool {
                     if seq.tts.iter().all(|seq_tt| {
                         match *seq_tt {
                             TokenTree::Sequence(_, ref sub_seq) =>
-                                sub_seq.op == tokenstream::KleeneOp::ZeroOrMore,
+                                sub_seq.op == quoted::KleeneOp::ZeroOrMore,
                             _ => false,
                         }
                     }) {
@@ -296,15 +297,15 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[TokenTree]) -> bool {
     true
 }
 
-fn check_rhs(sess: &ParseSess, rhs: &TokenTree) -> bool {
+fn check_rhs(sess: &ParseSess, rhs: &quoted::TokenTree) -> bool {
     match *rhs {
-        TokenTree::Delimited(..) => return true,
-        _ => sess.span_diagnostic.span_err(rhs.get_span(), "macro rhs must be delimited")
+        quoted::TokenTree::Delimited(..) => return true,
+        _ => sess.span_diagnostic.span_err(rhs.span(), "macro rhs must be delimited")
     }
     false
 }
 
-fn check_matcher(sess: &ParseSess, matcher: &[TokenTree]) -> bool {
+fn check_matcher(sess: &ParseSess, matcher: &[quoted::TokenTree]) -> bool {
     let first_sets = FirstSets::new(matcher);
     let empty_suffix = TokenSet::empty();
     let err = sess.span_diagnostic.err_count();
@@ -335,7 +336,9 @@ struct FirstSets {
 }
 
 impl FirstSets {
-    fn new(tts: &[TokenTree]) -> FirstSets {
+    fn new(tts: &[quoted::TokenTree]) -> FirstSets {
+        use self::quoted::TokenTree;
+
         let mut sets = FirstSets { first: HashMap::new() };
         build_recur(&mut sets, tts);
         return sets;
@@ -347,13 +350,12 @@ fn build_recur(sets: &mut FirstSets, tts: &[TokenTree]) -> TokenSet {
             let mut first = TokenSet::empty();
             for tt in tts.iter().rev() {
                 match *tt {
-                    TokenTree::Token(sp, ref tok) => {
-                        first.replace_with((sp, tok.clone()));
+                    TokenTree::Token(..) | TokenTree::MetaVarDecl(..) => {
+                        first.replace_with(tt.clone());
                     }
                     TokenTree::Delimited(span, ref delimited) => {
                         build_recur(sets, &delimited.tts[..]);
-                        first.replace_with((delimited.open_tt(span).span(),
-                                            Token::OpenDelim(delimited.delim)));
+                        first.replace_with(delimited.open_tt(span));
                     }
                     TokenTree::Sequence(sp, ref seq_rep) => {
                         let subfirst = build_recur(sets, &seq_rep.tts[..]);
@@ -378,11 +380,11 @@ fn build_recur(sets: &mut FirstSets, tts: &[TokenTree]) -> TokenSet {
 
                         if let (Some(ref sep), true) = (seq_rep.separator.clone(),
                                                         subfirst.maybe_empty) {
-                            first.add_one_maybe((sp, sep.clone()));
+                            first.add_one_maybe(TokenTree::Token(sp, sep.clone()));
                         }
 
                         // Reverse scan: Sequence comes before `first`.
-                        if subfirst.maybe_empty || seq_rep.op == tokenstream::KleeneOp::ZeroOrMore {
+                        if subfirst.maybe_empty || seq_rep.op == quoted::KleeneOp::ZeroOrMore {
                             // If sequence is potentially empty, then
                             // union them (preserving first emptiness).
                             first.add_all(&TokenSet { maybe_empty: true, ..subfirst });
@@ -401,18 +403,19 @@ fn build_recur(sets: &mut FirstSets, tts: &[TokenTree]) -> TokenSet {
 
     // walks forward over `tts` until all potential FIRST tokens are
     // identified.
-    fn first(&self, tts: &[TokenTree]) -> TokenSet {
+    fn first(&self, tts: &[quoted::TokenTree]) -> TokenSet {
+        use self::quoted::TokenTree;
+
         let mut first = TokenSet::empty();
         for tt in tts.iter() {
             assert!(first.maybe_empty);
             match *tt {
-                TokenTree::Token(sp, ref tok) => {
-                    first.add_one((sp, tok.clone()));
+                TokenTree::Token(..) | TokenTree::MetaVarDecl(..) => {
+                    first.add_one(tt.clone());
                     return first;
                 }
                 TokenTree::Delimited(span, ref delimited) => {
-                    first.add_one((delimited.open_tt(span).span(),
-                                   Token::OpenDelim(delimited.delim)));
+                    first.add_one(delimited.open_tt(span));
                     return first;
                 }
                 TokenTree::Sequence(sp, ref seq_rep) => {
@@ -424,13 +427,13 @@ fn first(&self, tts: &[TokenTree]) -> TokenSet {
 
                             if let (Some(ref sep), true) = (seq_rep.separator.clone(),
                                                             subfirst.maybe_empty) {
-                                first.add_one_maybe((sp, sep.clone()));
+                                first.add_one_maybe(TokenTree::Token(sp, sep.clone()));
                             }
 
                             assert!(first.maybe_empty);
                             first.add_all(subfirst);
                             if subfirst.maybe_empty ||
-                               seq_rep.op == tokenstream::KleeneOp::ZeroOrMore {
+                               seq_rep.op == quoted::KleeneOp::ZeroOrMore {
                                 // continue scanning for more first
                                 // tokens, but also make sure we
                                 // restore empty-tracking state
@@ -460,8 +463,8 @@ fn first(&self, tts: &[TokenTree]) -> TokenSet {
     }
 }
 
-// A set of Tokens, which may include MatchNt tokens (for
-// macro-by-example syntactic variables). It also carries the
+// A set of `quoted::TokenTree`s, which may include `TokenTree::Match`s
+// (for macro-by-example syntactic variables). It also carries the
 // `maybe_empty` flag; that is true if and only if the matcher can
 // match an empty token sequence.
 //
@@ -472,7 +475,7 @@ fn first(&self, tts: &[TokenTree]) -> TokenSet {
 // (Notably, we must allow for *-op to occur zero times.)
 #[derive(Clone, Debug)]
 struct TokenSet {
-    tokens: Vec<(Span, Token)>,
+    tokens: Vec<quoted::TokenTree>,
     maybe_empty: bool,
 }
 
@@ -482,13 +485,13 @@ fn empty() -> Self { TokenSet { tokens: Vec::new(), maybe_empty: true } }
 
     // Returns the set `{ tok }` for the single-token (and thus
     // non-empty) sequence [tok].
-    fn singleton(tok: (Span, Token)) -> Self {
+    fn singleton(tok: quoted::TokenTree) -> Self {
         TokenSet { tokens: vec![tok], maybe_empty: false }
     }
 
     // Changes self to be the set `{ tok }`.
     // Since `tok` is always present, marks self as non-empty.
-    fn replace_with(&mut self, tok: (Span, Token)) {
+    fn replace_with(&mut self, tok: quoted::TokenTree) {
         self.tokens.clear();
         self.tokens.push(tok);
         self.maybe_empty = false;
@@ -503,7 +506,7 @@ fn replace_with_irrelevant(&mut self) {
     }
 
     // Adds `tok` to the set for `self`, marking sequence as non-empy.
-    fn add_one(&mut self, tok: (Span, Token)) {
+    fn add_one(&mut self, tok: quoted::TokenTree) {
         if !self.tokens.contains(&tok) {
             self.tokens.push(tok);
         }
@@ -511,7 +514,7 @@ fn add_one(&mut self, tok: (Span, Token)) {
     }
 
     // Adds `tok` to the set for `self`. (Leaves `maybe_empty` flag alone.)
-    fn add_one_maybe(&mut self, tok: (Span, Token)) {
+    fn add_one_maybe(&mut self, tok: quoted::TokenTree) {
         if !self.tokens.contains(&tok) {
             self.tokens.push(tok);
         }
@@ -549,9 +552,9 @@ fn add_all(&mut self, other: &Self) {
 // see `FirstSets::new`.
 fn check_matcher_core(sess: &ParseSess,
                       first_sets: &FirstSets,
-                      matcher: &[TokenTree],
+                      matcher: &[quoted::TokenTree],
                       follow: &TokenSet) -> TokenSet {
-    use print::pprust::token_to_string;
+    use self::quoted::TokenTree;
 
     let mut last = TokenSet::empty();
 
@@ -576,11 +579,11 @@ fn check_matcher_core(sess: &ParseSess,
         // First, update `last` so that it corresponds to the set
         // of NT tokens that might end the sequence `... token`.
         match *token {
-            TokenTree::Token(sp, ref tok) => {
+            TokenTree::Token(..) | TokenTree::MetaVarDecl(..) => {
                 let can_be_followed_by_any;
-                if let Err(bad_frag) = has_legal_fragment_specifier(tok) {
+                if let Err(bad_frag) = has_legal_fragment_specifier(token) {
                     let msg = format!("invalid fragment specifier `{}`", bad_frag);
-                    sess.span_diagnostic.struct_span_err(sp, &msg)
+                    sess.span_diagnostic.struct_span_err(token.span(), &msg)
                         .help("valid fragment specifiers are `ident`, `block`, \
                                `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
                                and `item`")
@@ -589,7 +592,7 @@ fn check_matcher_core(sess: &ParseSess,
                     // from error messages.)
                     can_be_followed_by_any = true;
                 } else {
-                    can_be_followed_by_any = token_can_be_followed_by_any(tok);
+                    can_be_followed_by_any = token_can_be_followed_by_any(token);
                 }
 
                 if can_be_followed_by_any {
@@ -599,13 +602,12 @@ fn check_matcher_core(sess: &ParseSess,
                     // followed by anything against SUFFIX.
                     continue 'each_token;
                 } else {
-                    last.replace_with((sp, tok.clone()));
+                    last.replace_with(token.clone());
                     suffix_first = build_suffix_first();
                 }
             }
             TokenTree::Delimited(span, ref d) => {
-                let my_suffix = TokenSet::singleton((d.close_tt(span).span(),
-                                                     Token::CloseDelim(d.delim)));
+                let my_suffix = TokenSet::singleton(d.close_tt(span));
                 check_matcher_core(sess, first_sets, &d.tts, &my_suffix);
                 // don't track non NT tokens
                 last.replace_with_irrelevant();
@@ -629,7 +631,7 @@ fn check_matcher_core(sess: &ParseSess,
                 let mut new;
                 let my_suffix = if let Some(ref u) = seq_rep.separator {
                     new = suffix_first.clone();
-                    new.add_one_maybe((sp, u.clone()));
+                    new.add_one_maybe(TokenTree::Token(sp, u.clone()));
                     &new
                 } else {
                     &suffix_first
@@ -655,12 +657,13 @@ fn check_matcher_core(sess: &ParseSess,
 
         // Now `last` holds the complete set of NT tokens that could
         // end the sequence before SUFFIX. Check that every one works with `suffix`.
-        'each_last: for &(_sp, ref t) in &last.tokens {
-            if let MatchNt(ref name, ref frag_spec) = *t {
-                for &(sp, ref next_token) in &suffix_first.tokens {
+        'each_last: for token in &last.tokens {
+            if let TokenTree::MetaVarDecl(_, ref name, ref frag_spec) = *token {
+                for next_token in &suffix_first.tokens {
                     match is_in_follow(next_token, &frag_spec.name.as_str()) {
                         Err((msg, help)) => {
-                            sess.span_diagnostic.struct_span_err(sp, &msg).help(help).emit();
+                            sess.span_diagnostic.struct_span_err(next_token.span(), &msg)
+                                .help(help).emit();
                             // don't bother reporting every source of
                             // conflict for a particular element of `last`.
                             continue 'each_last;
@@ -676,12 +679,12 @@ fn check_matcher_core(sess: &ParseSess,
                             };
 
                             sess.span_diagnostic.span_err(
-                                sp,
+                                next_token.span(),
                                 &format!("`${name}:{frag}` {may_be} followed by `{next}`, which \
                                           is not allowed for `{frag}` fragments",
                                          name=name,
                                          frag=frag_spec,
-                                         next=token_to_string(next_token),
+                                         next=quoted_tt_to_string(next_token),
                                          may_be=may_be)
                             );
                         }
@@ -693,8 +696,8 @@ fn check_matcher_core(sess: &ParseSess,
     last
 }
 
-fn token_can_be_followed_by_any(tok: &Token) -> bool {
-    if let &MatchNt(_, ref frag_spec) = tok {
+fn token_can_be_followed_by_any(tok: &quoted::TokenTree) -> bool {
+    if let quoted::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok {
         frag_can_be_followed_by_any(&frag_spec.name.as_str())
     } else {
         // (Non NT's can always be followed by anthing in matchers.)
@@ -732,8 +735,10 @@ fn frag_can_be_followed_by_any(frag: &str) -> bool {
 /// break macros that were relying on that binary operator as a
 /// separator.
 // when changing this do not forget to update doc/book/macros.md!
-fn is_in_follow(tok: &Token, frag: &str) -> Result<bool, (String, &'static str)> {
-    if let &CloseDelim(_) = tok {
+fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> Result<bool, (String, &'static str)> {
+    use self::quoted::TokenTree;
+
+    if let TokenTree::Token(_, token::CloseDelim(_)) = *tok {
         // closing a token tree can never be matched by any fragment;
         // iow, we always require that `(` and `)` match, etc.
         Ok(true)
@@ -749,27 +754,30 @@ fn is_in_follow(tok: &Token, frag: &str) -> Result<bool, (String, &'static str)>
                 // maintain
                 Ok(true)
             },
-            "stmt" | "expr"  => {
-                match *tok {
+            "stmt" | "expr"  => match *tok {
+                TokenTree::Token(_, ref tok) => match *tok {
                     FatArrow | Comma | Semi => Ok(true),
                     _ => Ok(false)
-                }
+                },
+                _ => Ok(false),
             },
-            "pat" => {
-                match *tok {
+            "pat" => match *tok {
+                TokenTree::Token(_, ref tok) => match *tok {
                     FatArrow | Comma | Eq | BinOp(token::Or) => Ok(true),
                     Ident(i) if i.name == "if" || i.name == "in" => Ok(true),
                     _ => Ok(false)
-                }
+                },
+                _ => Ok(false),
             },
-            "path" | "ty" => {
-                match *tok {
+            "path" | "ty" => match *tok {
+                TokenTree::Token(_, ref tok) => match *tok {
                     OpenDelim(token::DelimToken::Brace) | OpenDelim(token::DelimToken::Bracket) |
                     Comma | FatArrow | Colon | Eq | Gt | Semi | BinOp(token::Or) => Ok(true),
-                    MatchNt(_, ref frag) if frag.name == "block" => Ok(true),
                     Ident(i) if i.name == "as" || i.name == "where" => Ok(true),
                     _ => Ok(false)
-                }
+                },
+                TokenTree::MetaVarDecl(_, _, frag) if frag.name == "block" => Ok(true),
+                _ => Ok(false),
             },
             "ident" => {
                 // being a single token, idents are harmless
@@ -780,6 +788,7 @@ fn is_in_follow(tok: &Token, frag: &str) -> Result<bool, (String, &'static str)>
                 // harmless
                 Ok(true)
             },
+            "" => Ok(true), // keywords::Invalid
             _ => Err((format!("invalid fragment specifier `{}`", frag),
                      "valid fragment specifiers are `ident`, `block`, \
                       `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
@@ -788,9 +797,9 @@ fn is_in_follow(tok: &Token, frag: &str) -> Result<bool, (String, &'static str)>
     }
 }
 
-fn has_legal_fragment_specifier(tok: &Token) -> Result<(), String> {
+fn has_legal_fragment_specifier(tok: &quoted::TokenTree) -> Result<(), String> {
     debug!("has_legal_fragment_specifier({:?})", tok);
-    if let &MatchNt(_, ref frag_spec) = tok {
+    if let quoted::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok {
         let s = &frag_spec.name.as_str();
         if !is_legal_fragment_specifier(s) {
             return Err(s.to_string());
@@ -802,7 +811,15 @@ fn has_legal_fragment_specifier(tok: &Token) -> Result<(), String> {
 fn is_legal_fragment_specifier(frag: &str) -> bool {
     match frag {
         "item" | "block" | "stmt" | "expr" | "pat" |
-        "path" | "ty" | "ident" | "meta" | "tt" => true,
+        "path" | "ty" | "ident" | "meta" | "tt" | "" => true,
         _ => false,
     }
 }
+
+fn quoted_tt_to_string(tt: &quoted::TokenTree) -> String {
+    match *tt {
+        quoted::TokenTree::Token(_, ref tok) => ::print::pprust::token_to_string(tok),
+        quoted::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
+        _ => panic!("unexpected quoted::TokenTree::{Sequence or Delimited} in follow set checker"),
+    }
+}
diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs
new file mode 100644 (file)
index 0000000..530824b
--- /dev/null
@@ -0,0 +1,234 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ast;
+use ext::tt::macro_parser;
+use parse::{ParseSess, token};
+use print::pprust;
+use symbol::{keywords, Symbol};
+use syntax_pos::{DUMMY_SP, Span, BytePos};
+use tokenstream;
+
+use std::rc::Rc;
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct Delimited {
+    pub delim: token::DelimToken,
+    pub tts: Vec<TokenTree>,
+}
+
+impl Delimited {
+    pub fn open_token(&self) -> token::Token {
+        token::OpenDelim(self.delim)
+    }
+
+    pub fn close_token(&self) -> token::Token {
+        token::CloseDelim(self.delim)
+    }
+
+    pub fn open_tt(&self, span: Span) -> TokenTree {
+        let open_span = match span {
+            DUMMY_SP => DUMMY_SP,
+            _ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span },
+        };
+        TokenTree::Token(open_span, self.open_token())
+    }
+
+    pub fn close_tt(&self, span: Span) -> TokenTree {
+        let close_span = match span {
+            DUMMY_SP => DUMMY_SP,
+            _ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span },
+        };
+        TokenTree::Token(close_span, self.close_token())
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct SequenceRepetition {
+    /// The sequence of token trees
+    pub tts: Vec<TokenTree>,
+    /// The optional separator
+    pub separator: Option<token::Token>,
+    /// Whether the sequence can be repeated zero (*), or one or more times (+)
+    pub op: KleeneOp,
+    /// The number of `Match`s that appear in the sequence (and subsequences)
+    pub num_captures: usize,
+}
+
+/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star)
+/// for token sequences.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum KleeneOp {
+    ZeroOrMore,
+    OneOrMore,
+}
+
+/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)`
+/// are "first-class" token trees.
+#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
+pub enum TokenTree {
+    Token(Span, token::Token),
+    Delimited(Span, Rc<Delimited>),
+    /// A kleene-style repetition sequence with a span
+    Sequence(Span, Rc<SequenceRepetition>),
+    /// Matches a nonterminal. This is only used in the left hand side of MBE macros.
+    MetaVarDecl(Span, ast::Ident /* name to bind */, ast::Ident /* kind of nonterminal */),
+}
+
+impl TokenTree {
+    pub fn len(&self) -> usize {
+        match *self {
+            TokenTree::Delimited(_, ref delimed) => match delimed.delim {
+                token::NoDelim => delimed.tts.len(),
+                _ => delimed.tts.len() + 2,
+            },
+            TokenTree::Sequence(_, ref seq) => seq.tts.len(),
+            _ => 0,
+        }
+    }
+
+    pub fn get_tt(&self, index: usize) -> TokenTree {
+        match (self, index) {
+            (&TokenTree::Delimited(_, ref delimed), _) if delimed.delim == token::NoDelim => {
+                delimed.tts[index].clone()
+            }
+            (&TokenTree::Delimited(span, ref delimed), _) => {
+                if index == 0 {
+                    return delimed.open_tt(span);
+                }
+                if index == delimed.tts.len() + 1 {
+                    return delimed.close_tt(span);
+                }
+                delimed.tts[index - 1].clone()
+            }
+            (&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(),
+            _ => panic!("Cannot expand a token tree"),
+        }
+    }
+
+    /// Retrieve the TokenTree's span.
+    pub fn span(&self) -> Span {
+        match *self {
+            TokenTree::Token(sp, _) |
+            TokenTree::MetaVarDecl(sp, _, _) |
+            TokenTree::Delimited(sp, _) |
+            TokenTree::Sequence(sp, _) => sp,
+        }
+    }
+}
+
+pub fn parse(input: &[tokenstream::TokenTree], expect_matchers: bool, sess: &ParseSess)
+             -> Vec<TokenTree> {
+    let mut result = Vec::new();
+    let mut trees = input.iter().cloned();
+    while let Some(tree) = trees.next() {
+        let tree = parse_tree(tree, &mut trees, expect_matchers, sess);
+        match tree {
+            TokenTree::Token(start_sp, token::SubstNt(ident)) if expect_matchers => {
+                let span = match trees.next() {
+                    Some(tokenstream::TokenTree::Token(span, token::Colon)) => match trees.next() {
+                        Some(tokenstream::TokenTree::Token(end_sp, token::Ident(kind))) => {
+                            let span = Span { lo: start_sp.lo, ..end_sp };
+                            result.push(TokenTree::MetaVarDecl(span, ident, kind));
+                            continue
+                        }
+                        tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
+                    },
+                    tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp),
+                };
+                sess.missing_fragment_specifiers.borrow_mut().insert(span);
+                result.push(TokenTree::MetaVarDecl(span, ident, keywords::Invalid.ident()));
+            }
+            _ => result.push(tree),
+        }
+    }
+    result
+}
+
+fn parse_tree<I>(tree: tokenstream::TokenTree,
+                 trees: &mut I,
+                 expect_matchers: bool,
+                 sess: &ParseSess)
+                 -> TokenTree
+    where I: Iterator<Item = tokenstream::TokenTree>,
+{
+    match tree {
+        tokenstream::TokenTree::Token(span, token::Dollar) => match trees.next() {
+            Some(tokenstream::TokenTree::Delimited(span, ref delimited)) => {
+                if delimited.delim != token::Paren {
+                    let tok = pprust::token_to_string(&token::OpenDelim(delimited.delim));
+                    let msg = format!("expected `(`, found `{}`", tok);
+                    sess.span_diagnostic.span_err(span, &msg);
+                }
+                let sequence = parse(&delimited.tts, expect_matchers, sess);
+                let (separator, op) = parse_sep_and_kleene_op(trees, span, sess);
+                let name_captures = macro_parser::count_names(&sequence);
+                TokenTree::Sequence(span, Rc::new(SequenceRepetition {
+                    tts: sequence,
+                    separator: separator,
+                    op: op,
+                    num_captures: name_captures,
+                }))
+            }
+            Some(tokenstream::TokenTree::Token(ident_span, token::Ident(ident))) => {
+                let span = Span { lo: span.lo, ..ident_span };
+                if ident.name == keywords::Crate.name() {
+                    let ident = ast::Ident { name: Symbol::intern("$crate"), ..ident };
+                    TokenTree::Token(span, token::Ident(ident))
+                } else {
+                    TokenTree::Token(span, token::SubstNt(ident))
+                }
+            }
+            Some(tokenstream::TokenTree::Token(span, tok)) => {
+                let msg = format!("expected identifier, found `{}`", pprust::token_to_string(&tok));
+                sess.span_diagnostic.span_err(span, &msg);
+                TokenTree::Token(span, token::SubstNt(keywords::Invalid.ident()))
+            }
+            None => TokenTree::Token(span, token::Dollar),
+        },
+        tokenstream::TokenTree::Token(span, tok) => TokenTree::Token(span, tok),
+        tokenstream::TokenTree::Delimited(span, delimited) => {
+            TokenTree::Delimited(span, Rc::new(Delimited {
+                delim: delimited.delim,
+                tts: parse(&delimited.tts, expect_matchers, sess),
+            }))
+        }
+    }
+}
+
+fn parse_sep_and_kleene_op<I>(input: &mut I, span: Span, sess: &ParseSess)
+                              -> (Option<token::Token>, KleeneOp)
+    where I: Iterator<Item = tokenstream::TokenTree>,
+{
+    fn kleene_op(token: &token::Token) -> Option<KleeneOp> {
+        match *token {
+            token::BinOp(token::Star) => Some(KleeneOp::ZeroOrMore),
+            token::BinOp(token::Plus) => Some(KleeneOp::OneOrMore),
+            _ => None,
+        }
+    }
+
+    let span = match input.next() {
+        Some(tokenstream::TokenTree::Token(span, tok)) => match kleene_op(&tok) {
+            Some(op) => return (None, op),
+            None => match input.next() {
+                Some(tokenstream::TokenTree::Token(span, tok2)) => match kleene_op(&tok2) {
+                    Some(op) => return (Some(tok), op),
+                    None => span,
+                },
+                tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
+            }
+        },
+        tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
+    };
+
+    sess.span_diagnostic.span_err(span, "expected `*` or `+`");
+    (None, KleeneOp::ZeroOrMore)
+}
index 38becbe7b1d30a31a5ba0869f065adfd1fcad786..90f64a5208f75cc006830fc74b5abf51a68f2dff 100644 (file)
 // <LICENSE-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::LockstepIterSize::*;
 
 use ast::Ident;
 use errors::Handler;
 use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
-use parse::token::{self, MatchNt, SubstNt, Token, NtIdent, NtTT};
+use ext::tt::quoted;
+use parse::token::{self, SubstNt, Token, NtIdent, NtTT};
 use syntax_pos::{Span, DUMMY_SP};
-use tokenstream::{self, TokenTree};
+use tokenstream::{TokenTree, Delimited};
 use util::small_vector::SmallVector;
 
 use std::rc::Rc;
+use std::mem;
 use std::ops::Add;
 use std::collections::HashMap;
 
-///an unzipping of `TokenTree`s
-#[derive(Clone)]
-struct TtFrame {
-    forest: TokenTree,
-    idx: usize,
-    dotdotdoted: bool,
-    sep: Option<Token>,
+// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`).
+enum Frame {
+    Delimited {
+        forest: Rc<quoted::Delimited>,
+        idx: usize,
+        span: Span,
+    },
+    Sequence {
+        forest: Rc<quoted::SequenceRepetition>,
+        idx: usize,
+        sep: Option<Token>,
+    },
 }
 
-#[derive(Clone)]
-struct TtReader<'a> {
-    sp_diag: &'a Handler,
-    /// the unzipped tree:
-    stack: SmallVector<TtFrame>,
-    /* for MBE-style macro transcription */
-    interpolations: HashMap<Ident, Rc<NamedMatch>>,
+impl Frame {
+    fn new(tts: Vec<quoted::TokenTree>) -> Frame {
+        let forest = Rc::new(quoted::Delimited { delim: token::NoDelim, tts: tts });
+        Frame::Delimited { forest: forest, idx: 0, span: DUMMY_SP }
+    }
+}
+
+impl Iterator for Frame {
+    type Item = quoted::TokenTree;
 
-    repeat_idx: Vec<usize>,
-    repeat_len: Vec<usize>,
+    fn next(&mut self) -> Option<quoted::TokenTree> {
+        match *self {
+            Frame::Delimited { ref forest, ref mut idx, .. } => {
+                *idx += 1;
+                forest.tts.get(*idx - 1).cloned()
+            }
+            Frame::Sequence { ref forest, ref mut idx, .. } => {
+                *idx += 1;
+                forest.tts.get(*idx - 1).cloned()
+            }
+        }
+    }
 }
 
 /// This can do Macro-By-Example transcription. On the other hand, if
-/// `src` contains no `TokenTree::Sequence`s, `MatchNt`s or `SubstNt`s, `interp` can
+/// `src` contains no `TokenTree::{Sequence, Match}`s, or `SubstNt`s, `interp` can
 /// (and should) be None.
 pub fn transcribe(sp_diag: &Handler,
                   interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
-                  src: Vec<tokenstream::TokenTree>)
+                  src: Vec<quoted::TokenTree>)
                   -> Vec<TokenTree> {
-    let mut r = TtReader {
-        sp_diag: sp_diag,
-        stack: SmallVector::one(TtFrame {
-            forest: TokenTree::Sequence(DUMMY_SP, Rc::new(tokenstream::SequenceRepetition {
-                tts: src,
-                // doesn't matter. This merely holds the root unzipping.
-                separator: None, op: tokenstream::KleeneOp::ZeroOrMore, num_captures: 0
-            })),
-            idx: 0,
-            dotdotdoted: false,
-            sep: None,
-        }),
-        interpolations: match interp { /* just a convenience */
-            None => HashMap::new(),
-            Some(x) => x,
-        },
-        repeat_idx: Vec::new(),
-        repeat_len: Vec::new(),
-    };
+    let mut stack = SmallVector::one(Frame::new(src));
+    let interpolations = interp.unwrap_or_else(HashMap::new); /* just a convenience */
+    let mut repeats = Vec::new();
+    let mut result = Vec::new();
+    let mut result_stack = Vec::new();
 
-    let mut tts = Vec::new();
-    let mut prev_span = DUMMY_SP;
-    while let Some(tt) = tt_next_token(&mut r, prev_span) {
-        prev_span = tt.span();
-        tts.push(tt);
-    }
-    tts
-}
-
-fn lookup_cur_matched_by_matched(r: &TtReader, start: Rc<NamedMatch>) -> Rc<NamedMatch> {
-    r.repeat_idx.iter().fold(start, |ad, idx| {
-        match *ad {
-            MatchedNonterminal(_) => {
-                // end of the line; duplicate henceforth
-                ad.clone()
+    loop {
+        let tree = if let Some(tree) = stack.last_mut().unwrap().next() {
+            tree
+        } else {
+            if let Frame::Sequence { ref mut idx, ref sep, .. } = *stack.last_mut().unwrap() {
+                let (ref mut repeat_idx, repeat_len) = *repeats.last_mut().unwrap();
+                *repeat_idx += 1;
+                if *repeat_idx < repeat_len {
+                    *idx = 0;
+                    if let Some(sep) = sep.clone() {
+                        // repeat same span, I guess
+                        let prev_span = result.last().map(TokenTree::span).unwrap_or(DUMMY_SP);
+                        result.push(TokenTree::Token(prev_span, sep));
+                    }
+                    continue
+                }
             }
-            MatchedSeq(ref ads, _) => ads[*idx].clone()
-        }
-    })
-}
-
-fn lookup_cur_matched(r: &TtReader, name: Ident) -> Option<Rc<NamedMatch>> {
-    let matched_opt = r.interpolations.get(&name).cloned();
-    matched_opt.map(|s| lookup_cur_matched_by_matched(r, s))
-}
-
-#[derive(Clone)]
-enum LockstepIterSize {
-    LisUnconstrained,
-    LisConstraint(usize, Ident),
-    LisContradiction(String),
-}
-
-impl Add for LockstepIterSize {
-    type Output = LockstepIterSize;
 
-    fn add(self, other: LockstepIterSize) -> LockstepIterSize {
-        match self {
-            LisUnconstrained => other,
-            LisContradiction(_) => self,
-            LisConstraint(l_len, ref l_id) => match other {
-                LisUnconstrained => self.clone(),
-                LisContradiction(_) => other,
-                LisConstraint(r_len, _) if l_len == r_len => self.clone(),
-                LisConstraint(r_len, r_id) => {
-                    LisContradiction(format!("inconsistent lockstep iteration: \
-                                              '{}' has {} items, but '{}' has {}",
-                                              l_id, l_len, r_id, r_len))
+            match stack.pop().unwrap() {
+                Frame::Sequence { .. } => {
+                    repeats.pop();
+                }
+                Frame::Delimited { forest, span, .. } => {
+                    if result_stack.is_empty() {
+                        return result;
+                    }
+                    let tree = TokenTree::Delimited(span, Rc::new(Delimited {
+                        delim: forest.delim,
+                        tts: result,
+                    }));
+                    result = result_stack.pop().unwrap();
+                    result.push(tree);
                 }
-            },
-        }
-    }
-}
-
-fn lockstep_iter_size(t: &TokenTree, r: &TtReader) -> LockstepIterSize {
-    match *t {
-        TokenTree::Delimited(_, ref delimed) => {
-            delimed.tts.iter().fold(LisUnconstrained, |size, tt| {
-                size + lockstep_iter_size(tt, r)
-            })
-        },
-        TokenTree::Sequence(_, ref seq) => {
-            seq.tts.iter().fold(LisUnconstrained, |size, tt| {
-                size + lockstep_iter_size(tt, r)
-            })
-        },
-        TokenTree::Token(_, SubstNt(name)) | TokenTree::Token(_, MatchNt(name, _)) =>
-            match lookup_cur_matched(r, name) {
-                Some(matched) => match *matched {
-                    MatchedNonterminal(_) => LisUnconstrained,
-                    MatchedSeq(ref ads, _) => LisConstraint(ads.len(), name),
-                },
-                _ => LisUnconstrained
-            },
-        TokenTree::Token(..) => LisUnconstrained,
-    }
-}
-
-/// Return the next token from the TtReader.
-/// EFFECT: advances the reader's token field
-fn tt_next_token(r: &mut TtReader, prev_span: Span) -> Option<TokenTree> {
-    loop {
-        let should_pop = if let Some(frame) = r.stack.last() {
-            if frame.idx < frame.forest.len() {
-                break;
             }
-            !frame.dotdotdoted || *r.repeat_idx.last().unwrap() == *r.repeat_len.last().unwrap() - 1
-        } else {
-            return None;
+            continue
         };
 
-        /* done with this set; pop or repeat? */
-        if should_pop {
-            let prev = r.stack.pop().unwrap();
-            if let Some(frame) = r.stack.last_mut() {
-                frame.idx += 1;
-            } else {
-                return None;
-            }
-            if prev.dotdotdoted {
-                r.repeat_idx.pop();
-                r.repeat_len.pop();
-            }
-        } else { /* repeat */
-            *r.repeat_idx.last_mut().unwrap() += 1;
-            r.stack.last_mut().unwrap().idx = 0;
-            if let Some(tk) = r.stack.last().unwrap().sep.clone() {
-                return Some(TokenTree::Token(prev_span, tk)); // repeat same span, I guess
-            }
-        }
-    }
-    loop { /* because it's easiest, this handles `TokenTree::Delimited` not starting
-              with a `TokenTree::Token`, even though it won't happen */
-        let t = {
-            let frame = r.stack.last().unwrap();
-            // FIXME(pcwalton): Bad copy.
-            frame.forest.get_tt(frame.idx)
-        };
-        match t {
-            TokenTree::Sequence(sp, seq) => {
+        match tree {
+            quoted::TokenTree::Sequence(sp, seq) => {
                 // FIXME(pcwalton): Bad copy.
-                match lockstep_iter_size(&TokenTree::Sequence(sp, seq.clone()),
-                                         r) {
-                    LisUnconstrained => {
-                        panic!(r.sp_diag.span_fatal(
+                match lockstep_iter_size(&quoted::TokenTree::Sequence(sp, seq.clone()),
+                                         &interpolations,
+                                         &repeats) {
+                    LockstepIterSize::Unconstrained => {
+                        panic!(sp_diag.span_fatal(
                             sp.clone(), /* blame macro writer */
                             "attempted to repeat an expression \
                              containing no syntax \
                              variables matched as repeating at this depth"));
                     }
-                    LisContradiction(ref msg) => {
+                    LockstepIterSize::Contradiction(ref msg) => {
                         // FIXME #2887 blame macro invoker instead
-                        panic!(r.sp_diag.span_fatal(sp.clone(), &msg[..]));
+                        panic!(sp_diag.span_fatal(sp.clone(), &msg[..]));
                     }
-                    LisConstraint(len, _) => {
+                    LockstepIterSize::Constraint(len, _) => {
                         if len == 0 {
-                            if seq.op == tokenstream::KleeneOp::OneOrMore {
+                            if seq.op == quoted::KleeneOp::OneOrMore {
                                 // FIXME #2887 blame invoker
-                                panic!(r.sp_diag.span_fatal(sp.clone(),
-                                                     "this must repeat at least once"));
+                                panic!(sp_diag.span_fatal(sp.clone(),
+                                                          "this must repeat at least once"));
                             }
-
-                            r.stack.last_mut().unwrap().idx += 1;
-                            return tt_next_token(r, prev_span);
+                        } else {
+                            repeats.push((0, len));
+                            stack.push(Frame::Sequence {
+                                idx: 0,
+                                sep: seq.separator.clone(),
+                                forest: seq,
+                            });
                         }
-                        r.repeat_len.push(len);
-                        r.repeat_idx.push(0);
-                        r.stack.push(TtFrame {
-                            idx: 0,
-                            dotdotdoted: true,
-                            sep: seq.separator.clone(),
-                            forest: TokenTree::Sequence(sp, seq),
-                        });
                     }
                 }
             }
             // FIXME #2887: think about span stuff here
-            TokenTree::Token(sp, SubstNt(ident)) => {
-                r.stack.last_mut().unwrap().idx += 1;
-                match lookup_cur_matched(r, ident) {
-                    None => {
-                        return Some(TokenTree::Token(sp, SubstNt(ident)));
-                        // this can't be 0 length, just like TokenTree::Delimited
-                    }
+            quoted::TokenTree::Token(sp, SubstNt(ident)) => {
+                match lookup_cur_matched(ident, &interpolations, &repeats) {
+                    None => result.push(TokenTree::Token(sp, SubstNt(ident))),
                     Some(cur_matched) => if let MatchedNonterminal(ref nt) = *cur_matched {
                         match **nt {
                             // sidestep the interpolation tricks for ident because
                             // (a) idents can be in lots of places, so it'd be a pain
                             // (b) we actually can, since it's a token.
                             NtIdent(ref sn) => {
-                                return Some(TokenTree::Token(sn.span, token::Ident(sn.node)));
+                                result.push(TokenTree::Token(sn.span, token::Ident(sn.node)));
                             }
-                            NtTT(ref tt) => return Some(tt.clone()),
+                            NtTT(ref tt) => result.push(tt.clone()),
                             _ => {
                                 // FIXME(pcwalton): Bad copy
-                                return Some(TokenTree::Token(sp, token::Interpolated(nt.clone())));
+                                result.push(TokenTree::Token(sp, token::Interpolated(nt.clone())));
                             }
                         }
                     } else {
-                        panic!(r.sp_diag.span_fatal(
+                        panic!(sp_diag.span_fatal(
                             sp, /* blame the macro writer */
                             &format!("variable '{}' is still repeating at this depth", ident)));
                     }
                 }
             }
-            // TokenTree::Delimited or any token that can be unzipped
-            seq @ TokenTree::Delimited(..) | seq @ TokenTree::Token(_, MatchNt(..)) => {
-                // do not advance the idx yet
-                r.stack.push(TtFrame {
-                   forest: seq,
-                   idx: 0,
-                   dotdotdoted: false,
-                   sep: None
-                });
-                // if this could be 0-length, we'd need to potentially recur here
+            quoted::TokenTree::Delimited(span, delimited) => {
+                stack.push(Frame::Delimited { forest: delimited, idx: 0, span: span });
+                result_stack.push(mem::replace(&mut result, Vec::new()));
             }
-            tt @ TokenTree::Token(..) => {
-                r.stack.last_mut().unwrap().idx += 1;
-                return Some(tt);
+            quoted::TokenTree::Token(span, tok) => result.push(TokenTree::Token(span, tok)),
+            quoted::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"),
+        }
+    }
+}
+
+fn lookup_cur_matched(ident: Ident,
+                      interpolations: &HashMap<Ident, Rc<NamedMatch>>,
+                      repeats: &[(usize, usize)])
+                      -> Option<Rc<NamedMatch>> {
+    interpolations.get(&ident).map(|matched| {
+        repeats.iter().fold(matched.clone(), |ad, &(idx, _)| {
+            match *ad {
+                MatchedNonterminal(_) => {
+                    // end of the line; duplicate henceforth
+                    ad.clone()
+                }
+                MatchedSeq(ref ads, _) => ads[idx].clone()
             }
+        })
+    })
+}
+
+#[derive(Clone)]
+enum LockstepIterSize {
+    Unconstrained,
+    Constraint(usize, Ident),
+    Contradiction(String),
+}
+
+impl Add for LockstepIterSize {
+    type Output = LockstepIterSize;
+
+    fn add(self, other: LockstepIterSize) -> LockstepIterSize {
+        match self {
+            LockstepIterSize::Unconstrained => other,
+            LockstepIterSize::Contradiction(_) => self,
+            LockstepIterSize::Constraint(l_len, ref l_id) => match other {
+                LockstepIterSize::Unconstrained => self.clone(),
+                LockstepIterSize::Contradiction(_) => other,
+                LockstepIterSize::Constraint(r_len, _) if l_len == r_len => self.clone(),
+                LockstepIterSize::Constraint(r_len, r_id) => {
+                    let msg = format!("inconsistent lockstep iteration: \
+                                       '{}' has {} items, but '{}' has {}",
+                                      l_id, l_len, r_id, r_len);
+                    LockstepIterSize::Contradiction(msg)
+                }
+            },
         }
     }
 }
+
+fn lockstep_iter_size(tree: &quoted::TokenTree,
+                      interpolations: &HashMap<Ident, Rc<NamedMatch>>,
+                      repeats: &[(usize, usize)])
+                      -> LockstepIterSize {
+    use self::quoted::TokenTree;
+    match *tree {
+        TokenTree::Delimited(_, ref delimed) => {
+            delimed.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| {
+                size + lockstep_iter_size(tt, interpolations, repeats)
+            })
+        },
+        TokenTree::Sequence(_, ref seq) => {
+            seq.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| {
+                size + lockstep_iter_size(tt, interpolations, repeats)
+            })
+        },
+        TokenTree::Token(_, SubstNt(name)) | TokenTree::MetaVarDecl(_, name, _) =>
+            match lookup_cur_matched(name, interpolations, repeats) {
+                Some(matched) => match *matched {
+                    MatchedNonterminal(_) => LockstepIterSize::Unconstrained,
+                    MatchedSeq(ref ads, _) => LockstepIterSize::Constraint(ads.len(), name),
+                },
+                _ => LockstepIterSize::Unconstrained
+            },
+        TokenTree::Token(..) => LockstepIterSize::Unconstrained,
+    }
+}
index b7be084fa0bab8453b078b507bf320572ad22a5a..6eb7d449f269287afe915646535552840b0ec16d 100644 (file)
@@ -77,12 +77,19 @@ pub fn new() -> Features {
     };
 
     ($((removed, $feature: ident, $ver: expr, $issue: expr),)+) => {
-        /// Represents features which has since been removed (it was once Active)
+        /// Represents unstable features which have since been removed (it was once Active)
         const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
             $((stringify!($feature), $ver, $issue)),+
         ];
     };
 
+    ($((stable_removed, $feature: ident, $ver: expr, $issue: expr),)+) => {
+        /// Represents stable features which have since been removed (it was once Accepted)
+        const STABLE_REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
+            $((stringify!($feature), $ver, $issue)),+
+        ];
+    };
+
     ($((accepted, $feature: ident, $ver: expr, $issue: expr),)+) => {
         /// Those language feature has since been Accepted (it was once Active)
         const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
@@ -200,9 +207,6 @@ pub fn new() -> Features {
     // rustc internal
     (active, prelude_import, "1.2.0", None),
 
-    // Allows the definition recursive static items.
-    (active, static_recursion, "1.3.0", Some(29719)),
-
     // Allows default type parameters to influence type inference.
     (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
 
@@ -326,9 +330,16 @@ pub fn new() -> Features {
     // `extern "msp430-interrupt" fn()`
     (active, abi_msp430_interrupt, "1.16.0", Some(38487)),
 
+    // Used to identify crates that contain sanitizer runtimes
+    // rustc internal
+    (active, closure_to_fn_coercion, "1.17.0", Some(39817)),
+
     // Used to identify crates that contain sanitizer runtimes
     // rustc internal
     (active, sanitizer_runtime, "1.17.0", None),
+
+    // `extern "x86-interrupt" fn()`
+    (active, abi_x86_interrupt, "1.17.0", Some(40180)),
 );
 
 declare_features! (
@@ -350,6 +361,10 @@ pub fn new() -> Features {
     (removed, pushpop_unsafe, "1.2.0", None),
 );
 
+declare_features! (
+    (stable_removed, no_stack_check, "1.0.0", None),
+);
+
 declare_features! (
     (accepted, associated_types, "1.0.0", None),
     // allow overloading augmented assignment operations like `a += b`
@@ -387,6 +402,8 @@ pub fn new() -> Features {
     (accepted, static_in_const, "1.17.0", Some(35897)),
     // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
     (accepted, field_init_shorthand, "1.17.0", Some(37340)),
+    // Allows the definition recursive static items.
+    (accepted, static_recursion, "1.17.0", Some(29719)),
 );
 // If you change this, please modify src/doc/unstable-book as well. You must
 // move that documentation into the relevant place in the other docs, and
@@ -502,9 +519,6 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
                                              not yet settled",
                                             cfg_fn!(structural_match))),
 
-    // Not used any more, but we can't feature gate it
-    ("no_stack_check", Normal, Ungated),
-
     ("plugin", CrateLevel, Gated(Stability::Unstable,
                                  "plugin",
                                  "compiler plugins are experimental \
@@ -760,6 +774,11 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
                                            "attribute proc macros are currently unstable",
                                            cfg_fn!(proc_macro))),
 
+    ("proc_macro", Normal, Gated(Stability::Unstable,
+                                 "proc_macro",
+                                 "function-like proc macros are currently unstable",
+                                 cfg_fn!(proc_macro))),
+
     ("rustc_derive_registrar", Normal, Gated(Stability::Unstable,
                                              "rustc_derive_registrar",
                                              "used internally by rustc",
@@ -906,8 +925,10 @@ fn find_lang_feature_issue(feature: &str) -> Option<u32> {
         // assert!(issue.is_some())
         issue
     } else {
-        // search in Accepted or Removed features
-        match ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).find(|t| t.0 == feature) {
+        // search in Accepted, Removed, or Stable Removed features
+        let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES)
+            .find(|t| t.0 == feature);
+        match found {
             Some(&(_, _, issue)) => issue,
             None => panic!("Feature `{}` is not declared anywhere", feature),
         }
@@ -982,6 +1003,9 @@ pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: Ga
 pub const EXPLAIN_PLACEMENT_IN: &'static str =
     "placement-in expression syntax is experimental and subject to change.";
 
+pub const CLOSURE_TO_FN_COERCION: &'static str =
+    "non-capturing closure to fn coercion is experimental";
+
 struct PostExpansionVisitor<'a> {
     context: &'a Context<'a>,
 }
@@ -1030,6 +1054,10 @@ fn check_abi(&self, abi: Abi, span: Span) {
                 gate_feature_post!(&self, abi_msp430_interrupt, span,
                                    "msp430-interrupt ABI is experimental and subject to change");
             },
+            Abi::X86Interrupt => {
+                gate_feature_post!(&self, abi_x86_interrupt, span,
+                                   "x86-interrupt ABI is experimental and subject to change");
+            },
             // Stable
             Abi::Cdecl |
             Abi::Stdcall |
@@ -1438,7 +1466,9 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> F
                         feature_checker.collect(&features, mi.span);
                     }
                     else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
-                        .find(|& &(n, _, _)| name == n) {
+                            .find(|& &(n, _, _)| name == n)
+                        .or_else(|| STABLE_REMOVED_FEATURES.iter()
+                            .find(|& &(n, _, _)| name == n)) {
                         span_err!(span_handler, mi.span, E0557, "feature has been removed");
                     }
                     else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
index 1ee070cb92d9fe03de2a6bbcf2b9fb6a96d5be7f..257b7efba5c8e8d2f49cf96eef59d93a56a125f1 100644 (file)
@@ -551,13 +551,6 @@ pub fn noop_fold_tt<T: Folder>(tt: &TokenTree, fld: &mut T) -> TokenTree {
                             }
                         ))
         },
-        TokenTree::Sequence(span, ref seq) =>
-            TokenTree::Sequence(fld.new_span(span),
-                       Rc::new(SequenceRepetition {
-                           tts: fld.fold_tts(&seq.tts),
-                           separator: seq.separator.clone().map(|tok| fld.fold_token(tok)),
-                           ..**seq
-                       })),
     }
 }
 
@@ -578,7 +571,6 @@ pub fn noop_fold_token<T: Folder>(t: token::Token, fld: &mut T) -> token::Token
             token::Interpolated(Rc::new(fld.fold_interpolated(nt)))
         }
         token::SubstNt(ident) => token::SubstNt(fld.fold_ident(ident)),
-        token::MatchNt(name, kind) => token::MatchNt(fld.fold_ident(name), fld.fold_ident(kind)),
         _ => t
     }
 }
index 87a03adf6b77c018784aa535a3939f0ba1db4a2c..39a9aff48bf27163d0b8dcea76916863b54bd7de 100644 (file)
@@ -139,6 +139,7 @@ pub mod tt {
         pub mod transcribe;
         pub mod macro_parser;
         pub mod macro_rules;
+        pub mod quoted;
     }
 }
 
index 6bc15115b09d3efca57ab6b55100e9c450132996..de8a87e3a2b3293c9531d75b6dc53b7fe1cf3833 100644 (file)
@@ -51,10 +51,10 @@ pub struct StringReader<'a> {
     pub filemap: Rc<syntax_pos::FileMap>,
     /// If Some, stop reading the source at this position (inclusive).
     pub terminator: Option<BytePos>,
-    /// Whether to record new-lines in filemap. This is only necessary the first
-    /// time a filemap is lexed. If part of a filemap is being re-lexed, this
-    /// should be set to false.
-    pub save_new_lines: bool,
+    /// Whether to record new-lines and multibyte chars in filemap.
+    /// This is only necessary the first time a filemap is lexed.
+    /// If part of a filemap is being re-lexed, this should be set to false.
+    pub save_new_lines_and_multibyte: bool,
     // cached:
     pub peek_tok: token::Token,
     pub peek_span: Span,
@@ -162,7 +162,7 @@ fn new_raw_internal(sess: &'a ParseSess, filemap: Rc<syntax_pos::FileMap>) -> Se
             ch: Some('\n'),
             filemap: filemap,
             terminator: None,
-            save_new_lines: true,
+            save_new_lines_and_multibyte: true,
             // dummy values; not read
             peek_tok: token::Eof,
             peek_span: syntax_pos::DUMMY_SP,
@@ -183,6 +183,31 @@ pub fn new(sess: &'a ParseSess, filemap: Rc<syntax_pos::FileMap>) -> Self {
         sr
     }
 
+    pub fn retokenize(sess: &'a ParseSess, mut span: Span) -> Self {
+        let begin = sess.codemap().lookup_byte_offset(span.lo);
+        let end = sess.codemap().lookup_byte_offset(span.hi);
+
+        // Make the range zero-length if the span is invalid.
+        if span.lo > span.hi || begin.fm.start_pos != end.fm.start_pos {
+            span.hi = span.lo;
+        }
+
+        let mut sr = StringReader::new_raw_internal(sess, begin.fm);
+
+        // Seek the lexer to the right byte range.
+        sr.save_new_lines_and_multibyte = false;
+        sr.next_pos = span.lo;
+        sr.terminator = Some(span.hi);
+
+        sr.bump();
+
+        if let Err(_) = sr.advance_token() {
+            sr.emit_fatal_errors();
+            panic!(FatalError);
+        }
+        sr
+    }
+
     pub fn ch_is(&self, c: char) -> bool {
         self.ch == Some(c)
     }
@@ -378,7 +403,10 @@ fn translate_crlf_(rdr: &StringReader,
     pub fn bump(&mut self) {
         let new_pos = self.next_pos;
         let new_byte_offset = self.byte_offset(new_pos).to_usize();
-        if new_byte_offset < self.source_text.len() {
+        let end = self.terminator.map_or(self.source_text.len(), |t| {
+            self.byte_offset(t).to_usize()
+        });
+        if new_byte_offset < end {
             let old_ch_is_newline = self.ch.unwrap() == '\n';
             let new_ch = char_at(&self.source_text, new_byte_offset);
             let new_ch_len = new_ch.len_utf8();
@@ -387,7 +415,7 @@ pub fn bump(&mut self) {
             self.pos = new_pos;
             self.next_pos = new_pos + Pos::from_usize(new_ch_len);
             if old_ch_is_newline {
-                if self.save_new_lines {
+                if self.save_new_lines_and_multibyte {
                     self.filemap.next_line(self.pos);
                 }
                 self.col = CharPos(0);
@@ -395,7 +423,9 @@ pub fn bump(&mut self) {
                 self.col = self.col + CharPos(1);
             }
             if new_ch_len > 1 {
-                self.filemap.record_multibyte_char(self.pos, new_ch_len);
+                if self.save_new_lines_and_multibyte {
+                    self.filemap.record_multibyte_char(self.pos, new_ch_len);
+                }
             }
         } else {
             self.ch = None;
@@ -1663,6 +1693,7 @@ mod tests {
     use feature_gate::UnstableFeatures;
     use parse::token;
     use std::cell::RefCell;
+    use std::collections::HashSet;
     use std::io;
     use std::rc::Rc;
 
@@ -1674,6 +1705,7 @@ fn mk_sess(cm: Rc<CodeMap>) -> ParseSess {
             config: CrateConfig::new(),
             included_mod_stack: RefCell::new(Vec::new()),
             code_map: cm,
+            missing_fragment_specifiers: RefCell::new(HashSet::new()),
         }
     }
 
index 20e80afc115f5676ffc746377dd6920f2f2ae7ec..6fec49b229abeeb315d37c608d7c033381619f7a 100644 (file)
@@ -46,6 +46,7 @@ pub struct ParseSess {
     pub span_diagnostic: Handler,
     pub unstable_features: UnstableFeatures,
     pub config: CrateConfig,
+    pub missing_fragment_specifiers: RefCell<HashSet<Span>>,
     /// Used to determine and report recursive mod inclusions
     included_mod_stack: RefCell<Vec<PathBuf>>,
     code_map: Rc<CodeMap>,
@@ -66,6 +67,7 @@ pub fn with_span_handler(handler: Handler, code_map: Rc<CodeMap>) -> ParseSess {
             span_diagnostic: handler,
             unstable_features: UnstableFeatures::from_environment(),
             config: HashSet::new(),
+            missing_fragment_specifiers: RefCell::new(HashSet::new()),
             included_mod_stack: RefCell::new(vec![]),
             code_map: code_map
         }
@@ -139,13 +141,9 @@ pub fn parse_stmt_from_source_str<'a>(name: String, source: String, sess: &'a Pa
     new_parser_from_source_str(sess, name, source).parse_stmt()
 }
 
-// Warning: This parses with quote_depth > 0, which is not the default.
 pub fn parse_tts_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
-                                     -> PResult<'a, Vec<tokenstream::TokenTree>> {
-    let mut p = new_parser_from_source_str(sess, name, source);
-    p.quote_depth += 1;
-    // right now this is re-creating the token trees from ... token trees.
-    p.parse_all_token_trees()
+                                     -> Vec<tokenstream::TokenTree> {
+    filemap_to_tts(sess, sess.codemap().new_filemap(name, None, source))
 }
 
 // Create a new parser from a source string
@@ -986,7 +984,7 @@ fn ttdelim_span() {
             _ => panic!("not a macro"),
         };
 
-        let span = tts.iter().rev().next().unwrap().get_span();
+        let span = tts.iter().rev().next().unwrap().span();
 
         match sess.codemap().span_to_snippet(span) {
             Ok(s) => assert_eq!(&s[..], "{ body }"),
index b5b8a6bc0ef64c80f08a32ed04739606146392a4..71274c4fdaa4ead88e9512baac8a1ec75d7b065c 100644 (file)
 use codemap::{self, CodeMap, Spanned, spanned, respan};
 use syntax_pos::{self, Span, Pos, BytePos, mk_sp};
 use errors::{self, DiagnosticBuilder};
-use ext::tt::macro_parser;
-use parse;
-use parse::classify;
+use parse::{self, classify, token};
 use parse::common::SeqSep;
 use parse::lexer::TokenAndSpan;
 use parse::obsolete::ObsoleteSyntax;
-use parse::token::{self, MatchNt, SubstNt};
 use parse::{new_sub_parser_from_file, ParseSess, Directory, DirectoryOwnership};
 use util::parser::{AssocOp, Fixity};
 use print::pprust;
 use ptr::P;
 use parse::PResult;
-use tokenstream::{self, Delimited, SequenceRepetition, TokenTree};
+use tokenstream::{Delimited, TokenTree};
 use symbol::{Symbol, keywords};
 use util::ThinVec;
 
@@ -168,8 +165,6 @@ pub struct Parser<'a> {
     /// the previous token kind
     prev_token_kind: PrevTokenKind,
     pub restrictions: Restrictions,
-    pub quote_depth: usize, // not (yet) related to the quasiquoter
-    parsing_token_tree: bool,
     /// The set of seen errors about obsolete syntax. Used to suppress
     /// extra detail when the same error is seen twice
     pub obsolete_set: HashSet<ObsoleteSyntax>,
@@ -329,8 +324,6 @@ pub fn new(sess: &'a ParseSess,
             prev_span: syntax_pos::DUMMY_SP,
             prev_token_kind: PrevTokenKind::Other,
             restrictions: Restrictions::empty(),
-            quote_depth: 0,
-            parsing_token_tree: false,
             obsolete_set: HashSet::new(),
             directory: Directory { path: PathBuf::new(), ownership: DirectoryOwnership::Owned },
             root_module_name: None,
@@ -359,20 +352,11 @@ fn next_tok(&mut self) -> TokenAndSpan {
                 if i + 1 < tts.len() {
                     self.tts.push((tts, i + 1));
                 }
-                // FIXME(jseyfried): remove after fixing #39390 in #39419.
-                if self.quote_depth > 0 {
-                    if let TokenTree::Sequence(sp, _) = tt {
-                        self.span_err(sp, "attempted to repeat an expression containing no \
-                                           syntax variables matched as repeating at this depth");
-                    }
-                }
-                match tt {
-                    TokenTree::Token(sp, tok) => TokenAndSpan { tok: tok, sp: sp },
-                    _ if tt.len() > 0 => {
-                        self.tts.push((tt, 0));
-                        continue
-                    }
-                    _ => continue,
+                if let TokenTree::Token(sp, tok) = tt {
+                    TokenAndSpan { tok: tok, sp: sp }
+                } else {
+                    self.tts.push((tt, 0));
+                    continue
                 }
             } else {
                 TokenAndSpan { tok: token::Eof, sp: self.span }
@@ -997,7 +981,6 @@ pub fn look_ahead<R, F>(&mut self, dist: usize, f: F) -> R where
                 tok = match tts.get_tt(i) {
                     TokenTree::Token(_, tok) => tok,
                     TokenTree::Delimited(_, delimited) => token::OpenDelim(delimited.delim),
-                    TokenTree::Sequence(..) => token::Dollar,
                 };
             }
         }
@@ -1187,10 +1170,7 @@ pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> {
             self.expect(&token::Not)?;
 
             // eat a matched-delimiter token tree:
-            let delim = self.expect_open_delim()?;
-            let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
-                                            SeqSep::none(),
-                                            |pp| pp.parse_token_tree())?;
+            let (delim, tts) = self.expect_delimited_token_tree()?;
             if delim != token::Brace {
                 self.expect(&token::Semi)?
             }
@@ -1448,10 +1428,7 @@ pub fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
             let path = self.parse_path(PathStyle::Type)?;
             if self.eat(&token::Not) {
                 // MACRO INVOCATION
-                let delim = self.expect_open_delim()?;
-                let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
-                                                SeqSep::none(),
-                                                |p| p.parse_token_tree())?;
+                let (_, tts) = self.expect_delimited_token_tree()?;
                 let hi = self.span.hi;
                 TyKind::Mac(spanned(lo, hi, Mac_ { path: path, tts: tts }))
             } else {
@@ -2045,13 +2022,12 @@ pub fn mk_lit_u32(&mut self, i: u32, attrs: ThinVec<Attribute>) -> P<Expr> {
         })
     }
 
-    fn expect_open_delim(&mut self) -> PResult<'a, token::DelimToken> {
-        self.expected_tokens.push(TokenType::Token(token::Gt));
+    fn expect_delimited_token_tree(&mut self) -> PResult<'a, (token::DelimToken, Vec<TokenTree>)> {
         match self.token {
-            token::OpenDelim(delim) => {
-                self.bump();
-                Ok(delim)
-            },
+            token::OpenDelim(delim) => self.parse_token_tree().map(|tree| match tree {
+                TokenTree::Delimited(_, delimited) => (delim, delimited.tts.clone()),
+                _ => unreachable!(),
+            }),
             _ => Err(self.fatal("expected open delimiter")),
         }
     }
@@ -2261,10 +2237,7 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
                     // `!`, as an operator, is prefix, so we know this isn't that
                     if self.eat(&token::Not) {
                         // MACRO INVOCATION expression
-                        let delim = self.expect_open_delim()?;
-                        let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
-                                                        SeqSep::none(),
-                                                        |p| p.parse_token_tree())?;
+                        let (_, tts) = self.expect_delimited_token_tree()?;
                         let hi = self.prev_span.hi;
                         return Ok(self.mk_mac_expr(lo, hi, Mac_ { path: pth, tts: tts }, attrs));
                     }
@@ -2586,139 +2559,22 @@ fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: BytePos) -> PResult<
         return Ok(e);
     }
 
-    // Parse unquoted tokens after a `$` in a token tree
-    fn parse_unquoted(&mut self) -> PResult<'a, TokenTree> {
-        let mut sp = self.span;
-        let name = match self.token {
-            token::Dollar => {
-                self.bump();
-
-                if self.token == token::OpenDelim(token::Paren) {
-                    let Spanned { node: seq, span: seq_span } = self.parse_seq(
-                        &token::OpenDelim(token::Paren),
-                        &token::CloseDelim(token::Paren),
-                        SeqSep::none(),
-                        |p| p.parse_token_tree()
-                    )?;
-                    let (sep, repeat) = self.parse_sep_and_kleene_op()?;
-                    let name_num = macro_parser::count_names(&seq);
-                    return Ok(TokenTree::Sequence(mk_sp(sp.lo, seq_span.hi),
-                                      Rc::new(SequenceRepetition {
-                                          tts: seq,
-                                          separator: sep,
-                                          op: repeat,
-                                          num_captures: name_num
-                                      })));
-                } else if self.token.is_keyword(keywords::Crate) {
-                    let ident = match self.token {
-                        token::Ident(id) => ast::Ident { name: Symbol::intern("$crate"), ..id },
-                        _ => unreachable!(),
-                    };
-                    self.bump();
-                    return Ok(TokenTree::Token(sp, token::Ident(ident)));
-                } else {
-                    sp = mk_sp(sp.lo, self.span.hi);
-                    self.parse_ident().unwrap_or_else(|mut e| {
-                        e.emit();
-                        keywords::Invalid.ident()
-                    })
-                }
-            }
-            token::SubstNt(name) => {
-                self.bump();
-                name
-            }
-            _ => unreachable!()
-        };
-        // continue by trying to parse the `:ident` after `$name`
-        if self.token == token::Colon &&
-                self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) {
-            self.bump();
-            sp = mk_sp(sp.lo, self.span.hi);
-            let nt_kind = self.parse_ident()?;
-            Ok(TokenTree::Token(sp, MatchNt(name, nt_kind)))
-        } else {
-            Ok(TokenTree::Token(sp, SubstNt(name)))
-        }
-    }
-
     pub fn check_unknown_macro_variable(&mut self) {
-        if self.quote_depth == 0 && !self.parsing_token_tree {
-            match self.token {
-                token::SubstNt(name) =>
-                    self.fatal(&format!("unknown macro variable `{}`", name)).emit(),
-                _ => {}
-            }
-        }
-    }
-
-    /// Parse an optional separator followed by a Kleene-style
-    /// repetition token (+ or *).
-    pub fn parse_sep_and_kleene_op(&mut self)
-                                   -> PResult<'a, (Option<token::Token>, tokenstream::KleeneOp)> {
-        fn parse_kleene_op<'a>(parser: &mut Parser<'a>) ->
-          PResult<'a,  Option<tokenstream::KleeneOp>> {
-            match parser.token {
-                token::BinOp(token::Star) => {
-                    parser.bump();
-                    Ok(Some(tokenstream::KleeneOp::ZeroOrMore))
-                },
-                token::BinOp(token::Plus) => {
-                    parser.bump();
-                    Ok(Some(tokenstream::KleeneOp::OneOrMore))
-                },
-                _ => Ok(None)
-            }
-        };
-
-        if let Some(kleene_op) = parse_kleene_op(self)? {
-            return Ok((None, kleene_op));
-        }
-
-        let separator = match self.token {
-            token::CloseDelim(..) => None,
-            _ => Some(self.bump_and_get()),
-        };
-        match parse_kleene_op(self)? {
-            Some(zerok) => Ok((separator, zerok)),
-            None => return Err(self.fatal("expected `*` or `+`"))
+        if let token::SubstNt(name) = self.token {
+            self.fatal(&format!("unknown macro variable `{}`", name)).emit()
         }
     }
 
     /// parse a single token tree from the input.
     pub fn parse_token_tree(&mut self) -> PResult<'a, TokenTree> {
-        // FIXME #6994: currently, this is too eager. It
-        // parses token trees but also identifies TokenType::Sequence's
-        // and token::SubstNt's; it's too early to know yet
-        // whether something will be a nonterminal or a seq
-        // yet.
         match self.token {
-            token::OpenDelim(delim) => {
-                if self.quote_depth == 0 && self.tts.last().map(|&(_, i)| i == 1).unwrap_or(false) {
-                    let tt = self.tts.pop().unwrap().0;
-                    self.bump();
-                    return Ok(tt);
-                }
-
-                let parsing_token_tree = ::std::mem::replace(&mut self.parsing_token_tree, true);
-                let lo = self.span.lo;
-                self.bump();
-                let tts = self.parse_seq_to_before_tokens(&[&token::CloseDelim(token::Brace),
-                                                            &token::CloseDelim(token::Paren),
-                                                            &token::CloseDelim(token::Bracket)],
-                                                          SeqSep::none(),
-                                                          |p| p.parse_token_tree(),
-                                                          |mut e| e.emit());
-                self.parsing_token_tree = parsing_token_tree;
+            token::OpenDelim(..) => {
+                let tt = self.tts.pop().unwrap().0;
+                self.span = tt.span();
                 self.bump();
-
-                Ok(TokenTree::Delimited(Span { lo: lo, ..self.prev_span }, Rc::new(Delimited {
-                    delim: delim,
-                    tts: tts,
-                })))
+                return Ok(tt);
             },
-            token::CloseDelim(..) | token::Eof => Ok(TokenTree::Token(self.span, token::Eof)),
-            token::Dollar | token::SubstNt(..) if self.quote_depth > 0 => self.parse_unquoted(),
+            token::CloseDelim(_) | token::Eof => unreachable!(),
             _ => Ok(TokenTree::Token(self.span, self.bump_and_get())),
         }
     }
@@ -3528,10 +3384,7 @@ pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
                     token::Not if qself.is_none() => {
                         // Parse macro invocation
                         self.bump();
-                        let delim = self.expect_open_delim()?;
-                        let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
-                                                        SeqSep::none(),
-                                                        |p| p.parse_token_tree())?;
+                        let (_, tts) = self.expect_delimited_token_tree()?;
                         let mac = spanned(lo, self.prev_span.hi, Mac_ { path: path, tts: tts });
                         pat = PatKind::Mac(mac);
                     }
@@ -3831,12 +3684,7 @@ fn parse_stmt_without_recovery(&mut self,
                 },
             };
 
-            let tts = self.parse_unspanned_seq(
-                &token::OpenDelim(delim),
-                &token::CloseDelim(delim),
-                SeqSep::none(),
-                |p| p.parse_token_tree()
-            )?;
+            let (_, tts) = self.expect_delimited_token_tree()?;
             let hi = self.prev_span.hi;
 
             let style = if delim == token::Brace {
@@ -4744,10 +4592,7 @@ fn parse_impl_method(&mut self, vis: &Visibility)
             self.expect(&token::Not)?;
 
             // eat a matched-delimiter token tree:
-            let delim = self.expect_open_delim()?;
-            let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
-                                            SeqSep::none(),
-                                            |p| p.parse_token_tree())?;
+            let (delim, tts) = self.expect_delimited_token_tree()?;
             if delim != token::Brace {
                 self.expect(&token::Semi)?
             }
@@ -5893,10 +5738,7 @@ fn parse_macro_use_or_failure(
                 keywords::Invalid.ident() // no special identifier
             };
             // eat a matched-delimiter token tree:
-            let delim = self.expect_open_delim()?;
-            let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
-                                            SeqSep::none(),
-                                            |p| p.parse_token_tree())?;
+            let (delim, tts) = self.expect_delimited_token_tree()?;
             if delim != token::Brace {
                 if !self.eat(&token::Semi) {
                     let prev_span = self.prev_span;
index 0f0c6d0ca83f5f01a333de4f542a9755f7966786..5b65aac92b81c2d28ad6efe19d6ba38e1d0c59bc 100644 (file)
@@ -50,8 +50,8 @@ pub enum DelimToken {
 }
 
 impl DelimToken {
-    pub fn len(&self) -> u32 {
-        if *self == NoDelim { 0 } else { 1 }
+    pub fn len(self) -> usize {
+        if self == NoDelim { 0 } else { 1 }
     }
 }
 
@@ -152,9 +152,6 @@ pub enum Token {
     // Can be expanded into several tokens.
     /// Doc comment
     DocComment(ast::Name),
-    // In left-hand-sides of MBE macros:
-    /// Parse a nonterminal (name to bind, name of NT)
-    MatchNt(ast::Ident, ast::Ident),
     // In right-hand-sides of MBE macros:
     /// A syntactic variable that will be filled in by macro expansion.
     SubstNt(ast::Ident),
index f8f1820d0b97ea47f3f566e49d877c8c13c54ae8..ec962d03458d1753c905e7cffd90269efb092f7d 100644 (file)
@@ -271,7 +271,6 @@ pub fn token_to_string(tok: &Token) -> String {
         /* Other */
         token::DocComment(s)        => s.to_string(),
         token::SubstNt(s)           => format!("${}", s),
-        token::MatchNt(s, t)        => format!("${}:{}", s, t),
         token::Eof                  => "<eof>".to_string(),
         token::Whitespace           => " ".to_string(),
         token::Comment              => "/* */".to_string(),
@@ -1475,20 +1474,6 @@ pub fn print_tt(&mut self, tt: &tokenstream::TokenTree) -> io::Result<()> {
                 space(&mut self.s)?;
                 word(&mut self.s, &token_to_string(&delimed.close_token()))
             },
-            TokenTree::Sequence(_, ref seq) => {
-                word(&mut self.s, "$(")?;
-                for tt_elt in &seq.tts {
-                    self.print_tt(tt_elt)?;
-                }
-                word(&mut self.s, ")")?;
-                if let Some(ref tk) = seq.separator {
-                    word(&mut self.s, &token_to_string(tk))?;
-                }
-                match seq.op {
-                    tokenstream::KleeneOp::ZeroOrMore => word(&mut self.s, "*"),
-                    tokenstream::KleeneOp::OneOrMore => word(&mut self.s, "+"),
-                }
-            }
         }
     }
 
index 86b0fcebeb21ecf0d37548bf007e12ea3d4c378b..666540467213326d13bc18a0ac7a2691793897e6 100644 (file)
@@ -12,9 +12,7 @@
 //!
 //! TokenStreams represent syntactic objects before they are converted into ASTs.
 //! A `TokenStream` is, roughly speaking, a sequence (eg stream) of `TokenTree`s,
-//! which are themselves either a single Token, a Delimited subsequence of tokens,
-//! or a SequenceRepetition specifier (for the purpose of sequence generation during macro
-//! expansion).
+//! which are themselves a single `Token` or a `Delimited` subsequence of tokens.
 //!
 //! ## Ownership
 //! TokenStreams are persistent data structures constructed as ropes with reference
 use syntax_pos::{BytePos, Span, DUMMY_SP};
 use codemap::Spanned;
 use ext::base;
-use ext::tt::macro_parser;
+use ext::tt::{macro_parser, quoted};
 use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
 use parse::{self, Directory};
-use parse::token::{self, Token, Lit, Nonterminal};
+use parse::token::{self, Token, Lit};
 use print::pprust;
 use serialize::{Decoder, Decodable, Encoder, Encodable};
 use symbol::Symbol;
@@ -64,7 +62,7 @@ pub fn close_token(&self) -> token::Token {
     pub fn open_tt(&self, span: Span) -> TokenTree {
         let open_span = match span {
             DUMMY_SP => DUMMY_SP,
-            _ => Span { hi: span.lo + BytePos(self.delim.len()), ..span },
+            _ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span },
         };
         TokenTree::Token(open_span, self.open_token())
     }
@@ -73,7 +71,7 @@ pub fn open_tt(&self, span: Span) -> TokenTree {
     pub fn close_tt(&self, span: Span) -> TokenTree {
         let close_span = match span {
             DUMMY_SP => DUMMY_SP,
-            _ => Span { lo: span.hi - BytePos(self.delim.len()), ..span },
+            _ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span },
         };
         TokenTree::Token(close_span, self.close_token())
     }
@@ -84,27 +82,6 @@ pub fn subtrees(&self) -> &[TokenTree] {
     }
 }
 
-/// A sequence of token trees
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct SequenceRepetition {
-    /// The sequence of token trees
-    pub tts: Vec<TokenTree>,
-    /// The optional separator
-    pub separator: Option<token::Token>,
-    /// Whether the sequence can be repeated zero (*), or one or more times (+)
-    pub op: KleeneOp,
-    /// The number of `MatchNt`s that appear in the sequence (and subsequences)
-    pub num_captures: usize,
-}
-
-/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star)
-/// for token sequences.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum KleeneOp {
-    ZeroOrMore,
-    OneOrMore,
-}
-
 /// When the main rust parser encounters a syntax-extension invocation, it
 /// parses the arguments to the invocation as a token-tree. This is a very
 /// loose structure, such that all sorts of different AST-fragments can
@@ -123,10 +100,6 @@ pub enum TokenTree {
     Token(Span, token::Token),
     /// A delimited sequence of token trees
     Delimited(Span, Rc<Delimited>),
-
-    // This only makes sense in MBE macros.
-    /// A kleene-style repetition sequence with a span
-    Sequence(Span, Rc<SequenceRepetition>),
 }
 
 impl TokenTree {
@@ -138,15 +111,10 @@ pub fn len(&self) -> usize {
                     AttrStyle::Inner => 3,
                 }
             }
-            TokenTree::Token(_, token::Interpolated(ref nt)) => {
-                if let Nonterminal::NtTT(..) = **nt { 1 } else { 0 }
-            },
-            TokenTree::Token(_, token::MatchNt(..)) => 3,
             TokenTree::Delimited(_, ref delimed) => match delimed.delim {
                 token::NoDelim => delimed.tts.len(),
                 _ => delimed.tts.len() + 2,
             },
-            TokenTree::Sequence(_, ref seq) => seq.tts.len(),
             TokenTree::Token(..) => 0,
         }
     }
@@ -197,30 +165,12 @@ pub fn get_tt(&self, index: usize) -> TokenTree {
                 }
                 delimed.tts[index - 1].clone()
             }
-            (&TokenTree::Token(sp, token::MatchNt(name, kind)), _) => {
-                let v = [TokenTree::Token(sp, token::SubstNt(name)),
-                         TokenTree::Token(sp, token::Colon),
-                         TokenTree::Token(sp, token::Ident(kind))];
-                v[index].clone()
-            }
-            (&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(),
             _ => panic!("Cannot expand a token tree"),
         }
     }
 
-    /// Returns the `Span` corresponding to this token tree.
-    pub fn get_span(&self) -> Span {
-        match *self {
-            TokenTree::Token(span, _) => span,
-            TokenTree::Delimited(span, _) => span,
-            TokenTree::Sequence(span, _) => span,
-        }
-    }
-
     /// Use this token tree as a matcher to parse given tts.
-    pub fn parse(cx: &base::ExtCtxt,
-                 mtch: &[TokenTree],
-                 tts: &[TokenTree])
+    pub fn parse(cx: &base::ExtCtxt, mtch: &[quoted::TokenTree], tts: &[TokenTree])
                  -> macro_parser::NamedParseResult {
         // `None` is because we're not interpolating
         let directory = Directory {
@@ -252,9 +202,7 @@ pub fn eq_unspanned(&self, other: &TokenTree) -> bool {
     /// Retrieve the TokenTree's span.
     pub fn span(&self) -> Span {
         match *self {
-            TokenTree::Token(sp, _) |
-            TokenTree::Delimited(sp, _) |
-            TokenTree::Sequence(sp, _) => sp,
+            TokenTree::Token(sp, _) | TokenTree::Delimited(sp, _) => sp,
         }
     }
 
index bfab7a250c67f275b582f58356b6240995e26306..013632141dee69b27baf174a1abfe5a62b9fb973 100644 (file)
@@ -68,6 +68,9 @@ fn visit_expr(&mut self, ex: &'ast Expr) { walk_expr(self, ex) }
     fn visit_expr_post(&mut self, _ex: &'ast Expr) { }
     fn visit_ty(&mut self, t: &'ast Ty) { walk_ty(self, t) }
     fn visit_generics(&mut self, g: &'ast Generics) { walk_generics(self, g) }
+    fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
+        walk_where_predicate(self, p)
+    }
     fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl, s: Span, _: NodeId) {
         walk_fn(self, fk, fd, s)
     }
@@ -488,28 +491,30 @@ pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics
         walk_list!(visitor, visit_attribute, &*param.attrs);
     }
     walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
-    for predicate in &generics.where_clause.predicates {
-        match *predicate {
-            WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
-                                                               ref bounds,
-                                                               ref bound_lifetimes,
-                                                               ..}) => {
-                visitor.visit_ty(bounded_ty);
-                walk_list!(visitor, visit_ty_param_bound, bounds);
-                walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
-            }
-            WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
-                                                                 ref bounds,
-                                                                 ..}) => {
-                visitor.visit_lifetime(lifetime);
-                walk_list!(visitor, visit_lifetime, bounds);
-            }
-            WherePredicate::EqPredicate(WhereEqPredicate{ref lhs_ty,
-                                                         ref rhs_ty,
-                                                         ..}) => {
-                visitor.visit_ty(lhs_ty);
-                visitor.visit_ty(rhs_ty);
-            }
+    walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates);
+}
+
+pub fn walk_where_predicate<'a, V: Visitor<'a>>(visitor: &mut V, predicate: &'a WherePredicate) {
+    match *predicate {
+        WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
+                                                           ref bounds,
+                                                           ref bound_lifetimes,
+                                                           ..}) => {
+            visitor.visit_ty(bounded_ty);
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+            walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
+        }
+        WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
+                                                             ref bounds,
+                                                             ..}) => {
+            visitor.visit_lifetime(lifetime);
+            walk_list!(visitor, visit_lifetime, bounds);
+        }
+        WherePredicate::EqPredicate(WhereEqPredicate{ref lhs_ty,
+                                                     ref rhs_ty,
+                                                     ..}) => {
+            visitor.visit_ty(lhs_ty);
+            visitor.visit_ty(rhs_ty);
         }
     }
 }
index ce64aef516f493eaf106a03fdfc4575ef3ad1ef9..fe492bd7fc849bbaa46cce06734570adefb8cfda 100644 (file)
@@ -773,7 +773,7 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> &
     for a in type_attrs {
         for r in &attr::find_repr_attrs(diagnostic, a) {
             repr_type_name = match *r {
-                attr::ReprAny | attr::ReprPacked | attr::ReprSimd => continue,
+                attr::ReprPacked | attr::ReprSimd => continue,
                 attr::ReprExtern => "i32",
 
                 attr::ReprInt(attr::SignedInt(ast::IntTy::Is)) => "isize",
index 7533171b08556df082f2fcabfd27dbcb11e3e3d0..f92cde4019f67b06e9147c6264badd7e4e41cfac 100644 (file)
@@ -79,7 +79,6 @@ macro_rules! register {
             quote_pat: expand_quote_pat,
             quote_arm: expand_quote_arm,
             quote_stmt: expand_quote_stmt,
-            quote_matcher: expand_quote_matcher,
             quote_attr: expand_quote_attr,
             quote_arg: expand_quote_arg,
             quote_block: expand_quote_block,
index b454628acb1c09bf95b0dabcd04ed18411daf1f8..f60e5824db9627cc67e203060a8409ab58afee7f 100644 (file)
@@ -56,3 +56,38 @@ fn expand<'cx>(&self,
         }
     }
 }
+
+pub struct BangProcMacro {
+    pub inner: fn(TsShim) -> TsShim,
+}
+
+impl base::ProcMacro for BangProcMacro {
+    fn expand<'cx>(&self,
+                   ecx: &'cx mut ExtCtxt,
+                   span: Span,
+                   input: TokenStream)
+                   -> TokenStream {
+        let input = __internal::token_stream_wrap(input);
+
+        let res = __internal::set_parse_sess(&ecx.parse_sess, || {
+            panic::catch_unwind(panic::AssertUnwindSafe(|| (self.inner)(input)))
+        });
+
+        match res {
+            Ok(stream) => __internal::token_stream_inner(stream),
+            Err(e) => {
+                let msg = "proc macro panicked";
+                let mut err = ecx.struct_span_fatal(span, msg);
+                if let Some(s) = e.downcast_ref::<String>() {
+                    err.help(&format!("message: {}", s));
+                }
+                if let Some(s) = e.downcast_ref::<&'static str>() {
+                    err.help(&format!("message: {}", s));
+                }
+
+                err.emit();
+                panic!(FatalError);
+            }
+        }
+    }
+}
index 325f09a83ddab80860afd3524f7937ab23cd2e7c..9c96ad547e1ae33254dc8034826b68748db50bc9 100644 (file)
@@ -27,6 +27,9 @@
 
 use deriving;
 
+const PROC_MACRO_KINDS: [&'static str; 3] =
+    ["proc_macro_derive", "proc_macro_attribute", "proc_macro"];
+
 struct ProcMacroDerive {
     trait_name: ast::Name,
     function_name: Ident,
@@ -34,14 +37,15 @@ struct ProcMacroDerive {
     attrs: Vec<ast::Name>,
 }
 
-struct AttrProcMacro {
+struct ProcMacroDef {
     function_name: Ident,
     span: Span,
 }
 
 struct CollectProcMacros<'a> {
     derives: Vec<ProcMacroDerive>,
-    attr_macros: Vec<AttrProcMacro>,
+    attr_macros: Vec<ProcMacroDef>,
+    bang_macros: Vec<ProcMacroDef>,
     in_root: bool,
     handler: &'a errors::Handler,
     is_proc_macro_crate: bool,
@@ -58,17 +62,18 @@ pub fn modify(sess: &ParseSess,
     let ecfg = ExpansionConfig::default("proc_macro".to_string());
     let mut cx = ExtCtxt::new(sess, ecfg, resolver);
 
-    let (derives, attr_macros) = {
+    let (derives, attr_macros, bang_macros) = {
         let mut collect = CollectProcMacros {
             derives: Vec::new(),
             attr_macros: Vec::new(),
+            bang_macros: Vec::new(),
             in_root: true,
             handler: handler,
             is_proc_macro_crate: is_proc_macro_crate,
             is_test_crate: is_test_crate,
         };
         visit::walk_crate(&mut collect, &krate);
-        (collect.derives, collect.attr_macros)
+        (collect.derives, collect.attr_macros, collect.bang_macros)
     };
 
     if !is_proc_macro_crate {
@@ -83,7 +88,7 @@ pub fn modify(sess: &ParseSess,
         return krate;
     }
 
-    krate.module.items.push(mk_registrar(&mut cx, &derives, &attr_macros));
+    krate.module.items.push(mk_registrar(&mut cx, &derives, &attr_macros, &bang_macros));
 
     if krate.exported_macros.len() > 0 {
         handler.err("cannot export macro_rules! macros from a `proc-macro` \
@@ -93,6 +98,10 @@ pub fn modify(sess: &ParseSess,
     return krate
 }
 
+fn is_proc_macro_attr(attr: &ast::Attribute) -> bool {
+    PROC_MACRO_KINDS.iter().any(|kind| attr.check_name(kind))
+}
+
 impl<'a> CollectProcMacros<'a> {
     fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) {
         if self.is_proc_macro_crate &&
@@ -196,12 +205,12 @@ fn collect_custom_derive(&mut self, item: &'a ast::Item, attr: &'a ast::Attribut
     fn collect_attr_proc_macro(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) {
         if let Some(_) = attr.meta_item_list() {
             self.handler.span_err(attr.span, "`#[proc_macro_attribute]` attribute
-                cannot contain any meta items");
+                does not take any arguments");
             return;
         }
 
         if self.in_root && item.vis == ast::Visibility::Public {
-            self.attr_macros.push(AttrProcMacro {
+            self.attr_macros.push(ProcMacroDef {
                 span: item.span,
                 function_name: item.ident,
             });
@@ -215,6 +224,29 @@ fn collect_attr_proc_macro(&mut self, item: &'a ast::Item, attr: &'a ast::Attrib
             self.handler.span_err(item.span, msg);
         }
     }
+
+    fn collect_bang_proc_macro(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) {
+        if let Some(_) = attr.meta_item_list() {
+            self.handler.span_err(attr.span, "`#[proc_macro]` attribute
+                does not take any arguments");
+            return;
+        }
+
+        if self.in_root && item.vis == ast::Visibility::Public {
+            self.bang_macros.push(ProcMacroDef {
+                span: item.span,
+                function_name: item.ident,
+            });
+        } else {
+            let msg = if !self.in_root {
+                "functions tagged with `#[proc_macro]` must \
+                 currently reside in the root of the crate"
+            } else {
+                "functions tagged with `#[proc_macro]` must be `pub`"
+            };
+            self.handler.span_err(item.span, msg);
+        }
+    }
 }
 
 impl<'a> Visitor<'a> for CollectProcMacros<'a> {
@@ -232,7 +264,7 @@ fn visit_item(&mut self, item: &'a ast::Item) {
         let mut found_attr: Option<&'a ast::Attribute> = None;
 
         for attr in &item.attrs {
-            if attr.check_name("proc_macro_derive") || attr.check_name("proc_macro_attribute") {
+            if is_proc_macro_attr(&attr) {
                 if let Some(prev_attr) = found_attr {
                     let msg = if attr.name() == prev_attr.name() {
                         format!("Only one `#[{}]` attribute is allowed on any given function",
@@ -285,6 +317,8 @@ fn visit_item(&mut self, item: &'a ast::Item) {
             self.collect_custom_derive(item, attr);
         } else if attr.check_name("proc_macro_attribute") {
             self.collect_attr_proc_macro(item, attr);
+        } else if attr.check_name("proc_macro") {
+            self.collect_bang_proc_macro(item, attr);
         };
 
         visit::walk_item(self, item);
@@ -320,7 +354,8 @@ fn visit_mac(&mut self, mac: &ast::Mac) {
 //      }
 fn mk_registrar(cx: &mut ExtCtxt,
                 custom_derives: &[ProcMacroDerive],
-                custom_attrs: &[AttrProcMacro]) -> P<ast::Item> {
+                custom_attrs: &[ProcMacroDef],
+                custom_macros: &[ProcMacroDef]) -> P<ast::Item> {
     let eid = cx.codemap().record_expansion(ExpnInfo {
         call_site: DUMMY_SP,
         callee: NameAndSpan {
@@ -342,6 +377,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
     let registrar = Ident::from_str("registrar");
     let register_custom_derive = Ident::from_str("register_custom_derive");
     let register_attr_proc_macro = Ident::from_str("register_attr_proc_macro");
+    let register_bang_proc_macro = Ident::from_str("register_bang_proc_macro");
 
     let mut stmts = custom_derives.iter().map(|cd| {
         let path = cx.path_global(cd.span, vec![cd.function_name]);
@@ -371,6 +407,18 @@ fn mk_registrar(cx: &mut ExtCtxt,
                                   vec![registrar, name, cx.expr_path(path)]))
     }));
 
+    stmts.extend(custom_macros.iter().map(|cm| {
+        let name = cx.expr_str(cm.span, cm.function_name.name);
+        let path = cx.path_global(cm.span, vec![cm.function_name]);
+        let registrar = cx.expr_ident(cm.span, registrar);
+
+        let ufcs_path = cx.path(span,
+                                vec![proc_macro, __internal, registry, register_bang_proc_macro]);
+
+        cx.stmt_expr(cx.expr_call(span, cx.expr_path(ufcs_path),
+                                  vec![registrar, name, cx.expr_path(path)]))
+    }));
+
     let path = cx.path(span, vec![proc_macro, __internal, registry]);
     let registrar_path = cx.ty_path(path);
     let arg_ty = cx.ty_rptr(span, registrar_path, None, ast::Mutability::Mutable);
index 112bf61cf97222aec886f9b20fee335e46365818..5fdb0aa0641a0057c0dacaa47900cd8b7bdaf2fa 100644 (file)
@@ -106,7 +106,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq)]
-enum NamePadding {
+pub enum NamePadding {
     PadNone,
     PadOnRight,
 }
@@ -950,7 +950,7 @@ fn stdout_isatty() -> bool {
 }
 
 #[derive(Clone)]
-enum TestEvent {
+pub enum TestEvent {
     TeFiltered(Vec<TestDesc>),
     TeWait(TestDesc, NamePadding),
     TeResult(TestDesc, TestResult, Vec<u8>),
@@ -960,7 +960,7 @@ enum TestEvent {
 pub type MonitorMsg = (TestDesc, TestResult, Vec<u8>);
 
 
-fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()>
+pub fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()>
     where F: FnMut(TestEvent) -> io::Result<()>
 {
     use std::collections::HashMap;
index 993fb703e51ddc79e095adc8baf4abe35e656db6..077d57a9da389f895bc6b20f3fee50dcdc267b62 100644 (file)
@@ -264,8 +264,8 @@ fn quartiles(&self) -> (f64, f64, f64) {
         local_sort(&mut tmp);
         let first = 25f64;
         let a = percentile_of_sorted(&tmp, first);
-        let secound = 50f64;
-        let b = percentile_of_sorted(&tmp, secound);
+        let second = 50f64;
+        let b = percentile_of_sorted(&tmp, second);
         let third = 75f64;
         let c = percentile_of_sorted(&tmp, third);
         (a, b, c)
index 7fb58373251a515be8a104da34b7af5829918597..e22f6702672986091766db4b5f7aadd6ddce784e 100644 (file)
@@ -18,7 +18,7 @@ macro_rules! cfg_if {
 use libc::{c_int, c_void, uintptr_t};
 
 #[repr(C)]
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Debug, Copy, Clone, PartialEq)]
 pub enum _Unwind_Reason_Code {
     _URC_NO_REASON = 0,
     _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
diff --git a/src/test/COMPILER_TESTS.md b/src/test/COMPILER_TESTS.md
new file mode 100644 (file)
index 0000000..58df1aa
--- /dev/null
@@ -0,0 +1,88 @@
+# Compiler Test Documentation
+
+In the Rust project, we use a special set of commands embedded in
+comments to test the Rust compiler. There are two groups of commands:
+
+1. Header commands
+2. Error info commands
+
+Both types of commands are inside comments, but header commands should
+be in a comment before any code.
+
+## Summary of Error Info Commands
+
+Error commands specify something about certain lines of the
+program. They tell the test what kind of error and what message you
+are expecting.
+
+* `~`: Associates the following error level and message with the
+  current line
+* `~|`: Associates the following error level and message with the same
+  line as the previous comment
+* `~^`: Associates the following error level and message with the
+  previous line. Each caret (`^`) that you add adds a line to this, so
+  `~^^^^^^^` is seven lines up.
+
+The error levels that you can have are:
+
+1. `ERROR`
+2. `WARNING`
+3. `NOTE`
+4. `HELP` and `SUGGESTION`*
+
+\* **Note**: `SUGGESTION` must follow immediately after `HELP`.
+
+## Summary of Header Commands
+
+Header commands specify something about the entire test file as a
+whole, instead of just a few lines inside the test.
+
+* `ignore-X` where `X` is an architecture, OS or stage will ignore the test accordingly
+* `ignore-pretty` will not compile the pretty-printed test (this is done to test the pretty-printer, but might not always work)
+* `ignore-test` always ignores the test
+* `ignore-lldb` and `ignore-gdb` will skip the debuginfo tests
+* `min-{gdb,lldb}-version`
+* `should-fail` indicates that the test should fail; used for "meta testing",
+  where we test the compiletest program itself to check that it will generate
+  errors in appropriate scenarios. This header is ignored for pretty-printer tests.
+* `gate-test-X` where `X` is a feature marks the test as "gate test" for feature X.
+  Such tests are supposed to ensure that the compiler errors when usage of a gated
+  feature is attempted without the proper `#![feature(X)]` tag.
+  Each unstable lang feature is required to have a gate test.
+
+## Revisions
+
+Certain classes of tests support "revisions" (as of the time of this
+writing, this includes run-pass, compile-fail, run-fail, and
+incremental, though incremental tests are somewhat
+different). Revisions allow a single test file to be used for multiple
+tests. This is done by adding a special header at the top of the file:
+
+```
+// revisions: foo bar baz
+```
+
+This will result in the test being compiled (and tested) three times,
+once with `--cfg foo`, once with `--cfg bar`, and once with `--cfg
+baz`. You can therefore use `#[cfg(foo)]` etc within the test to tweak
+each of these results.
+
+You can also customize headers and expected error messages to a particular
+revision. To do this, add `[foo]` (or `bar`, `baz`, etc) after the `//`
+comment, like so:
+
+```
+// A flag to pass in only for cfg `foo`:
+//[foo]compile-flags: -Z verbose
+
+#[cfg(foo)]
+fn test_foo() {
+    let x: usize = 32_u32; //[foo]~ ERROR mismatched types
+}
+```
+
+Note that not all headers have meaning when customized to a revision.
+For example, the `ignore-test` header (and all "ignore" headers)
+currently only apply to the test as a whole, not to particular
+revisions. The only headers that are intended to really work when
+customized to a revision are error patterns and compiler flags.
diff --git a/src/test/codegen/abi-x86-interrupt.rs b/src/test/codegen/abi-x86-interrupt.rs
new file mode 100644 (file)
index 0000000..838cd4b
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Checks if the correct annotation for the x86-interrupt ABI is passed to
+// llvm. Also checks that the abi_x86_interrupt feature gate allows usage
+// of the x86-interrupt abi.
+
+// ignore-arm
+// ignore-aarch64
+// min-llvm-version 3.8
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(abi_x86_interrupt)]
+
+// CHECK: define x86_intrcc i64 @has_x86_interrupt_abi
+#[no_mangle]
+pub extern "x86-interrupt" fn has_x86_interrupt_abi(a: i64) -> i64 {
+    a * 2
+}
index c373cdb76c5c73a9d6620dc999c743479b9fb2e8..76313b158ab1109422938a7368706a81838b5d9f 100644 (file)
@@ -121,13 +121,13 @@ pub fn unsafe_slice(_: &[UnsafeInner]) {
 fn str(_: &[u8]) {
 }
 
-// CHECK: @trait_borrow(i8* nonnull, void (i8*)** nonnull)
+// CHECK: @trait_borrow(i8* nonnull, void (i8*)** noalias nonnull readonly)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 fn trait_borrow(_: &Drop) {
 }
 
-// CHECK: @trait_box(i8* noalias nonnull, void (i8*)** nonnull)
+// CHECK: @trait_box(i8* noalias nonnull, void (i8*)** noalias nonnull readonly)
 #[no_mangle]
 fn trait_box(_: Box<Drop>) {
 }
index 726af9864b48215022022f436320d276c500a516..63e1c6f16b3e6be4b8ac4727833ef6f6cf182d9c 100644 (file)
@@ -54,8 +54,6 @@ pub fn main() {
     //~^ ERROR cannot find macro `quote_arm!` in this scope
     let x = quote_stmt!(ecx, 3);
     //~^ ERROR cannot find macro `quote_stmt!` in this scope
-    let x = quote_matcher!(ecx, 3);
-    //~^ ERROR cannot find macro `quote_matcher!` in this scope
     let x = quote_attr!(ecx, 3);
     //~^ ERROR cannot find macro `quote_attr!` in this scope
     let x = quote_arg!(ecx, 3);
diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/bang_proc_macro.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/bang_proc_macro.rs
new file mode 100644 (file)
index 0000000..89ac11b
--- /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.
+
+// force-host
+// no-prefer-dynamic
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn bang_proc_macro(input: TokenStream) -> TokenStream {
+    input
+}
diff --git a/src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs b/src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs
new file mode 100644 (file)
index 0000000..7ecc685
--- /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.
+
+// aux-build:bang_proc_macro.rs
+
+#![feature(proc_macro)]
+
+#[macro_use]
+extern crate bang_proc_macro;
+
+fn main() {
+    bang_proc_macro!(println!("Hello, world!"));
+    //~^ ERROR: procedural macros cannot be imported with `#[macro_use]`
+}
index c9a36920a19e403a27824e3e5eeef6a1000f1e26..e0066dd43be89f13cb3d8ec3a8abf80d302ce5a6 100644 (file)
@@ -11,6 +11,7 @@
 // aux-build:derive-foo.rs
 // aux-build:derive-clona.rs
 // aux-build:attr_proc_macro.rs
+// aux-build:bang_proc_macro.rs
 
 #![feature(proc_macro)]
 
 #[macro_use]
 extern crate derive_clona;
 extern crate attr_proc_macro;
+extern crate bang_proc_macro;
 
 use attr_proc_macro::attr_proc_macro;
+use bang_proc_macro::bang_proc_macro;
 
-#[derive(FooWithLongNam)]
-//~^ ERROR cannot find derive macro `FooWithLongNam` in this scope
+macro_rules! FooWithLongNam {
+    () => {}
+}
+
+macro_rules! attr_proc_mac {
+    () => {}
+}
+
+#[derive(FooWithLongNan)]
+//~^ ERROR cannot find derive macro `FooWithLongNan` in this scope
 //~^^ HELP did you mean `FooWithLongName`?
 struct Foo;
 
 #[attr_proc_macra]
 //~^ ERROR cannot find attribute macro `attr_proc_macra` in this scope
+//~^^ HELP did you mean `attr_proc_macro`?
 struct Bar;
 
+#[FooWithLongNan]
+//~^ ERROR cannot find attribute macro `FooWithLongNan` in this scope
+struct Asdf;
+
 #[derive(Dlone)]
 //~^ ERROR cannot find derive macro `Dlone` in this scope
 //~^^ HELP did you mean `Clone`?
 //~^^ HELP did you mean `Clona`?
 struct B;
 
-fn main() {}
+#[derive(attr_proc_macra)]
+//~^ ERROR cannot find derive macro `attr_proc_macra` in this scope
+struct C;
+
+fn main() {
+    FooWithLongNama!();
+    //~^ ERROR cannot find macro `FooWithLongNama!` in this scope
+    //~^^ HELP did you mean `FooWithLongNam!`?
+
+    attr_proc_macra!();
+    //~^ ERROR cannot find macro `attr_proc_macra!` in this scope
+    //~^^ HELP did you mean `attr_proc_mac!`?
+
+    Dlona!();
+    //~^ ERROR cannot find macro `Dlona!` in this scope
+
+    bang_proc_macrp!();
+    //~^ ERROR cannot find macro `bang_proc_macrp!` in this scope
+    //~^^ HELP did you mean `bang_proc_macro!`?
+}
diff --git a/src/test/compile-fail/E0079.rs b/src/test/compile-fail/E0079.rs
deleted file mode 100644 (file)
index c9b7f54..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.
-
-enum Foo {
-    Q = "32" //~ ERROR E0079
-    //~^ expected 'isize' type
-}
-
-fn main() {
-}
index e12eff72c7f41f7e6de35ade2c315ed6c3321907..9911e093a898036d5fcae44fe656f6add46c2225 100644 (file)
@@ -9,10 +9,10 @@
 // except according to those terms.
 
 enum Enum {
-    P = 3, //~ NOTE first use of `3`
+    P = 3, //~ NOTE first use of `3isize`
     X = 3,
-    //~^ ERROR discriminant value `3` already exists
-    //~| NOTE enum already has `3`
+    //~^ ERROR discriminant value `3isize` already exists
+    //~| NOTE enum already has `3isize`
     Y = 5
 }
 
index 4ba9c3382f35d4792219ac0f5b54f559eefcaf6d..3da00da205fec27e1d827b0a08d613a9ee59fbd4 100644 (file)
@@ -12,6 +12,8 @@ impl Drop for u32 {} //~ ERROR E0117
 //~^ NOTE impl doesn't use types inside crate
 //~| NOTE the impl does not reference any types defined in this crate
 //~| NOTE define and implement a trait or new type instead
+//~| ERROR the Drop trait may only be implemented on structures
+//~| implementing Drop requires a struct
 
 fn main() {
 }
diff --git a/src/test/compile-fail/E0306.rs b/src/test/compile-fail/E0306.rs
deleted file mode 100644 (file)
index 9ffaef7..0000000
+++ /dev/null
@@ -1,24 +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.
-
-const A: [u32; "hello"] = [];
-//~^ ERROR expected `usize` for array length, found string literal [E0306]
-//~| NOTE expected `usize`
-
-const B: [u32; true] = [];
-//~^ ERROR expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
-
-const C: [u32; 0.0] = [];
-//~^ ERROR expected `usize` for array length, found float [E0306]
-//~| NOTE expected `usize`
-
-fn main() {
-}
index cb931329051f981e48c313ef2d389b7cc999e334..145662fd87c9e398881b1a65dcc7d576b2749166 100644 (file)
@@ -13,6 +13,7 @@
 // ignore-aarch64
 // ignore-s390x
 // ignore-emscripten
+// ignore-powerpc
 
 #![feature(asm, rustc_attrs)]
 
index 7ba5beac213407e0d189dbaa46df5b34a0329c41..f0467e75223be992a2e03617299993646d1f89fe 100644 (file)
@@ -10,6 +10,7 @@
 
 // ignore-s390x
 // ignore-emscripten
+// ignore-powerpc
 
 #![feature(asm)]
 
index bafbf625e3517530b535f32f465e70dc1e243e37..37a267535317c2acdbb8bd1f56fdad110a785668 100644 (file)
@@ -13,6 +13,7 @@
 // ignore-aarch64
 // ignore-s390x
 // ignore-emscripten
+// ignore-powerpc
 
 #![feature(asm, rustc_attrs)]
 
index 161c0b977ff0ce871cc3dcef9d19671311d4afa3..3c4a5dcb7b038356947fdcc613734e2cd6884bec 100644 (file)
@@ -10,6 +10,7 @@
 
 // ignore-s390x
 // ignore-emscripten
+// ignore-powerpc
 
 #![feature(asm)]
 
index cb8fb19a7c7f0d915f50cdbd35c4328f1f47d112..acf575c003a7df35acba97b33e1c02138f0b8819 100644 (file)
@@ -10,6 +10,7 @@
 
 // ignore-s390x
 // ignore-emscripten
+// ignore-powerpc
 
 #![feature(asm)]
 
index 42bff4c633aa953f933816d029e90a7bc7b32ab4..bd180f6e5ebd945eaafb86673a8d9f48099fd443 100644 (file)
@@ -10,6 +10,7 @@
 
 // ignore-s390x
 // ignore-emscripten
+// ignore-powerpc
 
 #![feature(asm)]
 
index 0239986f5ad3aef5dfe5886ed2f142bc93c902e1..7f77ae2ec1f10ec4b954b29e780527dead31b99b 100644 (file)
@@ -14,7 +14,8 @@ trait Foo {
     const ID: usize;
 }
 
-const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0080
+const X: [i32; <i32 as Foo>::ID] = [0, 1, 2];
+//~^ ERROR the trait bound `i32: Foo` is not satisfied
 
 fn main() {
     assert_eq!(1, X);
index 7c3f7a1d574f99fea3df47f3b596ba8f4ad3a9e0..7fd9605ef2cdc6323b7177cd822272e9e1e748a0 100644 (file)
@@ -27,8 +27,6 @@ impl Foo for Def {
 pub fn test<A: Foo, B: Foo>() {
     let _array = [4; <A as Foo>::Y];
     //~^ ERROR cannot use an outer type parameter in this context [E0402]
-    //~| ERROR constant evaluation error [E0080]
-    //~| non-constant path in constant
 }
 
 fn main() {
index dcf87d5f0fc44b97585cd070cc9f54ceab7fa4e6..71c7a3965ec3c8c5af96d6211de60b14cf3ca692 100644 (file)
@@ -27,8 +27,6 @@ impl Foo for Def {
 pub fn test<A: Foo, B: Foo>() {
     let _array: [u32; <A as Foo>::Y];
     //~^ ERROR cannot use an outer type parameter in this context [E0402]
-    //~| ERROR constant evaluation error [E0080]
-    //~| non-constant path in constant
 }
 
 fn main() {
diff --git a/src/test/compile-fail/closure-no-fn.rs b/src/test/compile-fail/closure-no-fn.rs
new file mode 100644 (file)
index 0000000..fe179e8
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Ensure that capturing closures are never coerced to fns
+// Especially interesting as non-capturing closures can be.
+
+fn main() {
+    let mut a = 0u8;
+    let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
+    //~^ ERROR mismatched types
+    let b = 0u8;
+    let bar: fn() -> u8 = || { b };
+    //~^ ERROR mismatched types
+    let baz: fn() -> u8 = || { b } as fn() -> u8;
+    //~^ ERROR mismatched types
+    //~^^ ERROR non-scalar cast
+}
index 9f74afbb2b3b5493ba7b30472b627a51e7685f18..aac870293fd5500ae27a04fbf764f2b016d1a026 100644 (file)
@@ -17,6 +17,7 @@
 
 impl<A> Foo for A {
     //~^ ERROR type parameter `A` must be used as the type parameter for some local type
+    //~| ERROR conflicting implementations of trait `trait_impl_conflict::Foo` for type `isize`
 }
 
 fn main() {
index 3d109de76ccd1c21908c0ff5a46dbef64fd0a072..15a80c64f8b0621fcd07d054ba4580a01e914377 100644 (file)
@@ -13,9 +13,9 @@
 trait MyTrait {}
 
 impl MyTrait for .. {}
+//~^ ERROR redundant default implementations of trait `MyTrait`
 
 impl MyTrait for .. {}
-//~^ ERROR redundant default implementations of trait `MyTrait`
 
 trait MySafeTrait {}
 
index 79767e5157b14b34e65a7d341de5c87fa068fb7d..60b5d14d1587a9f9706defd1eb3a56c2b4c169d6 100644 (file)
@@ -27,14 +27,20 @@ impl Sized for TestE {} //~ ERROR E0322
 impl Sized for MyType {} //~ ERROR E0322
 //~^ impl of 'Sized' not allowed
 
-impl Sized for (MyType, MyType) {} //~ ERROR E0117
+impl Sized for (MyType, MyType) {} //~ ERROR E0322
+//~^ impl of 'Sized' not allowed
+//~| ERROR E0117
 
 impl Sized for &'static NotSync {} //~ ERROR E0322
 //~^ impl of 'Sized' not allowed
 
-impl Sized for [MyType] {} //~ ERROR E0117
+impl Sized for [MyType] {} //~ ERROR E0322
+//~^ impl of 'Sized' not allowed
+//~| ERROR E0117
 
-impl Sized for &'static [NotSync] {} //~ ERROR E0117
+impl Sized for &'static [NotSync] {} //~ ERROR E0322
+//~^ impl of 'Sized' not allowed
+//~| ERROR E0117
 
 fn main() {
 }
index b980bc02c85a24fb22a4d7cb0e161768a0b858fa..108b7948dfcc20c981cc9ba88abebca27c909d5b 100644 (file)
@@ -12,8 +12,8 @@
 
 #![feature(const_indexing)]
 
-const FOO: [u32; 3] = [1, 2, 3];
-const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval
+const FOO: [usize; 3] = [1, 2, 3];
+const BAR: usize = FOO[5]; // no error, because the error below occurs before regular const eval
 
 const BLUB: [u32; FOO[4]] = [5, 6];
 //~^ ERROR constant evaluation error [E0080]
diff --git a/src/test/compile-fail/const-block-non-item-statement-2.rs b/src/test/compile-fail/const-block-non-item-statement-2.rs
new file mode 100644 (file)
index 0000000..83166c9
--- /dev/null
@@ -0,0 +1,26 @@
+// 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.
+
+const A: usize = { 1; 2 };
+//~^ ERROR: blocks in constants are limited to items and tail expressions
+
+const B: usize = { { } 2 };
+//~^ ERROR: blocks in constants are limited to items and tail expressions
+
+macro_rules! foo {
+    () => (()) //~ ERROR: blocks in constants are limited to items and tail expressions
+}
+const C: usize = { foo!(); 2 };
+
+const D: usize = { let x = 4; 2 };
+//~^ ERROR: blocks in constants are limited to items and tail expressions
+//~^^ ERROR: blocks in constants are limited to items and tail expressions
+
+pub fn main() {}
index edb85023c9ba78ead594de762b59b4eeeda3ebb2..bdc69c937c63780031f431cef0289674891359c8 100644 (file)
@@ -8,21 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-const A: usize = { 1; 2 };
-//~^ ERROR: blocks in constants are limited to items and tail expressions
-
-const B: usize = { { } 2 };
-//~^ ERROR: blocks in constants are limited to items and tail expressions
-
-macro_rules! foo {
-    () => (()) //~ ERROR: blocks in constants are limited to items and tail expressions
-}
-const C: usize = { foo!(); 2 };
-
-const D: usize = { let x = 4; 2 };
-//~^ ERROR: blocks in constants are limited to items and tail expressions
-//~^^ ERROR: blocks in constants are limited to items and tail expressions
-
 enum Foo {
     Bar = { let x = 1; 3 }
     //~^ ERROR: blocks in constants are limited to items and tail expressions
@@ -33,8 +18,4 @@ enum Foo {
 //~^ ERROR: blocks in constants are limited to items and tail expressions
 //~^^ ERROR: blocks in constants are limited to items and tail expressions
 
-pub fn main() {
-    let _: Array = [0; { let x = 3; 5 }];
-    //~^ ERROR: blocks in constants are limited to items and tail expressions
-    //~^^ ERROR: blocks in constants are limited to items and tail expressions
-}
+pub fn main() {}
index 7e2eabf412d6c2683646b19a0bdb27c4e65c4a21..ff83dd004a257ccb2a9f9b76911bf796d89bd844 100644 (file)
@@ -15,6 +15,8 @@ fn f(x: usize) -> usize {
 }
 
 fn main() {
-    let _ = [0; f(2)]; //~ ERROR constant evaluation error [E0080]
-                       //~| non-constant path in constant expression
+    let _ = [0; f(2)];
+    //~^ ERROR calls in constants are limited to constant functions
+    //~| ERROR constant evaluation error [E0080]
+    //~| non-constant path in constant expression
 }
index 9e7a5ecae105a2b123a51519f20a2944b26bfe6a..02072e9a1a1f6ab5e298a281e6aa16564dc84786 100644 (file)
@@ -20,8 +20,9 @@
 
 const A_I8_T
     : [u32; (i8::MAX as i8 + 1u8) as usize]
-    //~^ ERROR constant evaluation error [E0080]
+    //~^ ERROR mismatched types
     //~| expected i8, found u8
+    //~| ERROR the trait bound `i8: std::ops::Add<u8>` is not satisfied
     = [0; (i8::MAX as usize) + 1];
 
 
@@ -32,8 +33,7 @@
 
 const A_BAD_CHAR_USIZE
     : [u32; 5i8 as char as usize]
-    //~^ ERROR constant evaluation error
-    //~| only `u8` can be cast as `char`, not `i8`
+    //~^ ERROR only `u8` can be cast as `char`, not `i8`
     = [0; 5];
 
 fn main() {}
index 73351429b50608b770bb11571880aa364e46d666..16f89606b01e6da87a20f6781b2c5bfa6991c2d7 100644 (file)
 struct S(i32);
 
 const CONSTANT: S = S(0);
-//~^ ERROR E0080
-//~| unimplemented constant expression: tuple struct constructors
 
 enum E {
     V = CONSTANT,
-    //~^ NOTE: for enum discriminant here
+    //~^ ERROR mismatched types
+    //~| expected isize, found struct `S`
+    //~| NOTE expected type `isize`
+    //~|         found type `S`
 }
 
 fn main() {}
index 398dc2f22150cc8c90fc1daf0ee9030990b00c86..29bc665a22e7bbe5ed3c4b071ae847d2a3719f5e 100644 (file)
@@ -8,52 +8,71 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-const X: usize = 42 && 39; //~ ERROR E0080
-                           //~| can't do this op on integrals
-const ARR: [i32; X] = [99; 34]; //~ NOTE: for array length here
+const X: usize = 42 && 39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR: [i32; X] = [99; 34];
 
-const X1: usize = 42 || 39; //~ ERROR E0080
-                            //~| can't do this op on integrals
-const ARR1: [i32; X1] = [99; 47]; //~ NOTE: for array length here
+const X1: usize = 42 || 39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR1: [i32; X1] = [99; 47];
 
-const X2: usize = -42 || -39; //~ ERROR E0080
-                              //~| unary negation of unsigned integer
-const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here
+const X2: usize = -42 || -39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR2: [i32; X2] = [99; 18446744073709551607];
 
-const X3: usize = -42 && -39; //~ ERROR E0080
-                              //~| unary negation of unsigned integer
-const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here
+const X3: usize = -42 && -39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR3: [i32; X3] = [99; 6];
 
 const Y: usize = 42.0 == 42.0;
+//~^ ERROR mismatched types
+//~| expected usize, found bool
 const ARRR: [i32; Y] = [99; 1];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
 
 const Y1: usize = 42.0 >= 42.0;
-const ARRR1: [i32; Y] = [99; 1];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR1: [i32; Y1] = [99; 1];
 
 const Y2: usize = 42.0 <= 42.0;
-const ARRR2: [i32; Y] = [99; 1];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR2: [i32; Y2] = [99; 1];
 
 const Y3: usize = 42.0 > 42.0;
-const ARRR3: [i32; Y] = [99; 0];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR3: [i32; Y3] = [99; 0];
 
 const Y4: usize = 42.0 < 42.0;
-const ARRR4: [i32; Y] = [99; 0];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR4: [i32; Y4] = [99; 0];
 
 const Y5: usize = 42.0 != 42.0;
-const ARRR5: [i32; Y] = [99; 0];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
-
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR5: [i32; Y5] = [99; 0];
 
 fn main() {
     let _ = ARR;
index f3fb92e2b2206f5ddf47770edeed7d91531a3797..b42c440f87d74e3678dfc6bf79c8d32a5e5ee7d8 100644 (file)
@@ -11,8 +11,8 @@
 // Test spans of errors
 
 const TUP: (usize,) = 5usize << 64;
-//~^ ERROR E0080
-//~| attempt to shift left with overflow
+//~^ ERROR mismatched types
+//~| expected tuple, found usize
 const ARR: [i32; TUP.0] = [];
 
 fn main() {
index 5ca0700ce6edaa8425da266aec76db4953bc71f5..7af2f11bd281506d11174fb7a3e40e9469961882 100644 (file)
@@ -26,6 +26,7 @@ struct A<T>
     where T : Trait,
           T : Add<T::Item>
     //~^ ERROR unsupported cyclic reference between types/traits detected
+    //~| ERROR associated type `Item` not found for `T`
 {
     data: T
 }
index e6caeb34a8c8f30fddd833c1140200f73f2ea113..6825572b26c83cfa83eb9b154e4b2d2275fb1f41 100644 (file)
@@ -13,6 +13,7 @@
 
 trait Foo<X = Box<Foo>> {
     //~^ ERROR unsupported cyclic reference
+    //~| ERROR unsupported cyclic reference
 }
 
 fn main() { }
index c9bfde3f4ed12bb9ad233976cd0ec992be83611e..905d546e99a066984ee7c0f0c471bd78ada191d1 100644 (file)
 // a direct participant in the cycle.
 
 trait A: B {
-    //~^ ERROR unsupported cyclic reference
+    //~^ NOTE the cycle begins when computing the supertraits of `B`...
 }
 
 trait B: C {
-    //~^ ERROR unsupported cyclic reference
+    //~^ NOTE ...which then requires computing the supertraits of `C`...
 }
 
 trait C: B { }
     //~^ ERROR unsupported cyclic reference
+    //~| cyclic reference
+    //~| NOTE ...which then again requires computing the supertraits of `B`, completing the cycle
 
 fn main() { }
index 4702b504f157d9e4ad6c2745c6d53ffd6b792ee3..8cde239ca6edf0c8c3126d6de4e4a7b540dad199 100644 (file)
@@ -23,8 +23,6 @@ fn main() {
     // Here, F is instantiated with $0=uint
     let x = foo();
     //~^ ERROR: mismatched types
-    //~| expected type `usize`
-    //~| found type `isize`
     //~| NOTE: conflicting type parameter defaults `usize` and `isize`
     //~| NOTE: conflicting type parameter defaults `usize` and `isize`
     //~| NOTE: ...that was applied to an unconstrained type variable here
index b608c6c99be89a5754760dde87272bb94ac54945..e5b035e50aa931c625e36761098f26cd85a5f161 100644 (file)
@@ -29,6 +29,4 @@ fn main() {
     //~| NOTE: conflicting type parameter defaults `bool` and `char`
     //~| a second default is defined on `default_param_test::bleh`
     //~| NOTE:  ...that was applied to an unconstrained type variable here
-    //~| expected type `bool`
-    //~| found type `char`
 }
diff --git a/src/test/compile-fail/deprecated_no_stack_check.rs b/src/test/compile-fail/deprecated_no_stack_check.rs
new file mode 100644 (file)
index 0000000..38aaefd
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(warnings)]
+#![feature(no_stack_check)]
+//~^ ERROR: 12:12: 12:26: feature has been removed [E0557]
+fn main() {
+
+}
index c73b7e831b3217051eb1eef9b64372af92abda81..62e54c3f23773ab1f42bec31aee796eb13aaf10a 100644 (file)
@@ -25,7 +25,7 @@ enum A {
         Ok = i8::MAX - 1,
         Ok2,
         OhNo = 0_u8,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected i8, found u8
     }
 
@@ -38,7 +38,7 @@ enum A {
         Ok = u8::MAX - 1,
         Ok2,
         OhNo = 0_i8,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected u8, found i8
     }
 
@@ -51,7 +51,7 @@ enum A {
         Ok = i16::MAX - 1,
         Ok2,
         OhNo = 0_u16,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected i16, found u16
     }
 
@@ -64,7 +64,7 @@ enum A {
         Ok = u16::MAX - 1,
         Ok2,
         OhNo = 0_i16,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected u16, found i16
     }
 
@@ -77,7 +77,7 @@ enum A {
         Ok = i32::MAX - 1,
         Ok2,
         OhNo = 0_u32,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected i32, found u32
     }
 
@@ -90,7 +90,7 @@ enum A {
         Ok = u32::MAX - 1,
         Ok2,
         OhNo = 0_i32,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected u32, found i32
     }
 
@@ -103,7 +103,7 @@ enum A {
         Ok = i64::MAX - 1,
         Ok2,
         OhNo = 0_u64,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected i64, found u64
     }
 
@@ -116,7 +116,7 @@ enum A {
         Ok = u64::MAX - 1,
         Ok2,
         OhNo = 0_i64,
-        //~^ ERROR E0080
+        //~^ ERROR mismatched types
         //~| expected u64, found i64
     }
 
index bbdb3891d99807dbd989d231ddbcdfbb3805993c..393a67be57fe6b73daec83ae71929d4d7c310b8a 100644 (file)
 enum Eu8 {
     Au8 = 23,
     Bu8 = 223,
-    Cu8 = -23, //~ ERROR E0080
-               //~| unary negation of unsigned integer
+    Cu8 = -23,
+    //~^ ERROR cannot apply unary operator `-` to type `u8`
 }
 
 #[repr(u16)]
 enum Eu16 {
     Au16 = 23,
     Bu16 = 55555,
-    Cu16 = -22333, //~ ERROR E0080
-                   //~| unary negation of unsigned integer
+    Cu16 = -22333,
+    //~^ ERROR cannot apply unary operator `-` to type `u16`
 }
 
 #[repr(u32)]
 enum Eu32 {
     Au32 = 23,
     Bu32 = 3_000_000_000,
-    Cu32 = -2_000_000_000, //~ ERROR E0080
-                           //~| unary negation of unsigned integer
+    Cu32 = -2_000_000_000,
+    //~^ ERROR cannot apply unary operator `-` to type `u32`
 }
 
 #[repr(u64)]
 enum Eu64 {
     Au32 = 23,
     Bu32 = 3_000_000_000,
-    Cu32 = -2_000_000_000, //~ ERROR E0080
-                           //~| unary negation of unsigned integer
+    Cu32 = -2_000_000_000,
+    //~^ ERROR cannot apply unary operator `-` to type `u64`
 }
 
 // u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`.  This is a
index 517e37c3fa5a30fe9302134cfdb314d82e39abb9..b77c9fab7169f6add4cedb9cecc13ee304495b8d 100644 (file)
@@ -11,6 +11,8 @@
 // gate-test-intrinsics
 // gate-test-platform_intrinsics
 // gate-test-abi_vectorcall
+// gate-test-abi_ptx
+// gate-test-abi_x86_interrupt
 
 // Functions
 extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change
@@ -18,6 +20,8 @@ extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experim
 extern "vectorcall" fn f3() {} //~ ERROR vectorcall is experimental and subject to change
 extern "rust-call" fn f4() {} //~ ERROR rust-call ABI is subject to change
 extern "msp430-interrupt" fn f5() {} //~ ERROR msp430-interrupt ABI is experimental
+extern "ptx-kernel" fn f6() {} //~ ERROR PTX ABIs are experimental and subject to change
+extern "x86-interrupt" fn f7() {} //~ ERROR x86-interrupt ABI is experimental
 
 // Methods in trait definition
 trait Tr {
@@ -26,12 +30,16 @@ trait Tr {
     extern "vectorcall" fn m3(); //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn m4(); //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn m5(); //~ ERROR msp430-interrupt ABI is experimental
+    extern "ptx-kernel" fn m6(); //~ ERROR PTX ABIs are experimental and subject to change
+    extern "x86-interrupt" fn m7(); //~ ERROR x86-interrupt ABI is experimental
 
     extern "rust-intrinsic" fn dm1() {} //~ ERROR intrinsics are subject to change
     extern "platform-intrinsic" fn dm2() {} //~ ERROR platform intrinsics are experimental
     extern "vectorcall" fn dm3() {} //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn dm4() {} //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn dm5() {} //~ ERROR msp430-interrupt ABI is experimental
+    extern "ptx-kernel" fn dm6() {} //~ ERROR PTX ABIs are experimental and subject to change
+    extern "x86-interrupt" fn dm7() {} //~ ERROR x86-interrupt ABI is experimental
 }
 
 struct S;
@@ -43,6 +51,8 @@ extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experim
     extern "vectorcall" fn m3() {} //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn m4() {} //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn m5() {} //~ ERROR msp430-interrupt ABI is experimental
+    extern "ptx-kernel" fn m6() {} //~ ERROR PTX ABIs are experimental and subject to change
+    extern "x86-interrupt" fn m7() {} //~ ERROR x86-interrupt ABI is experimental
 }
 
 // Methods in inherent impl
@@ -52,6 +62,8 @@ extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experi
     extern "vectorcall" fn im3() {} //~ ERROR vectorcall is experimental and subject to change
     extern "rust-call" fn im4() {} //~ ERROR rust-call ABI is subject to change
     extern "msp430-interrupt" fn im5() {} //~ ERROR msp430-interrupt ABI is experimental
+    extern "ptx-kernel" fn im6() {} //~ ERROR PTX ABIs are experimental and subject to change
+    extern "x86-interrupt" fn im7() {} //~ ERROR x86-interrupt ABI is experimental
 }
 
 // Function pointer types
@@ -60,6 +72,8 @@ extern "msp430-interrupt" fn im5() {} //~ ERROR msp430-interrupt ABI is experime
 type A3 = extern "vectorcall" fn(); //~ ERROR vectorcall is experimental and subject to change
 type A4 = extern "rust-call" fn(); //~ ERROR rust-call ABI is subject to change
 type A5 = extern "msp430-interrupt" fn(); //~ ERROR msp430-interrupt ABI is experimental
+type A6 = extern "ptx-kernel" fn (); //~ ERROR PTX ABIs are experimental and subject to change
+type A7 = extern "x86-interrupt" fn(); //~ ERROR x86-interrupt ABI is experimental
 
 // Foreign modules
 extern "rust-intrinsic" {} //~ ERROR intrinsics are subject to change
@@ -67,5 +81,7 @@ extern "msp430-interrupt" fn im5() {} //~ ERROR msp430-interrupt ABI is experime
 extern "vectorcall" {} //~ ERROR vectorcall is experimental and subject to change
 extern "rust-call" {} //~ ERROR rust-call ABI is subject to change
 extern "msp430-interrupt" {} //~ ERROR msp430-interrupt ABI is experimental
+extern "ptx-kernel" {} //~ ERROR PTX ABIs are experimental and subject to change
+extern "x86-interrupt" {} //~ ERROR x86-interrupt ABI is experimental
 
 fn main() {}
diff --git a/src/test/compile-fail/feature-gate-cfg-target-has-atomic.rs b/src/test/compile-fail/feature-gate-cfg-target-has-atomic.rs
new file mode 100644 (file)
index 0000000..aa27f89
--- /dev/null
@@ -0,0 +1,86 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type="rlib"]
+#![no_core]
+
+extern "rust-intrinsic" {
+    fn atomic_xadd<T>(dst: *mut T, src: T) -> T;
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+#[cfg(target_has_atomic = "8")]
+//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+pub unsafe fn atomic_u8(x: *mut u8) {
+    atomic_xadd(x, 1);
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "8")]
+//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+pub unsafe fn atomic_i8(x: *mut i8) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "16")]
+//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+pub unsafe fn atomic_u16(x: *mut u16) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "16")]
+//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+pub unsafe fn atomic_i16(x: *mut i16) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "32")]
+//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+pub unsafe fn atomic_u32(x: *mut u32) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "32")]
+//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+pub unsafe fn atomic_i32(x: *mut i32) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "64")]
+//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+pub unsafe fn atomic_u64(x: *mut u64) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "64")]
+//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+pub unsafe fn atomic_i64(x: *mut i64) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "ptr")]
+//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+pub unsafe fn atomic_usize(x: *mut usize) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "ptr")]
+//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+pub unsafe fn atomic_isize(x: *mut isize) {
+    atomic_xadd(x, 1);
+}
+
+fn main() {
+    cfg!(target_has_atomic = "8");
+    //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+    cfg!(target_has_atomic = "16");
+    //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+    cfg!(target_has_atomic = "32");
+    //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+    cfg!(target_has_atomic = "64");
+    //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+    cfg!(target_has_atomic = "ptr");
+    //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+}
diff --git a/src/test/compile-fail/feature-gate-closure_to_fn_coercion.rs b/src/test/compile-fail/feature-gate-closure_to_fn_coercion.rs
new file mode 100644 (file)
index 0000000..d074a35
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-stage0: new feature, remove this when SNAP
+// revisions: a b
+
+#[cfg(a)]
+mod a {
+    const FOO: fn(u8) -> u8 = |v: u8| { v };
+    //[a]~^ ERROR non-capturing closure to fn coercion is experimental
+    //[a]~^^ ERROR mismatched types
+
+    const BAR: [fn(&mut u32); 1] = [
+        |v: &mut u32| *v += 1,
+    //[a]~^ ERROR non-capturing closure to fn coercion is experimental
+    //[a]~^^ ERROR mismatched types
+    ];
+}
+
+#[cfg(b)]
+mod b {
+    fn func_specific() -> (fn() -> u32) {
+        || return 42
+        //[b]~^ ERROR non-capturing closure to fn coercion is experimental
+        //[b]~^^ ERROR mismatched types
+    }
+    fn foo() {
+        // Items
+        assert_eq!(func_specific()(), 42);
+        let foo: fn(u8) -> u8 = |v: u8| { v };
+        //[b]~^ ERROR non-capturing closure to fn coercion is experimental
+        //[b]~^^ ERROR mismatched types
+    }
+
+}
+
+
+
diff --git a/src/test/compile-fail/feature-gate-static_recursion.rs b/src/test/compile-fail/feature-gate-static_recursion.rs
deleted file mode 100644 (file)
index bd20c89..0000000
+++ /dev/null
@@ -1,49 +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.
-
-static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
-//~^ ERROR recursive static (see issue #29719)
-
-struct StaticDoubleLinked {
-    prev: &'static StaticDoubleLinked,
-    next: &'static StaticDoubleLinked,
-    data: i32,
-    head: bool,
-}
-
-static L1: StaticDoubleLinked = StaticDoubleLinked{prev: &L3, next: &L2, data: 1, head: true};
-//~^ ERROR recursive static (see issue #29719)
-//~^^ ERROR recursive static (see issue #29719)
-//~^^^ ERROR recursive static (see issue #29719)
-static L2: StaticDoubleLinked = StaticDoubleLinked{prev: &L1, next: &L3, data: 2, head: false};
-static L3: StaticDoubleLinked = StaticDoubleLinked{prev: &L2, next: &L1, data: 3, head: false};
-
-
-pub fn main() {
-    unsafe { assert_eq!(S, *(S as *const *const u8)); }
-
-    let mut test_vec = Vec::new();
-    let mut cur = &L1;
-    loop {
-        test_vec.push(cur.data);
-        cur = cur.next;
-        if cur.head { break }
-    }
-    assert_eq!(&test_vec, &[1,2,3]);
-
-    let mut test_vec = Vec::new();
-    let mut cur = &L1;
-    loop {
-        cur = cur.prev;
-        test_vec.push(cur.data);
-        if cur.head { break }
-    }
-    assert_eq!(&test_vec, &[3,2,1]);
-}
diff --git a/src/test/compile-fail/feature-gate-unboxed-closures.rs b/src/test/compile-fail/feature-gate-unboxed-closures.rs
new file mode 100644 (file)
index 0000000..4005021
--- /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 Test;
+
+impl FnOnce<(u32, u32)> for Test {
+    type Output = u32;
+
+    extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 {
+        a + b
+    }
+    //~^^^ ERROR rust-call ABI is subject to change (see issue #29625)
+}
+
+fn main() {
+    assert_eq!(Test(1u32, 2u32), 3u32);
+}
index 77e5520326379e21193ee7d5ff1320aa8fc9ba7b..13b7753082c61d3c8915b5c75acbe58fd64ca06a 100644 (file)
 
 struct Heap;
 
-struct Vec<A = Heap, T>;
+struct Vec<A = Heap, T>(A, T);
 //~^ ERROR type parameters with a default must be trailing
 
-struct Foo<A, B = Vec<C>, C>;
+struct Foo<A, B = Vec<C>, C>(A, B, C);
 //~^ ERROR type parameters with a default must be trailing
 //~| ERROR type parameters with a default cannot use forward declared identifiers
 
index eda1b014fa7a4a54dc01eec1cdfea22c687f7174..bfa6af0da433bc2b2b2c9a638e7cf3debc0707bb 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // Ensure that we get an error and not an ICE for this problematic case.
-struct Foo<T = Option<U>, U = bool>;
+struct Foo<T = Option<U>, U = bool>(T, U);
 //~^ ERROR type parameters with a default cannot use forward declared identifiers
 fn main() {
     let x: Foo;
index f055d20e1343be79178270ef1fa266801aa6537a..13e53cab17226d385107b551928608cb95c56a1a 100644 (file)
@@ -52,23 +52,20 @@ fn after() -> impl Fn(i32) {
 // independently resolved and only require the concrete
 // return type, which can't depend on the obligation.
 fn cycle1() -> impl Clone {
+    //~^ ERROR unsupported cyclic reference between types/traits detected
+    //~| cyclic reference
+    //~| NOTE the cycle begins when processing `cycle1`...
+    //~| NOTE ...which then requires processing `cycle1::{{impl-Trait}}`...
+    //~| NOTE ...which then again requires processing `cycle1`, completing the cycle.
     send(cycle2().clone());
-    //~^ ERROR the trait bound `std::rc::Rc<std::string::String>: std::marker::Send` is not satisfied
-    //~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::string::String>`
-    //~| 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`
 
     Rc::new(Cell::new(5))
 }
 
 fn cycle2() -> impl Clone {
+    //~^ NOTE ...which then requires processing `cycle2::{{impl-Trait}}`...
+    //~| NOTE ...which then requires processing `cycle2`...
     send(cycle1().clone());
-    //~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
-    //~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
-    //~| 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`
 
     Rc::new(String::from("foo"))
 }
index 59ad1132b3501bdfae21910a24a0b6ba831c4bb9..36df4f0eb4d46f7cc25792807680fa6c622dd3cc 100644 (file)
@@ -49,17 +49,6 @@ impl Leak for i32 {
     fn leak(self) -> i32 { self }
 }
 
-trait CheckIfSend: Sized {
-    type T: Default;
-    fn check(self) -> Self::T { Default::default() }
-}
-impl<T> CheckIfSend for T {
-    default type T = ();
-}
-impl<T: Send> CheckIfSend for T {
-    type T = bool;
-}
-
 fn main() {
     let _: u32 = hide(0_u32);
     //~^ ERROR mismatched types
@@ -73,12 +62,6 @@ fn main() {
     //~| found type `<impl Foo as Leak>::T`
     //~| expected i32, found associated type
 
-    let _: bool = CheckIfSend::check(hide(0_i32));
-    //~^ ERROR mismatched types
-    //~| expected type `bool`
-    //~| found type `<impl Foo as CheckIfSend>::T`
-    //~| expected bool, found associated type
-
     let mut x = (hide(0_u32), hide(0_i32));
     x = (x.1,
     //~^ ERROR mismatched types
index 9a9358b787f5386cbebd0231958212dc4c61fc4d..ab839e7630de907904093b4f3ac54e70285a7f0b 100644 (file)
@@ -10,6 +10,5 @@
 
 fn main() {
     fn f(a: [u8; u32::DOESNOTEXIST]) {}
-    //~^ ERROR constant evaluation error
-    //~| unresolved path in constant expression
+    //~^ ERROR no associated item named `DOESNOTEXIST` found for type `u32`
 }
index 35697e687341f10b8c35655fcdb4dc8054721b6e..0c3073a770141f866a0eef4e883900413993cceb 100644 (file)
@@ -9,11 +9,14 @@
 // except according to those terms.
 
 trait t1 : t2 {
-//~^ ERROR: unsupported cyclic reference between types/traits detected
+//~^ NOTE the cycle begins when computing the supertraits of `t1`...
+//~| NOTE ...which then requires computing the supertraits of `t2`...
 }
 
 trait t2 : t1 {
-//~^ ERROR: unsupported cyclic reference between types/traits detected
+//~^ ERROR unsupported cyclic reference between types/traits detected
+//~| cyclic reference
+//~| NOTE ...which then again requires computing the supertraits of `t1`, completing the cycle
 }
 
 fn main() { }
index 0d5f5fd75eba881378e45d963ba5f95e3521395a..658a0c1546b9f337b27704fa31d060075e91bdfc 100644 (file)
 
 enum Foo {
     A = 1,
-    //~^ NOTE first use of `1`
-    //~| NOTE first use of `1`
-    //~| NOTE first use of `1`
+    //~^ NOTE first use of `1isize`
+    //~| NOTE first use of `1isize`
+    //~| NOTE first use of `1isize`
     B = 1,
-    //~^ ERROR discriminant value `1` already exists
-    //~| NOTE enum already has `1`
+    //~^ ERROR discriminant value `1isize` already exists
+    //~| NOTE enum already has `1isize`
     C = 0,
     D,
-    //~^ ERROR discriminant value `1` already exists
-    //~| NOTE enum already has `1`
+    //~^ ERROR discriminant value `1isize` already exists
+    //~| NOTE enum already has `1isize`
 
     E = N,
-    //~^ ERROR discriminant value `1` already exists
-    //~| NOTE enum already has `1`
+    //~^ ERROR discriminant value `1isize` already exists
+    //~| NOTE enum already has `1isize`
 
 }
 
index b3fc3aea148ee3b6cdaf70e4e75a4af0c862a78b..feab04531b7e11bca3b4738a7de5a19c6e1d8b71 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub struct Foo<Bar=Bar>; //~ ERROR E0128
-                         //~| NOTE defaulted type parameters cannot be forward declared
+pub struct Foo<Bar=Bar>(Bar); //~ ERROR E0128
+                              //~| NOTE defaulted type parameters cannot be forward declared
 pub struct Baz(Foo);
 fn main() {}
index 44c92f946f03d1f3bc4436b0aa5bec9ca8530deb..7ae4250d4203bac9f6274cd297433762c90c2d0f 100644 (file)
@@ -10,6 +10,7 @@
 
 trait T : Iterator<Item=Self::Item>
 //~^ ERROR unsupported cyclic reference between types/traits detected
+//~| ERROR associated type `Item` not found for `Self`
 {}
 
 fn main() {}
index 5ad9a12362d60a72aef936076703b566208d9b12..f49b71953835b28ac50d8b058f39901c2d601fb8 100644 (file)
@@ -14,6 +14,7 @@ trait Trait {
 }
 
 fn foo<T: Trait<A = T::B>>() { }
-//~^ ERROR: unsupported cyclic reference between types/traits detected
+//~^ ERROR unsupported cyclic reference between types/traits detected
+//~| ERROR associated type `B` not found for `T`
 
 fn main() { }
index 54a24089354614f05c4e90e04e1e3bdce16fba17..c78e1f7f5309505689b74c03c6d0f70e9f1b800c 100644 (file)
@@ -12,12 +12,10 @@ enum Delicious {
     Pie      = 0x1,
     Apple    = 0x2,
     ApplePie = Delicious::Apple as isize | Delicious::PIE as isize,
-    //~^ ERROR constant evaluation error
-    //~| unresolved path in constant expression
+    //~^ ERROR no associated item named `PIE` found for type `Delicious`
 }
 
 const FOO: [u32; u8::MIN as usize] = [];
-//~^ ERROR constant evaluation error
-//~| unresolved path in constant expression
+//~^ ERROR no associated item named `MIN` found for type `u8`
 
 fn main() {}
index c2bcbb9d54a9a447c1f5c0bf873d8a8542226f4a..95f6526f11559e835f37a126c6a20e17d7a297d2 100644 (file)
@@ -10,8 +10,7 @@
 
 pub enum SomeEnum {
     B = SomeEnum::A,
-    //~^ ERROR constant evaluation error
-    //~| unresolved path in constant expression
+    //~^ ERROR no associated item named `A` found for type `SomeEnum`
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-25145.rs b/src/test/compile-fail/issue-25145.rs
deleted file mode 100644 (file)
index 93f75e9..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.
-
-#![feature(associated_consts)]
-
-struct S;
-
-impl S {
-    const N: usize = 3;
-}
-
-static STUFF: [u8; S::N] = [0; S::N];
-//~^ ERROR constant evaluation error
-//~| unresolved path in constant expression
-
-fn main() {}
index 1dfd146985ff48a8df17ee421986e27306637c67..b8571d2e85e2c8bfae4f42a6238a5e7a37aa337c 100644 (file)
@@ -11,6 +11,7 @@
 // Regression test for issue #28586
 
 pub trait Foo {}
-impl Foo for [u8; usize::BYTES] {} //~ ERROR E0080
+impl Foo for [u8; usize::BYTES] {}
+//~^ ERROR no associated item named `BYTES` found for type `usize`
 
 fn main() { }
index 38b5fcbb3db0ee36b98b190945e09af7b1b33be4..3bc8413cbca73b1a16a9ca3137e576bfdebb6e9b 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(static_recursion)]
-
 enum foo { foo_(bar) }
 struct bar { x: bar }
 //~^ ERROR E0072
index 65fcd7df77ebeb0eb27080067aa9a3a589cbc55a..aac8b89e882b3b7f6adcec6367a7f13e25190e90 100644 (file)
@@ -11,7 +11,9 @@
 #![feature(associated_consts)]
 
 enum Enum<T: Trait> {
-    X = Trait::Number, //~ ERROR constant evaluation error
+    X = Trait::Number,
+    //~^ ERROR mismatched types
+    //~| expected isize, found i32
 }
 
 trait Trait {
index e2acdcee3de8f7447c00c613617b8969617f6137..78af11a0b5813ebc0a032382c6def694fd87b387 100644 (file)
@@ -15,9 +15,7 @@ fn main() {
     enum Stuff {
         Bar = foo
         //~^ ERROR attempt to use a non-constant value in a constant
-        //~^^ ERROR constant evaluation error
-        //~| unresolved path in constant expression
     }
 
-    println!("{}", Stuff::Bar);
+    println!("{:?}", Stuff::Bar);
 }
index d890d02a910478f978cdca71137bbd28ef05bedc..5f54f269c6c55694fb7596043f44abf457c81683 100644 (file)
@@ -8,9 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-macro_rules! m { ($t:tt) => { $t } }
+macro_rules! m { ($($t:tt)*) => { $($t)* } }
 
 fn main() {
-    m!($t); //~ ERROR unknown macro variable
-            //~| ERROR expected expression
+    m!($t); //~ ERROR expected expression
 }
index 8b7fc80bdb6b774f873c1a58e3465c4949a34da1..d1d6390cce35b2347f91255033657c6559434bea 100644 (file)
@@ -23,15 +23,19 @@ impl Foo for Bar {
     fn foo(_: fn(u16) -> ()) {}
     //~^ ERROR method `foo` has an incompatible type for trait
     //~| NOTE expected u8
+    //~| NOTE expected type `fn(fn(u8))`
     fn bar(_: Option<u16>) {}
     //~^ ERROR method `bar` has an incompatible type for trait
     //~| NOTE expected u8
+    //~| NOTE expected type `fn(std::option::Option<u8>)`
     fn baz(_: (u16, u16)) {}
     //~^ ERROR method `baz` has an incompatible type for trait
     //~| NOTE expected u8
+    //~| NOTE expected type `fn((u8, u16))`
     fn qux() -> u16 { 5u16 }
     //~^ ERROR method `qux` has an incompatible type for trait
     //~| NOTE expected u8
+    //~| NOTE expected type `fn() -> u8`
 }
 
 fn main() {}
index 88c6eb7f515c31366a3ad382d628033198087c29..efb0b249a8a59cbc84795eeebe51de8ef0026885 100644 (file)
@@ -11,8 +11,8 @@
 // Tests that compiling for a target which is not installed will result in a helpful
 // error message.
 
-// compile-flags: --target=s390x-unknown-linux-gnu
-// ignore s390x
+// compile-flags: --target=thumbv6m-none-eabi
+// ignore-arm
 
 // error-pattern:target may not be installed
 fn main() { }
diff --git a/src/test/compile-fail/issue-37576.rs b/src/test/compile-fail/issue-37576.rs
new file mode 100644 (file)
index 0000000..e3c1ada
--- /dev/null
@@ -0,0 +1,55 @@
+// 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.
+
+fn main() {
+    'test_1: while break 'test_1 {}
+    while break {}
+    //~^ ERROR `break` or `continue` with no label
+
+    'test_2: while let true = break 'test_2 {}
+    while let true = break {}
+    //~^ ERROR `break` or `continue` with no label
+
+    loop { 'test_3: while break 'test_3 {} }
+    loop { while break {} }
+    //~^ ERROR `break` or `continue` with no label
+
+    loop {
+        'test_4: while break 'test_4 {}
+        break;
+    }
+    loop {
+        while break {}
+        //~^ ERROR `break` or `continue` with no label
+        break;
+    }
+
+    'test_5: while continue 'test_5 {}
+    while continue {}
+    //~^ ERROR `break` or `continue` with no label
+
+    'test_6: while let true = continue 'test_6 {}
+    while let true = continue {}
+    //~^ ERROR `break` or `continue` with no label
+
+    loop { 'test_7: while continue 'test_7 {} }
+    loop { while continue {} }
+    //~^ ERROR `break` or `continue` with no label
+
+    loop {
+        'test_8: while continue 'test_8 {}
+        continue;
+    }
+    loop {
+        while continue {}
+        //~^ ERROR `break` or `continue` with no label
+        continue;
+    }
+}
diff --git a/src/test/compile-fail/issue-39404.rs b/src/test/compile-fail/issue-39404.rs
new file mode 100644 (file)
index 0000000..0168ae7
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(missing_fragment_specifier)] //~ NOTE lint level defined here
+
+macro_rules! m { ($i) => {} }
+//~^ ERROR missing fragment specifier
+//~| WARN previously accepted
+//~| NOTE issue #40107
+
+fn main() {}
index a56a5e8548944d01f8f7850cf4d9ccd00f53e079..06e8406cbc0bd15c3b7d531cc82058a71ec82eef 100644 (file)
@@ -23,9 +23,15 @@ fn dim() -> usize {
 pub struct Vector<T, D: Dim> {
     entries: [T; D::dim()]
     //~^ ERROR cannot use an outer type parameter in this context
-    //~| ERROR constant evaluation error
 }
 
 fn main() {
-    let array: [usize; Dim3::dim()] = [0; Dim3::dim()];
+    let array: [usize; Dim3::dim()]
+    //~^ ERROR calls in constants are limited to constant functions
+    //~| ERROR constant evaluation error
+    //~| non-constant path in constant expression
+        = [0; Dim3::dim()];
+        //~^ ERROR calls in constants are limited to constant functions
+        //~| ERROR constant evaluation error
+        //~| non-constant path in constant expression
 }
diff --git a/src/test/compile-fail/issue-39709.rs b/src/test/compile-fail/issue-39709.rs
deleted file mode 100644 (file)
index 0f66fe8..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn main() {
-    println!("{}", { macro_rules! x { ($()*) => {} } 33 });
-    //~^ ERROR no syntax variables matched as repeating at this depth
-}
-
index 91a07dd9ba6dd68ede4d5bf9129a180f1d579d89..f8424ea64ef9e29794a76aa621eb0e974e34b075 100644 (file)
 
 enum Foo {
     A = 1i64,
-    //~^ ERROR constant evaluation error
+    //~^ ERROR mismatched types
     //~| expected isize, found i64
     B = 2u8
-    //~^ ERROR constant evaluation error
+    //~^ ERROR mismatched types
     //~| expected isize, found u8
 }
 
index 78f95e365c44b7ef8510c649a35b1fe0ebf0d038..82a5aa487291320cd4bc27dda7c77b30e7a9b459 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 macro_rules! foo {
-    ($a:expr) => $a; //~ ERROR macro rhs must be delimited
+    ($a:expr) => a; //~ ERROR macro rhs must be delimited
 }
 
 fn main() {
index 969f1500717d73f41cabba776782a741105b204f..7255e7d00b6115c1a60caa9f279a969fb3c9cfe1 100644 (file)
@@ -17,16 +17,5 @@ macro_rules! foo {
 
 foo!(Box);
 
-macro_rules! bar {
-    ($x:tt) => {
-        macro_rules! baz {
-            ($x:tt, $y:tt) => { ($x, $y) }
-        }
-    }
-}
-
 #[rustc_error]
-fn main() { //~ ERROR compilation successful
-    bar!($y);
-    let _: (i8, i16) = baz!(0i8, 0i16);
-}
+fn main() {} //~ ERROR compilation successful
index 5d81e21f05684e1f816522c214a289bc287458b7..0b437be5393edac4aafdf4b3f4b36dc0c57382a2 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 macro_rules! my_precioooous {
-    $($t:tt)* => (1); //~ ERROR invalid macro matcher
+    t => (1); //~ ERROR invalid macro matcher
 }
 
 fn main() {
diff --git a/src/test/compile-fail/match-privately-empty.rs b/src/test/compile-fail/match-privately-empty.rs
new file mode 100644 (file)
index 0000000..3affb1c
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(never_type)]
+
+mod private {
+    pub struct Private {
+        _bot: !,
+        pub misc: bool,
+    }
+    pub const DATA: Option<Private> = None;
+}
+
+fn main() {
+    match private::DATA {
+    //~^ ERROR non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered
+        None => {}
+        Some(private::Private {
+            misc: false,
+            ..
+        }) => {}
+    }
+}
index 691d8d31b412d1c3934d8cbf2f7da2cff49b1788..52cd4e8a3ed95122a8683b43c3944fde46f82e2b 100644 (file)
@@ -14,6 +14,5 @@ fn main() {
     fn bar(n: isize) {
         let _x: [isize; n];
         //~^ ERROR attempt to use a non-constant value in a constant [E0435]
-        //~| ERROR constant evaluation error [E0080]
     }
 }
index f4769a78587280494ea4bab4f91ca3784317f148..1eda5087784029be6f3aa30a76c95c035b6fa942 100644 (file)
@@ -15,7 +15,5 @@ fn bar(n: usize) {
         let _x = [0; n];
         //~^ ERROR attempt to use a non-constant value in a constant [E0435]
         //~| NOTE non-constant used with constant
-        //~| NOTE unresolved path in constant expression
-        //~| ERROR constant evaluation error [E0080]
     }
 }
index ed2c3e0e9b86054433fd656c746988ab10c225fb..6695e972f333731caa591f8d2c27f4c08b458580 100644 (file)
@@ -17,8 +17,7 @@ fn g() {
         }
     }
 
-    // issue #37353
-    loop { 'w: while break 'w { } } //~ ERROR use of undeclared label
+    loop { 'w: while break 'w { } }
 }
 
 fn main() {}
index 04f98c7ab329faa751bddadfe4598d3ac6974b39..710d8e11ff03420964d691d587428e81cc60a97f 100644 (file)
@@ -8,22 +8,24 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(associated_type_defaults)]
+
 struct S<T = u8>(T);
-trait Tr<T = u8> {}
+trait Tr<T = u8> {
+    type A = ();
+}
 
 impl Tr<Self> for S {} // OK
+impl<T: Tr<Self>> Tr<T> for S {} // OK
+impl<T = Self> Tr<T> for S {} // OK
+impl Tr for S where Self: Copy {} // OK
+impl Tr for S where S<Self>: Copy {} // OK
+impl Tr for S where Self::A: Copy {} // OK
 
-// FIXME: `Self` cannot be used in bounds because it depends on bounds itself.
-impl<T: Tr<Self>> Tr<T> for S {} //~ ERROR `Self` type is used before it's determined
-impl<T = Self> Tr<T> for S {} //~ ERROR `Self` type is used before it's determined
-impl Tr for S where Self: Copy {} //~ ERROR `Self` type is used before it's determined
-impl Tr for S where S<Self>: Copy {} //~ ERROR `Self` type is used before it's determined
-impl Tr for S where Self::Assoc: Copy {} //~ ERROR `Self` type is used before it's determined
-                                         //~^ ERROR `Self` type is used before it's determined
-impl Tr for Self {} //~ ERROR `Self` type is used before it's determined
-impl Tr for S<Self> {} //~ ERROR `Self` type is used before it's determined
-impl Self {} //~ ERROR `Self` type is used before it's determined
-impl S<Self> {} //~ ERROR `Self` type is used before it's determined
-impl Tr<Self::Assoc> for S {} //~ ERROR `Self` type is used before it's determined
+impl Tr for Self {} //~ ERROR unsupported cyclic reference between types/traits detected
+impl Tr for S<Self> {} //~ ERROR unsupported cyclic reference between types/traits detected
+impl Self {} //~ ERROR unsupported cyclic reference between types/traits detected
+impl S<Self> {} //~ ERROR unsupported cyclic reference between types/traits detected
+impl Tr<Self::A> for S {} //~ ERROR unsupported cyclic reference between types/traits detected
 
 fn main() {}
diff --git a/src/test/compile-fail/static-recursion-gate.rs b/src/test/compile-fail/static-recursion-gate.rs
deleted file mode 100644 (file)
index 29b5689..0000000
+++ /dev/null
@@ -1,16 +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.
-
-static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
-//~^ ERROR recursive static
-
-pub fn main() {
-    unsafe { assert_eq!(S, *(S as *const *const u8)); }
-}
index 50bcd53ecb82c55e6777dfc7471ddf535354848b..c3fe1de895df9dcf6ef9e3dfa4bccc596662eecd 100644 (file)
 
 use std::mem;
 
+unsafe fn foo() -> (isize, *const (), Option<fn()>) {
+    let i = mem::transmute(bar);
+    //~^ ERROR is zero-sized and can't be transmuted
+    //~^^ NOTE cast with `as` to a pointer instead
+
+    let p = mem::transmute(foo);
+    //~^ ERROR is zero-sized and can't be transmuted
+    //~^^ NOTE cast with `as` to a pointer instead
+
+    let of = mem::transmute(main);
+    //~^ ERROR is zero-sized and can't be transmuted
+    //~^^ NOTE cast with `as` to a pointer instead
+
+    (i, p, of)
+}
+
 unsafe fn bar() {
-    // Error, still, if the resulting type is not pointer-sized.
+    // Error as usual if the resulting type is not pointer-sized.
     mem::transmute::<_, u8>(main);
     //~^ ERROR transmute called with differently sized types
+    //~^^ NOTE transmuting between 0 bits and 8 bits
+
+    mem::transmute::<_, *mut ()>(foo);
+    //~^ ERROR is zero-sized and can't be transmuted
+    //~^^ NOTE cast with `as` to a pointer instead
+
+    mem::transmute::<_, fn()>(bar);
+    //~^ ERROR is zero-sized and can't be transmuted
+    //~^^ NOTE cast with `as` to a pointer instead
+
+    // No error if a coercion would otherwise occur.
+    mem::transmute::<fn(), usize>(main);
+}
+
+unsafe fn baz() {
+    mem::transmute::<_, *mut ()>(Some(foo));
+    //~^ ERROR is zero-sized and can't be transmuted
+    //~^^ NOTE cast with `as` to a pointer instead
+
+    mem::transmute::<_, fn()>(Some(bar));
+    //~^ ERROR is zero-sized and can't be transmuted
+    //~^^ NOTE cast with `as` to a pointer instead
+
+    mem::transmute::<_, Option<fn()>>(Some(baz));
+    //~^ ERROR is zero-sized and can't be transmuted
+    //~^^ NOTE cast with `as` to a pointer instead
+
+    // No error if a coercion would otherwise occur.
+    mem::transmute::<Option<fn()>, usize>(Some(main));
 }
 
 fn main() {
     unsafe {
+        foo();
         bar();
+        baz();
     }
 }
diff --git a/src/test/compile-fail/transmute-from-fn-item-types-lint.rs b/src/test/compile-fail/transmute-from-fn-item-types-lint.rs
deleted file mode 100644 (file)
index 08e660e..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![deny(transmute_from_fn_item_types)]
-
-use std::mem;
-
-unsafe fn foo() -> (isize, *const (), Option<fn()>) {
-    let i = mem::transmute(bar);
-    //~^ ERROR is now zero-sized and has to be cast to a pointer before transmuting
-    //~^^ WARNING was previously accepted
-
-    let p = mem::transmute(foo);
-    //~^ ERROR is now zero-sized and has to be cast to a pointer before transmuting
-    //~^^ WARNING was previously accepted
-
-    let of = mem::transmute(main);
-    //~^ ERROR is now zero-sized and has to be cast to a pointer before transmuting
-    //~^^ WARNING was previously accepted
-
-    (i, p, of)
-}
-
-unsafe fn bar() {
-    mem::transmute::<_, *mut ()>(foo);
-    //~^ ERROR is now zero-sized and has to be cast to a pointer before transmuting
-    //~^^ WARNING was previously accepted
-
-    mem::transmute::<_, fn()>(bar);
-    //~^ ERROR is now zero-sized and has to be cast to a pointer before transmuting
-    //~^^ WARNING was previously accepted
-
-    // No error if a coercion would otherwise occur.
-    mem::transmute::<fn(), usize>(main);
-}
-
-fn main() {
-    unsafe {
-        foo();
-        bar();
-    }
-}
index 0f8b0a6c238d08f03c4d2ae88554f4c3775313e5..0c3ea53a903ae9062c03098e6ee2838a975b4a1a 100644 (file)
@@ -19,16 +19,13 @@ fn main() {
     };
 
     let x: &Void = unsafe { std::mem::uninitialized() };
-    let _ = match x {};
-    //~^ ERROR non-exhaustive
+    let _ = match x {}; //~ ERROR non-exhaustive
 
     let x: (Void,) = unsafe { std::mem::uninitialized() };
-    let _ = match x {};
-    //~^ ERROR non-exhaustive
+    let _ = match x {}; //~ ERROR non-exhaustive
 
     let x: [Void; 1] = unsafe { std::mem::uninitialized() };
-    let _ = match x {};
-    //~^ ERROR non-exhaustive
+    let _ = match x {}; //~ ERROR non-exhaustive
 
     let x: &[Void] = unsafe { std::mem::uninitialized() };
     let _ = match x {   //~ ERROR non-exhaustive
@@ -47,4 +44,3 @@ fn main() {
     let Ok(x) = x;
     //~^ ERROR refutable
 }
-
index da3a953d11eaa883367ebcdedcca038947c44a7f..048ccb529a24fc9a516eaeea9667189c55c454fd 100644 (file)
@@ -112,10 +112,13 @@ enum EnumChangeValueCStyleVariant0 {
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_dirty(label="HirBody", cfg="cfail2")]
 #[rustc_clean(label="HirBody", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeValueCStyleVariant0 {
     Variant1,
+
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     Variant2 = 22,
 }
 
diff --git a/src/test/incremental/issue-39828/auxiliary/generic.rs b/src/test/incremental/issue-39828/auxiliary/generic.rs
new file mode 100644 (file)
index 0000000..a562eab
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// revisions:rpass1 rpass2
+// compile-flags: -Z query-dep-graph
+
+#![rustc_partition_reused(module="__rustc_fallback_codegen_unit", cfg="rpass2")]
+#![feature(rustc_attrs)]
+
+#![crate_type="rlib"]
+pub fn foo<T>() { }
diff --git a/src/test/incremental/issue-39828/issue-39828.rs b/src/test/incremental/issue-39828/issue-39828.rs
new file mode 100644 (file)
index 0000000..c729380
--- /dev/null
@@ -0,0 +1,22 @@
+// 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.
+
+// Regression test for #39828. If you make use of a module that
+// consists only of generics, no code is generated, just a dummy
+// module. The reduced graph consists of a single node (for that
+// module) with no inputs. Since we only serialize edges, when we
+// reload, we would consider that node dirty since it is not recreated
+// (it is not the target of any edges).
+
+// revisions:rpass1 rpass2
+// aux-build:generic.rs
+
+extern crate generic;
+fn main() { }
index 0e8971269b0075eda875512642821c54b2fa3b36..6e80a9174676a1247515fae79095f52fc17a9899 100644 (file)
@@ -17,7 +17,7 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node4.SimplifyBranches.initial-before.mir
 // bb0: {
-//     switchInt(const false) -> [0: bb2, otherwise: bb1];
+//     switchInt(const false) -> [0u8: bb2, otherwise: bb1];
 // }
 // END rustc.node4.SimplifyBranches.initial-before.mir
 // START rustc.node4.SimplifyBranches.initial-after.mir
index e3c17af82aab403d2eda1ce51af24d796447e050..15d491719a6d58dd8edf2350edd32d3309d98fee 100644 (file)
@@ -12,7 +12,9 @@
 
 macro_rules! foo {
     { $+ } => { //~ ERROR expected identifier, found `+`
+                //~^ ERROR missing fragment specifier
         $(x)(y) //~ ERROR expected `*` or `+`
-                //~^ ERROR no rules expected the token `)`
     }
 }
+
+foo!();
index 021b6dd3e260f79e7ea7e728588acc8a63adbaf7..30dc6fc5b20a028955ca4528de5e1db5f0abdd01 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// gate-test-inclusive_range_syntax
+
 // Make sure that #![feature(inclusive_range_syntax)] is required.
 
 // #![feature(inclusive_range_syntax, inclusive_range)]
diff --git a/src/test/run-make/fpic/Makefile b/src/test/run-make/fpic/Makefile
new file mode 100644 (file)
index 0000000..6de58c2
--- /dev/null
@@ -0,0 +1,13 @@
+-include ../tools.mk
+
+# Test for #39529.
+# `-z text` causes ld to error if there are any non-PIC sections
+
+ifeq ($(UNAME),Darwin)
+all:
+else ifdef IS_WINDOWS
+all:
+else
+all:
+       $(RUSTC) hello.rs -C link-args=-Wl,-z,text
+endif
diff --git a/src/test/run-make/fpic/hello.rs b/src/test/run-make/fpic/hello.rs
new file mode 100644 (file)
index 0000000..a9e231b
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() { }
index a3b531b1e2f413b6984fc6f8327f3229616a4943..07b9c744a71711c33f87bad824fbdd4746dc8140 100644 (file)
@@ -5,10 +5,10 @@ digraph block {
     N3[label="local mut x"];
     N4[label="stmt let mut x = 10;"];
     N5[label="(dummy_node)"];
-    N6[label="expr x"];
-    N7[label="expr 0"];
-    N8[label="expr x > 0"];
-    N9[label="expr while x > 0 { x -= 1; }"];
+    N6[label="expr while x > 0 { x -= 1; }"];
+    N7[label="expr x"];
+    N8[label="expr 0"];
+    N9[label="expr x > 0"];
     N10[label="expr 1"];
     N11[label="expr x"];
     N12[label="expr x -= 1"];
@@ -20,17 +20,17 @@ digraph block {
     N2 -> N3;
     N3 -> N4;
     N4 -> N5;
-    N5 -> N6;
-    N6 -> N7;
+    N5 -> N7;
     N7 -> N8;
     N8 -> N9;
-    N8 -> N10;
+    N9 -> N6;
+    N9 -> N10;
     N10 -> N11;
     N11 -> N12;
     N12 -> N13;
     N13 -> N14;
     N14 -> N5;
-    N9 -> N15;
+    N6 -> N15;
     N15 -> N16;
     N16 -> N1;
 }
index f152977438c505d87a932e5680012be93872eb69..c8bfcd6510b30054fd02295cc34bd62e033d5e94 100644 (file)
@@ -11,28 +11,28 @@ digraph block {
     N9[label="local mut z"];
     N10[label="stmt let mut z = 23;"];
     N11[label="(dummy_node)"];
-    N12[label="expr x"];
-    N13[label="expr 0"];
-    N14[label="expr x > 0"];
-    N15[label="expr while x > 0 {\l    x -= 1;\l    while y > 0 {\l        y -= 1;\l        while z > 0 { z -= 1; }\l        if x > 10 { return; \"unreachable\"; }\l    }\l}\l"];
+    N12[label="expr while x > 0 {\l    x -= 1;\l    while y > 0 {\l        y -= 1;\l        while z > 0 { z -= 1; }\l        if x > 10 { return; \"unreachable\"; }\l    }\l}\l"];
+    N13[label="expr x"];
+    N14[label="expr 0"];
+    N15[label="expr x > 0"];
     N16[label="expr 1"];
     N17[label="expr x"];
     N18[label="expr x -= 1"];
     N19[label="stmt x -= 1;"];
     N20[label="(dummy_node)"];
-    N21[label="expr y"];
-    N22[label="expr 0"];
-    N23[label="expr y > 0"];
-    N24[label="expr while y > 0 {\l    y -= 1;\l    while z > 0 { z -= 1; }\l    if x > 10 { return; \"unreachable\"; }\l}\l"];
+    N21[label="expr while y > 0 {\l    y -= 1;\l    while z > 0 { z -= 1; }\l    if x > 10 { return; \"unreachable\"; }\l}\l"];
+    N22[label="expr y"];
+    N23[label="expr 0"];
+    N24[label="expr y > 0"];
     N25[label="expr 1"];
     N26[label="expr y"];
     N27[label="expr y -= 1"];
     N28[label="stmt y -= 1;"];
     N29[label="(dummy_node)"];
-    N30[label="expr z"];
-    N31[label="expr 0"];
-    N32[label="expr z > 0"];
-    N33[label="expr while z > 0 { z -= 1; }"];
+    N30[label="expr while z > 0 { z -= 1; }"];
+    N31[label="expr z"];
+    N32[label="expr 0"];
+    N33[label="expr z > 0"];
     N34[label="expr 1"];
     N35[label="expr z"];
     N36[label="expr z -= 1"];
@@ -63,35 +63,35 @@ digraph block {
     N8 -> N9;
     N9 -> N10;
     N10 -> N11;
-    N11 -> N12;
-    N12 -> N13;
+    N11 -> N13;
     N13 -> N14;
     N14 -> N15;
-    N14 -> N16;
+    N15 -> N12;
+    N15 -> N16;
     N16 -> N17;
     N17 -> N18;
     N18 -> N19;
     N19 -> N20;
-    N20 -> N21;
-    N21 -> N22;
+    N20 -> N22;
     N22 -> N23;
     N23 -> N24;
-    N23 -> N25;
+    N24 -> N21;
+    N24 -> N25;
     N25 -> N26;
     N26 -> N27;
     N27 -> N28;
     N28 -> N29;
-    N29 -> N30;
-    N30 -> N31;
+    N29 -> N31;
     N31 -> N32;
     N32 -> N33;
-    N32 -> N34;
+    N33 -> N30;
+    N33 -> N34;
     N34 -> N35;
     N35 -> N36;
     N36 -> N37;
     N37 -> N38;
     N38 -> N29;
-    N33 -> N39;
+    N30 -> N39;
     N39 -> N40;
     N40 -> N41;
     N41 -> N42;
@@ -105,9 +105,9 @@ digraph block {
     N48 -> N49;
     N49 -> N50;
     N50 -> N20;
-    N24 -> N51;
+    N21 -> N51;
     N51 -> N11;
-    N15 -> N52;
+    N12 -> N52;
     N52 -> N53;
     N53 -> N1;
 }
index 7a0cbfcf517b7133664923a560be2dd6ba10a32a..2ed971bf7d9701659816e74e8553bfe863cdd9e1 100644 (file)
@@ -3,9 +3,9 @@
 ifeq ($(UNAME),Linux)
 all:
        $(RUSTC) foo.rs
-       $(CC) foo.c -lfoo -L $(TMPDIR) -Wl,--gc-sections -lpthread -o $(TMPDIR)/foo
+       $(CC) foo.c -lfoo -L $(TMPDIR) -Wl,--gc-sections -lpthread -ldl -o $(TMPDIR)/foo
        $(call RUN,foo)
-       $(CC) foo.c -lfoo -L $(TMPDIR) -Wl,--gc-sections -lpthread -pie -fPIC -o $(TMPDIR)/foo
+       $(CC) foo.c -lfoo -L $(TMPDIR) -Wl,--gc-sections -lpthread -ldl -pie -fPIC -o $(TMPDIR)/foo
        $(call RUN,foo)
 else
 all:
index 2b3857048f36732acc33f5c524aa8cd6f7fa978c..3db69f2167cc6e4ba7bc5fb89456a7761c532004 100644 (file)
@@ -23,6 +23,7 @@
 use syntax::tokenstream::{TokenTree};
 use syntax::ext::base::{ExtCtxt, MacResult, MacEager};
 use syntax::ext::build::AstBuilder;
+use syntax::ext::tt::quoted;
 use syntax::ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
 use syntax::ext::tt::macro_parser::{Success, Failure, Error};
 use syntax::ext::tt::macro_parser::parse_failure_msg;
@@ -33,7 +34,8 @@
 fn expand_mbe_matches(cx: &mut ExtCtxt, _: Span, args: &[TokenTree])
         -> Box<MacResult + 'static> {
 
-    let mbe_matcher = quote_matcher!(cx, $matched:expr, $($pat:pat)|+);
+    let mbe_matcher = quote_tokens!(cx, $$matched:expr, $$($$pat:pat)|+);
+    let mbe_matcher = quoted::parse(&mbe_matcher, true, cx.parse_sess);
     let map = match TokenTree::parse(cx, &mbe_matcher, args) {
         Success(map) => map,
         Failure(_, tok) => {
index 5383b11cf5363d720858fb93248c2d19a4eacea7..822b2c9b93b4a070d921f681fec3c50818b0c8e8 100644 (file)
 #![feature(plugin)]
 #![plugin(procedural_mbe_matching)]
 
-#[no_link]
-extern crate procedural_mbe_matching;
-
 pub fn main() {
-    let abc = 123u32;
     assert_eq!(matches!(Some(123), None | Some(0)), false);
     assert_eq!(matches!(Some(123), None | Some(123)), true);
     assert_eq!(matches!(true, true), true);
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/bang-macro.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/bang-macro.rs
new file mode 100644 (file)
index 0000000..122a47a
--- /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.
+
+// no-prefer-dynamic
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn rewrite(input: TokenStream) -> TokenStream {
+    let input = input.to_string();
+
+    assert_eq!(input, r#""Hello, world!""#);
+
+    r#""NOT Hello, world!""#.parse().unwrap()
+}
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/issue-39889.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/issue-39889.rs
new file mode 100644 (file)
index 0000000..9094310
--- /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.
+
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Issue39889)]
+pub fn f(_input: TokenStream) -> TokenStream {
+    let rules = r#"
+        macro_rules! id {
+            ($($tt:tt)*) => { $($tt)* };
+        }
+    "#;
+    rules.parse().unwrap()
+}
diff --git a/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs b/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs
new file mode 100644 (file)
index 0000000..531bd0d
--- /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.
+
+// aux-build:bang-macro.rs
+
+#![feature(proc_macro)]
+
+extern crate bang_macro;
+use bang_macro::rewrite;
+
+fn main() {
+    assert_eq!(rewrite!("Hello, world!"), "NOT Hello, world!");
+}
diff --git a/src/test/run-pass-fulldeps/proc-macro/issue-39889.rs b/src/test/run-pass-fulldeps/proc-macro/issue-39889.rs
new file mode 100644 (file)
index 0000000..0561011
--- /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.
+
+// aux-build:issue-39889.rs
+
+#![feature(proc_macro)]
+#![allow(unused)]
+
+extern crate issue_39889;
+use issue_39889::Issue39889;
+
+#[derive(Issue39889)]
+struct S;
+
+fn main() {}
index 9e9b7ce5bf29d2f80de3631ea1b6da9624991272..8e6a69cb58479e1af384cb19729e1554ca4d12dc 100644 (file)
@@ -37,7 +37,6 @@ fn syntax_extension(cx: &ExtCtxt) {
 
     let _l: P<syntax::ast::Ty> = quote_ty!(cx, &isize);
 
-    let _m: Vec<syntax::tokenstream::TokenTree> = quote_matcher!(cx, $($foo:tt,)* bar);
     let _n: syntax::ast::Attribute = quote_attr!(cx, #![cfg(foo, bar = "baz")]);
 
     let _o: Option<P<syntax::ast::Item>> = quote_item!(cx, fn foo<T: ?Sized>() {});
index 1432369f7143dbbf5730f0137cf3f445833bbe34..587fb3f80d6c8a810910d7a31aa2c0451202ef8e 100644 (file)
 
 // Test paths to associated types using the type-parameter-only sugar.
 
+use std::ops::Deref;
 
 pub trait Foo {
     type A;
     fn boo(&self) -> Self::A;
+
+    fn baz(_: Self::Target) where Self: Deref {}
 }
 
 impl Foo for isize {
diff --git a/src/test/run-pass/auxiliary/clibrary.rs b/src/test/run-pass/auxiliary/clibrary.rs
new file mode 100644 (file)
index 0000000..7438ba2
--- /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.
+
+// no-prefer-dynamic
+#![crate_type = "staticlib"]
+
+#[no_mangle]
+pub extern "C" fn foo(x:i32) -> i32 { x }
diff --git a/src/test/run-pass/auxiliary/issue_39823.rs b/src/test/run-pass/auxiliary/issue_39823.rs
new file mode 100644 (file)
index 0000000..5342601
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type="rlib"]
+
+#[derive(Debug, PartialEq)]
+pub struct RemoteC(pub u32);
+
+#[derive(Debug, PartialEq)]
+pub struct RemoteG<T>(pub T);
index 626eccfc9ec866ef56411ecc47245c6cc5522dd5..88fee9ed25b8d5aa93cc54e2583e4a7a5a209b7b 100644 (file)
@@ -141,12 +141,12 @@ fn run_test(me: &str) {
     use std::process::Command;
 
     let mut template = Command::new(me);
-    template.env("RUST_BACKTRACE", "1");
+    template.env("RUST_BACKTRACE", "full");
 
     let mut i = 0;
     loop {
         let out = Command::new(me)
-                          .env("RUST_BACKTRACE", "1")
+                          .env("RUST_BACKTRACE", "full")
                           .arg(i.to_string()).output().unwrap();
         let output = str::from_utf8(&out.stdout).unwrap();
         let error = str::from_utf8(&out.stderr).unwrap();
index 834ce984e6632e50678d4358f50947dafd333037..b3a9e8928be34b1e19645dec6f9461d9d5fc69ae 100644 (file)
@@ -47,7 +47,7 @@ fn template(me: &str) -> Command {
 }
 
 fn expected(fn_name: &str) -> String {
-    format!(" backtrace::{}", fn_name)
+    format!(" backtrace::{}", fn_name)
 }
 
 fn runtest(me: &str) {
@@ -58,6 +58,7 @@ fn runtest(me: &str) {
     let s = str::from_utf8(&out.stderr).unwrap();
     assert!(s.contains("stack backtrace") && s.contains(&expected("foo")),
             "bad output: {}", s);
+    assert!(s.contains(" 0:"), "the frame number should start at 0");
 
     // Make sure the stack trace is *not* printed
     // (Remove RUST_BACKTRACE from our own environment, in case developer
diff --git a/src/test/run-pass/closure-to-fn-coercion.rs b/src/test/run-pass/closure-to-fn-coercion.rs
new file mode 100644 (file)
index 0000000..13d1d6a
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-stage0: new feature, remove this when SNAP
+
+#![feature(closure_to_fn_coercion)]
+
+const FOO: fn(u8) -> u8 = |v: u8| { v };
+
+const BAR: [fn(&mut u32); 5] = [
+    |_: &mut u32| {},
+    |v: &mut u32| *v += 1,
+    |v: &mut u32| *v += 2,
+    |v: &mut u32| *v += 3,
+    |v: &mut u32| *v += 4,
+];
+fn func_specific() -> (fn() -> u32) {
+    || return 42
+}
+
+fn main() {
+    // Items
+    assert_eq!(func_specific()(), 42);
+    let foo: fn(u8) -> u8 = |v: u8| { v };
+    assert_eq!(foo(31), 31);
+    // Constants
+    assert_eq!(FOO(31), 31);
+    let mut a: u32 = 0;
+    assert_eq!({ BAR[0](&mut a); a }, 0);
+    assert_eq!({ BAR[1](&mut a); a }, 1);
+    assert_eq!({ BAR[2](&mut a); a }, 3);
+    assert_eq!({ BAR[3](&mut a); a }, 6);
+    assert_eq!({ BAR[4](&mut a); a }, 10);
+}
diff --git a/src/test/run-pass/enum-layout-optimization.rs b/src/test/run-pass/enum-layout-optimization.rs
new file mode 100644 (file)
index 0000000..a562761
--- /dev/null
@@ -0,0 +1,59 @@
+// 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 we will do various size optimizations to enum layout, but
+// *not* if `#[repr(u8)]` or `#[repr(C)]` is passed. See also #40029.
+
+#![allow(dead_code)]
+
+use std::mem;
+
+enum Nullable<T> {
+    Alive(T),
+    Dropped,
+}
+
+#[repr(u8)]
+enum NullableU8<T> {
+    Alive(T),
+    Dropped,
+}
+
+#[repr(C)]
+enum NullableC<T> {
+    Alive(T),
+    Dropped,
+}
+
+struct StructNewtype<T>(T);
+
+#[repr(C)]
+struct StructNewtypeC<T>(T);
+
+enum EnumNewtype<T> { Variant(T) }
+
+#[repr(u8)]
+enum EnumNewtypeU8<T> { Variant(T) }
+
+#[repr(C)]
+enum EnumNewtypeC<T> { Variant(T) }
+
+fn main() {
+    assert!(mem::size_of::<Box<i32>>() == mem::size_of::<Nullable<Box<i32>>>());
+    assert!(mem::size_of::<Box<i32>>() < mem::size_of::<NullableU8<Box<i32>>>());
+    assert!(mem::size_of::<Box<i32>>() < mem::size_of::<NullableC<Box<i32>>>());
+
+    assert!(mem::size_of::<i32>() == mem::size_of::<StructNewtype<i32>>());
+    assert!(mem::size_of::<i32>() == mem::size_of::<StructNewtypeC<i32>>());
+
+    assert!(mem::size_of::<i32>() == mem::size_of::<EnumNewtype<i32>>());
+    assert!(mem::size_of::<i32>() < mem::size_of::<EnumNewtypeU8<i32>>());
+    assert!(mem::size_of::<i32>() < mem::size_of::<EnumNewtypeC<i32>>());
+}
index c1201e7fa4f4c589c21f875aa26ef3d659defa71..011d910c5a50f6c5721445c3ea92e3cb8a49e6be 100644 (file)
@@ -29,16 +29,3 @@ fn after() -> impl FnMut(i32) {
     let mut p = Box::new(0);
     move |x| *p = x
 }
-
-// Cycles should work as the deferred obligations are
-// independently resolved and only require the concrete
-// return type, which can't depend on the obligation.
-fn cycle1() -> impl Clone {
-    send(cycle2().clone());
-    5
-}
-
-fn cycle2() -> impl Clone {
-    send(cycle1().clone());
-    String::from("foo")
-}
index 72b0e588ff483b3c8a292325074147bb5b404184..ceed454e5ad7e79698ccc8a3b6cf9fdb7b3825e2 100644 (file)
@@ -28,6 +28,17 @@ impl<T> Leak<T> for T {
     fn leak(self) -> T { self }
 }
 
+trait CheckIfSend: Sized {
+    type T: Default;
+    fn check(self) -> Self::T { Default::default() }
+}
+impl<T> CheckIfSend for T {
+    default type T = ();
+}
+impl<T: Send> CheckIfSend for T {
+    type T = bool;
+}
+
 fn lucky_seven() -> impl Fn(usize) -> u8 {
     let a = [1, 2, 3, 4, 5, 6, 7];
     move |i| a[i]
@@ -40,4 +51,6 @@ fn main() {
     assert_eq!(std::mem::size_of_val(&lucky_seven()), 7);
 
     assert_eq!(Leak::<i32>::leak(hide(5_i32)), 5_i32);
+
+    assert_eq!(CheckIfSend::check(hide(0_i32)), false);
 }
index aa9a7afc37f8a05e8ffda790256b8b72b2e58890..c3a0dc67e83edf189a810ef6a053d3fe02cc42a8 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(static_recursion)]
-
 // test that autoderef of a type like this does not
 // cause compiler to loop.  Note that no instances
 // of such a type could ever be constructed.
index 48da7ecc5089dd8b98949c3f0ad6d9c0d5bdeb45..5be4f8e8e73848813eeb780607f25fb646dec75d 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(static_recursion)]
-
 // test that autoderef of a type like this does not
 // cause compiler to loop.  Note that no instances
 // of such a type could ever be constructed.
diff --git a/src/test/run-pass/issue-25145.rs b/src/test/run-pass/issue-25145.rs
new file mode 100644 (file)
index 0000000..6f02f27
--- /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.
+
+#![feature(associated_consts)]
+
+struct S;
+
+impl S {
+    const N: usize = 3;
+}
+
+static STUFF: [u8; S::N] = [0; S::N];
+
+fn main() {
+    assert_eq!(STUFF, [0; 3]);
+}
diff --git a/src/test/run-pass/issue-38972.rs b/src/test/run-pass/issue-38972.rs
new file mode 100644 (file)
index 0000000..d5df84e
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This issue tracks a regression (a new warning) without
+// feature(never_type). When we make that the default, please
+// remove this test.
+
+enum Foo { }
+
+fn make_foo() -> Option<Foo> { None }
+
+#[deny(warnings)]
+fn main() {
+    match make_foo() {
+        None => {},
+        Some(_) => {}
+    }
+}
diff --git a/src/test/run-pass/issue-39548.rs b/src/test/run-pass/issue-39548.rs
new file mode 100644 (file)
index 0000000..7da5067
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+type Array = [(); ((1 < 2) == false) as usize];
+
+fn main() {
+    let _: Array = [];
+}
diff --git a/src/test/run-pass/issue-39709.rs b/src/test/run-pass/issue-39709.rs
new file mode 100644 (file)
index 0000000..ebca931
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    println!("{}", { macro_rules! x { ($(t:tt)*) => {} } 33 });
+}
+
diff --git a/src/test/run-pass/issue-39823.rs b/src/test/run-pass/issue-39823.rs
new file mode 100644 (file)
index 0000000..061a55b
--- /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.
+
+// aux-build:issue_39823.rs
+
+extern crate issue_39823;
+use issue_39823::{RemoteC, RemoteG};
+
+#[derive(Debug, PartialEq)]
+struct LocalC(u32);
+
+#[derive(Debug, PartialEq)]
+struct LocalG<T>(T);
+
+fn main() {
+    let virtual_localc : &Fn(_) -> LocalC = &LocalC;
+    assert_eq!(virtual_localc(1), LocalC(1));
+
+    let virtual_localg : &Fn(_) -> LocalG<u32> = &LocalG;
+    assert_eq!(virtual_localg(1), LocalG(1));
+
+    let virtual_remotec : &Fn(_) -> RemoteC = &RemoteC;
+    assert_eq!(virtual_remotec(1), RemoteC(1));
+
+    let virtual_remoteg : &Fn(_) -> RemoteG<u32> = &RemoteG;
+    assert_eq!(virtual_remoteg(1), RemoteG(1));
+}
diff --git a/src/test/run-pass/iter-sum-overflow-overflow-checks.rs b/src/test/run-pass/iter-sum-overflow-overflow-checks.rs
new file mode 100644 (file)
index 0000000..a3a7179
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C overflow-checks
+
+use std::panic;
+
+fn main() {
+    let r = panic::catch_unwind(|| {
+        [1, i32::max_value()].iter().sum::<i32>();
+    });
+    assert!(r.is_err());
+
+    let r = panic::catch_unwind(|| {
+        [2, i32::max_value()].iter().product::<i32>();
+    });
+    assert!(r.is_err());
+
+    let r = panic::catch_unwind(|| {
+        [1, i32::max_value()].iter().cloned().sum::<i32>();
+    });
+    assert!(r.is_err());
+
+    let r = panic::catch_unwind(|| {
+        [2, i32::max_value()].iter().cloned().product::<i32>();
+    });
+    assert!(r.is_err());
+}
diff --git a/src/test/run-pass/lib-defaults.rs b/src/test/run-pass/lib-defaults.rs
new file mode 100644 (file)
index 0000000..a38080f
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:clibrary.rs
+// compile-flags: -lclibrary
+
+#[link(name = "clibrary", kind = "static")]
+extern "C" {
+    pub fn foo(x:i32) -> i32;
+}
+
+fn main() {
+    unsafe {
+        foo(42);
+    }
+}
index 6a5e051c0c7322d72c18a136b0bca887e537b871..4906a8e71d7a4fad61a4d5b57bbedb7e4d5f7500 100644 (file)
@@ -124,10 +124,18 @@ pub fn main() {
     assert_eq!(nested_break_value, "hello");
 
     let break_from_while_cond = loop {
-        while break {
+        'inner_loop: while break 'inner_loop {
             panic!();
         }
         break 123;
     };
     assert_eq!(break_from_while_cond, 123);
+
+    let break_from_while_to_outer = 'outer_loop: loop {
+        while break 'outer_loop 567 {
+            panic!("from_inner");
+        }
+        panic!("from outer");
+    };
+    assert_eq!(break_from_while_to_outer, 567);
 }
index 493a00ac5d00d947123391101f6ebd60da2c830c..9bda07f077f062f0165950e3b162f940c69b68f6 100644 (file)
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 #![allow(dead_code)]
-#![feature(recover)]
 
 use std::panic::{UnwindSafe, AssertUnwindSafe};
 use std::cell::RefCell;
@@ -40,6 +39,10 @@ fn main() {
     assert::<&RwLock<i32>>();
     assert::<Rc<i32>>();
     assert::<Arc<i32>>();
+    assert::<Box<[u8]>>();
+
+    trait Trait: UnwindSafe {}
+    assert::<Box<Trait>>();
 
     fn bar<T>() {
         assert::<Mutex<T>>();
index f3db102ea5a49ae7579c18671e5772a263217621..4a6ba984eef0a085ecb5f4d33a76d9fd4db8392e 100644 (file)
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(static_recursion)]
-
 static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
 
 struct StaticDoubleLinked {
diff --git a/src/test/run-pass/transmute-from-fn-item-types.rs b/src/test/run-pass/transmute-from-fn-item-types.rs
deleted file mode 100644 (file)
index 574a90e..0000000
+++ /dev/null
@@ -1,27 +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.
-
-#![allow(transmute_from_fn_item_types)]
-
-use std::mem;
-
-fn main() {
-    unsafe {
-        let u = mem::transmute(main);
-        let p = mem::transmute(main);
-        let f = mem::transmute(main);
-        let tuple: (usize, *mut (), fn()) = (u, p, f);
-        assert_eq!(mem::transmute::<_, [usize; 3]>(tuple), [main as usize; 3]);
-
-        mem::transmute::<_, usize>(main);
-        mem::transmute::<_, *mut ()>(main);
-        mem::transmute::<_, fn()>(main);
-    }
-}
index 8d3f9b59bb2eebe0e25cf48f66bb659b267675e5..d4119f5d351c16fecae2c652bae61a8282b16bc1 100644 (file)
 pub trait Foo {
     // @has assoc_consts/trait.Foo.html '//*[@class="rust trait"]' \
     //      'const FOO: usize;'
-    // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO'
-    const FOO: usize;
+    // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
+    // @has - '//*[@class="docblock"]' 'FOO: usize = 12'
+    const FOO: usize = 12;
 }
 
 pub struct Bar;
 
 impl Bar {
     // @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.BAR"]' \
-    //      'const BAR: usize = 3'
+    //      'const BAR: usize'
+    // @has - '//*[@class="docblock"]' 'BAR: usize = 3'
     pub const BAR: usize = 3;
 }
index fe40ce2bd7ddbfd0b494b0f45ea02ca274f091a8..e82e93230aa07bf587a993254928cffffbd15491 100644 (file)
 #![unstable(feature="test", issue="27759")]
 
 // @has issue_27759/unstable/index.html
-// @has - '<code>test</code>'
+// @has - '<code>test </code>'
 // @has - '<a href="http://issue_url/27759">#27759</a>'
 #[unstable(feature="test", issue="27759")]
 pub mod unstable {
     // @has issue_27759/unstable/fn.issue.html
-    // @has - '<code>test_function</code>'
+    // @has - '<code>test_function </code>'
     // @has - '<a href="http://issue_url/1234567890">#1234567890</a>'
     #[unstable(feature="test_function", issue="1234567890")]
     pub fn issue() {}
index 0db92a491ed180d18b654c76994ae97f0b309a8a..493c08693e94a6d1e317f5d69000dff1d4792780 100644 (file)
@@ -16,7 +16,8 @@ pub trait Bar {
     // @has - '//*[@id="associatedtype.Bar"]' 'type Bar = ()'
     // @has - '//*[@href="#associatedtype.Bar"]' 'Bar'
     type Bar = ();
-    // @has - '//*[@id="associatedconstant.Baz"]' 'const Baz: usize = 7'
+    // @has - '//*[@id="associatedconstant.Baz"]' 'const Baz: usize'
+    // @has - '//*[@class="docblock"]' 'Baz: usize = 7'
     // @has - '//*[@href="#associatedconstant.Baz"]' 'Baz'
     const Baz: usize = 7;
     // @has - '//*[@id="tymethod.bar"]' 'fn bar'
index 5cca3708292012159fd47263cd54d9f72cc19346..6d1f8bc1cf9bac27ccfcd6421b6dceea06d9e32c 100644 (file)
 
 // @has issue_32374/struct.T.html '//*[@class="stab deprecated"]' \
 //      'Deprecated since 1.0.0: text'
-// @has - '<code>test</code>'
+// @has - '<code>test </code>'
 // @has - '<a href="http://issue_url/32374">#32374</a>'
 // @matches issue_32374/struct.T.html '//*[@class="stab unstable"]' \
-//      '🔬 This is a nightly-only experimental API.   \(test #32374\)$'
+//      '🔬 This is a nightly-only experimental API.  \(test #32374\)$'
 #[rustc_deprecated(since = "1.0.0", reason = "text")]
 #[unstable(feature = "test", issue = "32374")]
 pub struct T;
 // @has issue_32374/struct.U.html '//*[@class="stab deprecated"]' \
 //      'Deprecated since 1.0.0: deprecated'
 // @has issue_32374/struct.U.html '//*[@class="stab unstable"]' \
-//      '🔬 This is a nightly-only experimental API.  (test #32374)'
+//      '🔬 This is a nightly-only experimental API. (test #32374)'
 // @has issue_32374/struct.U.html '//details' \
-//      '🔬 This is a nightly-only experimental API.  (test #32374)'
+//      '🔬 This is a nightly-only experimental API. (test #32374)'
 // @has issue_32374/struct.U.html '//summary' \
-//      '🔬 This is a nightly-only experimental API.  (test #32374)'
+//      '🔬 This is a nightly-only experimental API. (test #32374)'
 // @has issue_32374/struct.U.html '//details/p' \
 //      'unstable'
 #[rustc_deprecated(since = "1.0.0", reason = "deprecated")]
index c6da6b0575b87c3bef842f051525a3ae3df97920..a34ee908ef295adff271c5ef0aa09044fc29ac78 100644 (file)
@@ -28,18 +28,40 @@ pub trait T<X> {
             fn ignore(_: &X) {}
             const C: X;
             // @has issue_33302/trait.T.html \
-            //        '//*[@class="rust trait"]' 'const D: i32 = 4 * 4;'
-            // @has - '//*[@id="associatedconstant.D"]' 'const D: i32 = 4 * 4'
+            //        '//*[@class="rust trait"]' 'const D: i32'
+            // @has - '//*[@class="docblock"]' 'D: i32 = 4 * 4'
+            // @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
             const D: i32 = ($n * $n);
         }
 
         // @has issue_33302/struct.S.html \
         //        '//h3[@class="impl"]' 'impl T<[i32; 16]> for S'
-        // @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16] = [0; 4 * 4]'
-        // @has - '//*[@id="associatedconstant.D"]' 'const D: i32 = 4 * 4'
+        // @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]'
+        // @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
+        // @has - '//*[@class="docblock"]' 'C: [i32; 16] = [0; 4 * 4]'
         impl T<[i32; ($n * $n)]> for S {
             const C: [i32; ($n * $n)] = [0; ($n * $n)];
         }
+
+        // @has issue_33302/struct.S.html \
+        //        '//h3[@class="impl"]' 'impl T<[i32; 16]> for S'
+        // @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)'
+        // @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32'
+        // @has - '//*[@class="docblock"]' 'C: (i32,) = (4,)'
+        impl T<(i32,)> for S {
+            const C: (i32,) = ($n,);
+        }
+
+        // @has issue_33302/struct.S.html \
+        //        '//h3[@class="impl"]' 'impl T<(i32, i32)> for S'
+        // @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)'
+        // @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32'
+        // @has - '//*[@class="docblock"]' 'C: (i32, i32) = (4, 4)'
+        // @has - '//*[@class="docblock"]' 'D: i32 = 4 / 4'
+        impl T<(i32, i32)> for S {
+            const C: (i32, i32) = ($n, $n);
+            const D: i32 = ($n / $n);
+        }
     }
 }
 
index 423cc9230e893964764852ff20323a3ce3945e19..eef8793511529fab5d904d6b766ce8b8a263d96b 100644 (file)
@@ -1,4 +1,4 @@
-error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted], found `路濫狼á́́`
+error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted], found `路濫狼á́́`
   --> $DIR/unicode.rs:11:8
    |
 11 | extern "路濫狼á́́" fn foo() {}
index b6e3d663e36bddf96e55c4b06b17a0ad372dc0c2..d9871b8970c5cf22b1cd32b70b5b34bbc8f4c32d 100644 (file)
@@ -6,6 +6,9 @@ error[E0053]: method `foo` has an incompatible type for trait
 ...
 19 |     fn foo(x: i16) { }
    |               ^^^ expected u16, found i16
+   |
+   = note: expected type `fn(u16)`
+              found type `fn(i16)`
 
 error[E0053]: method `bar` has an incompatible type for trait
   --> $DIR/E0053.rs:22:12
index 991197c2afba3e23446c775545ca1555a5660ea7..349432f64bbc20cf4af4839fe604639f2c6f7124 100644 (file)
@@ -6,6 +6,9 @@ error[E0053]: method `foo` has an incompatible type for trait
 ...
 21 |     fn foo(x: i16) { }
    |               ^^^ expected u16, found i16
+   |
+   = note: expected type `fn(u16)`
+              found type `fn(i16)`
 
 error[E0053]: method `bar` has an incompatible type for trait
   --> $DIR/trait-impl-fn-incompatibility.rs:22:28
index 881f04300ed036f67ed5dd1c74c8b14375dca2da..fda87de9b9c500bb2f3d151ec33aa14cc7d9ca59 100644 (file)
@@ -1,8 +1,15 @@
-error: `Self` type is used before it's determined
+error[E0391]: unsupported cyclic reference between types/traits detected
   --> $DIR/issue-23305.rs:15:12
    |
 15 | impl ToNbt<Self> {}
-   |            ^^^^
+   |            ^^^^ cyclic reference
+   |
+note: the cycle begins when processing `<impl at $DIR/issue-23305.rs:15:1: 15:20>`...
+  --> $DIR/issue-23305.rs:15:1
+   |
+15 | impl ToNbt<Self> {}
+   | ^^^^^^^^^^^^^^^^^^^
+   = note: ...which then again requires processing `<impl at $DIR/issue-23305.rs:15:1: 15:20>`, completing the cycle.
 
 error: aborting due to previous error
 
index d01ffcb2839b4f6fdd13162ef140962ca2bab576..c7c42bcf239405088ebea527aaae1baa55e460cb 100644 (file)
@@ -46,11 +46,5 @@ error[E0425]: cannot find value `second` in module `m`
 32 |     let b: m::first = m::second; // Misspelled item in module.
    |                       ^^^^^^^^^ did you mean `m::Second`?
 
-error[E0080]: constant evaluation error
-  --> $DIR/levenshtein.rs:30:20
-   |
-30 |     let v = [0u32; MAXITEM]; // Misspelled constant name.
-   |                    ^^^^^^^ unresolved path in constant expression
-
-error: aborting due to previous error
+error: aborting due to 8 previous errors
 
index 81a60a9dd3099ad0aedfb3d4014788f8f77fc49f..4fe6afaca8ec658a4eae9fdba79b35dc37cacb29 100644 (file)
@@ -7,15 +7,6 @@ error[E0204]: the trait `Copy` may not be implemented for this type
 15 | impl Copy for Foo { }
    |      ^^^^
 
-error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/E0204.rs:27:6
-   |
-23 |     Bar { x: Vec<u32> },
-   |           ----------- this field does not implement `Copy`
-...
-27 | impl Copy for EFoo { }
-   |      ^^^^
-
 error[E0204]: the trait `Copy` may not be implemented for this type
   --> $DIR/E0204.rs:17:10
    |
@@ -25,6 +16,15 @@ error[E0204]: the trait `Copy` may not be implemented for this type
 19 |     ty: &'a mut bool,
    |     ---------------- this field does not implement `Copy`
 
+error[E0204]: the trait `Copy` may not be implemented for this type
+  --> $DIR/E0204.rs:27:6
+   |
+23 |     Bar { x: Vec<u32> },
+   |           ----------- this field does not implement `Copy`
+...
+27 | impl Copy for EFoo { }
+   |      ^^^^
+
 error[E0204]: the trait `Copy` may not be implemented for this type
   --> $DIR/E0204.rs:29:10
    |
index 991cd02d215dcdfd782c6216e2c88a61bc28edc5..c2c91487b0c1714f19f39321e6f12fe9270ffe4d 100644 (file)
@@ -215,6 +215,10 @@ fn build_manifest(&mut self) -> Manifest {
         self.package("rust-docs", &mut manifest.pkg, TARGETS);
         self.package("rust-src", &mut manifest.pkg, &["*"]);
 
+        if self.channel == "nightly" {
+            self.package("rust-analysis", &mut manifest.pkg, TARGETS);
+        }
+
         let mut pkg = Package {
             version: self.cached_version("rust").to_string(),
             target: HashMap::new(),
@@ -264,6 +268,12 @@ fn build_manifest(&mut self) -> Manifest {
                         target: target.to_string(),
                     });
                 }
+                if self.channel == "nightly" {
+                    extensions.push(Component {
+                        pkg: "rust-analysis".to_string(),
+                        target: target.to_string(),
+                    });
+                }
             }
             extensions.push(Component {
                 pkg: "rust-src".to_string(),
@@ -273,7 +283,7 @@ fn build_manifest(&mut self) -> Manifest {
             pkg.target.insert(host.to_string(), Target {
                 available: true,
                 url: Some(self.url("rust", host)),
-                hash: Some(to_hex(digest.as_ref())),
+                hash: Some(digest),
                 components: Some(components),
                 extensions: Some(extensions),
             });
@@ -399,19 +409,3 @@ fn write_manifest(&self, manifest: &str, name: &str) {
         self.sign(&dst);
     }
 }
-
-fn to_hex(digest: &[u8]) -> String {
-    let mut ret = String::new();
-    for byte in digest {
-        ret.push(hex((byte & 0xf0) >> 4));
-        ret.push(hex(byte & 0xf));
-    }
-    return ret;
-
-    fn hex(b: u8) -> char {
-        match b {
-            0...9 => (b'0' + b) as char,
-            _ => (b'a' + b - 10) as char,
-        }
-    }
-}
index c9bdcd408ead755ecd571806d107c6010e7d66d2..1ec0838d45f7640a884a08e9cb6f2b021998cedc 100644 (file)
@@ -1987,12 +1987,22 @@ fn get_lines<P: AsRef<Path>>(&self, path: &P,
     fn check_rustdoc_test_option(&self, res: ProcRes) {
         let mut other_files = Vec::new();
         let mut files: HashMap<String, Vec<usize>> = HashMap::new();
-        files.insert(self.testpaths.file.to_str().unwrap().to_owned(),
+        let cwd = env::current_dir().unwrap();
+        files.insert(self.testpaths.file.strip_prefix(&cwd)
+                                        .unwrap_or(&self.testpaths.file)
+                                        .to_str()
+                                        .unwrap()
+                                        .replace('\\', "/"),
                      self.get_lines(&self.testpaths.file, Some(&mut other_files)));
         for other_file in other_files {
             let mut path = self.testpaths.file.clone();
             path.set_file_name(&format!("{}.rs", other_file));
-            files.insert(path.to_str().unwrap().to_owned(), self.get_lines(&path, None));
+            files.insert(path.strip_prefix(&cwd)
+                             .unwrap_or(&path)
+                             .to_str()
+                             .unwrap()
+                             .replace('\\', "/"),
+                         self.get_lines(&path, None));
         }
 
         let mut tested = 0;
@@ -2002,7 +2012,8 @@ fn check_rustdoc_test_option(&self, res: ProcRes) {
                                let tmp: Vec<&str> = s.split(" - ").collect();
                                if tmp.len() == 2 {
                                    let path = tmp[0].rsplit("test ").next().unwrap();
-                                   if let Some(ref mut v) = files.get_mut(path) {
+                                   if let Some(ref mut v) = files.get_mut(
+                                                                &path.replace('\\', "/")) {
                                        tested += 1;
                                        let mut iter = tmp[1].split("(line ");
                                        iter.next();
index f7a452d9f7bd7fef1311a739827ddf7ab7f4a5f3..40318141e04fa57716c45c673ab798eb33357789 100644 (file)
@@ -8,5 +8,5 @@ license = "MIT/Apache-2.0"
 clap = "2.19.3"
 
 [dependencies.mdbook]
-version = "0.0.16"
+version = "0.0.17"
 default-features = false
index 13f272517b1fda9c827a9dc5da2bc6fcca7ec0c6..3e951c85589f8ddc2f62fb482427c11ac36c6d6e 100644 (file)
@@ -116,7 +116,8 @@ pub fn check(path: &Path, bad: &mut bool) {
     });
 
     super::walk_many(&[&path.join("test/compile-fail"),
-                       &path.join("test/compile-fail-fulldeps")],
+                       &path.join("test/compile-fail-fulldeps"),
+                       &path.join("test/parse-fail"),],
                      &mut |path| super::filter_dirs(path),
                      &mut |file| {
         let filename = file.file_name().unwrap().to_string_lossy();
@@ -166,11 +167,9 @@ pub fn check(path: &Path, bad: &mut bool) {
 
     // FIXME get this whitelist empty.
     let whitelist = vec![
-        "abi_ptx", "simd",
-        "cfg_target_has_atomic",
-        "unboxed_closures", "stmt_expr_attributes",
+        "simd",
+        "stmt_expr_attributes",
         "cfg_target_thread_local", "unwind_attributes",
-        "inclusive_range_syntax"
     ];
 
     // Only check the number of lang features.