]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #50644 - kennytm:read-appveyor-dump, r=alexcrichton
authorkennytm <kennytm@gmail.com>
Sun, 13 May 2018 08:15:44 +0000 (16:15 +0800)
committerkennytm <kennytm@gmail.com>
Sun, 13 May 2018 09:20:26 +0000 (17:20 +0800)
AppVeyor: Read back trace from crash dump on failure.

This is an attempt to debug spurious access violations on Windows (#33434, #50604). Thanks to #50276, there should be minidumps to read when rustc segfault.

(The implementation is based on <https://github.com/springmeyer/travis-coredump/blob/master/test.bat>.)

192 files changed:
src/Cargo.lock
src/bootstrap/bin/rustc.rs
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/ci/docker/x86_64-gnu-tools/checktools.sh
src/liballoc/btree/map.rs
src/liballoc/btree/node.rs
src/libcore/tests/time.rs
src/libcore/time.rs
src/librustc/dep_graph/dep_node.rs
src/librustc/dep_graph/graph.rs
src/librustc/hir/itemlikevisit.rs
src/librustc/hir/mod.rs
src/librustc/ich/fingerprint.rs
src/librustc/ich/impls_ty.rs
src/librustc/lint/builtin.rs
src/librustc/middle/const_val.rs
src/librustc/middle/cstore.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/resolve_lifetime.rs
src/librustc/middle/stability.rs
src/librustc/mir/interpret/mod.rs
src/librustc/mir/interpret/value.rs
src/librustc/mir/mod.rs
src/librustc/mir/tcx.rs
src/librustc/session/mod.rs
src/librustc/traits/mod.rs
src/librustc/traits/specialize/mod.rs
src/librustc/ty/codec.rs
src/librustc/ty/context.rs
src/librustc/ty/error.rs
src/librustc/ty/inhabitedness/mod.rs
src/librustc/ty/layout.rs
src/librustc/ty/maps/config.rs
src/librustc/ty/maps/keys.rs
src/librustc/ty/maps/mod.rs
src/librustc/ty/maps/plumbing.rs
src/librustc/ty/mod.rs
src/librustc/ty/relate.rs
src/librustc/ty/sty.rs
src/librustc/ty/util.rs
src/librustc/util/ppaux.rs
src/librustc_data_structures/Cargo.toml
src/librustc_data_structures/control_flow_graph/dominators/mod.rs
src/librustc_data_structures/lib.rs
src/librustc_data_structures/owning_ref/mod.rs
src/librustc_data_structures/sync.rs
src/librustc_driver/Cargo.toml
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_driver/pretty.rs
src/librustc_driver/test.rs
src/librustc_errors/lib.rs
src/librustc_incremental/lib.rs
src/librustc_incremental/persist/mod.rs
src/librustc_incremental/persist/save.rs
src/librustc_incremental/persist/work_product.rs
src/librustc_lint/builtin.rs
src/librustc_lint/lib.rs
src/librustc_llvm/ffi.rs
src/librustc_mir/borrow_check/nll/region_infer/mod.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/librustc_mir/build/expr/as_rvalue.rs
src/librustc_mir/build/matches/test.rs
src/librustc_mir/build/misc.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/cx/mod.rs
src/librustc_mir/hair/pattern/_match.rs
src/librustc_mir/hair/pattern/mod.rs
src/librustc_mir/interpret/const_eval.rs
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/interpret/memory.rs
src/librustc_mir/interpret/mod.rs
src/librustc_mir/interpret/place.rs
src/librustc_mir/lib.rs
src/librustc_mir/monomorphize/collector.rs
src/librustc_mir/monomorphize/item.rs
src/librustc_mir/shim.rs
src/librustc_mir/transform/const_prop.rs
src/librustc_mir/transform/elaborate_drops.rs
src/librustc_mir/transform/generator.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/simplify_branches.rs
src/librustc_mir/transform/uniform_array_move_out.rs
src/librustc_mir/util/elaborate_drops.rs
src/librustc_mir/util/pretty.rs
src/librustc_target/spec/linux_musl_base.rs
src/librustc_target/spec/mod.rs
src/librustc_trans/back/link.rs
src/librustc_trans/back/lto.rs
src/librustc_trans/back/write.rs
src/librustc_trans/base.rs
src/librustc_trans/debuginfo/metadata.rs
src/librustc_trans/debuginfo/type_names.rs
src/librustc_trans/lib.rs
src/librustc_trans/mir/constant.rs
src/librustc_trans/mir/operand.rs
src/librustc_trans/mir/rvalue.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/op.rs
src/librustc_typeck/coherence/builtin.rs
src/librustdoc/clean/mod.rs
src/librustdoc/core.rs
src/librustdoc/html/render.rs
src/librustdoc/lib.rs
src/librustdoc/passes/propagate_doc_cfg.rs
src/librustdoc/test.rs
src/libstd/fs.rs
src/libstd/path.rs
src/libstd/sys/redox/syscall/error.rs
src/libstd/sys/unix/fd.rs
src/libstd/sys_common/wtf8.rs
src/libsyntax/edition.rs
src/libsyntax/feature_gate.rs
src/libsyntax/lib.rs
src/libsyntax_ext/format_foreign.rs
src/libsyntax_pos/Cargo.toml
src/libsyntax_pos/lib.rs
src/libsyntax_pos/symbol.rs
src/rustllvm/PassWrapper.cpp
src/test/codegen/link_section.rs
src/test/compile-fail/auxiliary/edition-extern-crate-allowed.rs [new file with mode: 0644]
src/test/compile-fail/edition-extern-crate-allowed.rs [new file with mode: 0644]
src/test/compile-fail/edition-feature-ok.rs [new file with mode: 0644]
src/test/run-make-fulldeps/issue-36710/Makefile [new file with mode: 0644]
src/test/run-make-fulldeps/issue-36710/foo.cpp [new file with mode: 0644]
src/test/run-make-fulldeps/issue-36710/foo.rs [new file with mode: 0644]
src/test/run-make-fulldeps/tools.mk
src/test/run-pass/atomic-print.rs
src/test/run-pass/union/union-trait-impl.rs
src/test/ui-fulldeps/unnecessary-extern-crate.rs
src/test/ui-fulldeps/unnecessary-extern-crate.stderr
src/test/ui/binary-op-on-double-ref.stderr
src/test/ui/codemap_tests/issue-28308.stderr
src/test/ui/const-eval/duration_conversion.rs [new file with mode: 0644]
src/test/ui/error-codes/E0067.stderr
src/test/ui/error-codes/E0600.stderr
src/test/ui/error-festival.stderr
src/test/ui/feature-gate-negate-unsigned.stderr
src/test/ui/in-band-lifetimes/single_use_lifetimes-2.rs [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes-2.stderr [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes-3.rs [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes-3.stderr [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes-4.rs [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes-4.stderr [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes-5.rs [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes-5.stderr [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes.rs [deleted file]
src/test/ui/in-band-lifetimes/single_use_lifetimes.stderr [deleted file]
src/test/ui/issue-50480.rs [new file with mode: 0644]
src/test/ui/issue-50480.stderr [new file with mode: 0644]
src/test/ui/issue-5239-1.stderr
src/test/ui/lint/unreachable_pub-pub_crate.rs
src/test/ui/lint/unreachable_pub-pub_crate.stderr
src/test/ui/lint/unreachable_pub.rs
src/test/ui/lint/unreachable_pub.stderr
src/test/ui/reachable/expr_unary.stderr
src/test/ui/single-use-lifetime/fn-types.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/fn-types.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-fn-argument.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-fn-return.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-struct.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/two-uses-in-fn-argument-and-return.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/two-uses-in-fn-arguments.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/two-uses-in-inherent-impl-header.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/two-uses-in-trait-impl.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/zero-uses-in-fn.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/zero-uses-in-fn.stderr [new file with mode: 0644]
src/test/ui/single-use-lifetime/zero-uses-in-impl.rs [new file with mode: 0644]
src/test/ui/single-use-lifetime/zero-uses-in-impl.stderr [new file with mode: 0644]
src/test/ui/type-check/missing_trait_impl.rs
src/test/ui/type-check/missing_trait_impl.stderr
src/tools/clippy
src/tools/compiletest/src/runtest.rs
src/tools/miri
src/tools/tidy/src/deps.rs
src/tools/tidy/src/libcoretest.rs

index e2a9a6efbdad4fc855a0794e2c748903ff1cef17..4cb82f94251ff62ab3a94082220fbebb0d899478 100644 (file)
@@ -79,15 +79,15 @@ dependencies = [
 
 [[package]]
 name = "assert_cli"
-version = "0.5.4"
+version = "0.5.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -183,11 +183,6 @@ dependencies = [
 name = "build_helper"
 version = "0.1.0"
 
-[[package]]
-name = "bytecount"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "byteorder"
 version = "1.2.2"
@@ -233,25 +228,13 @@ dependencies = [
  "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "cargo_metadata"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "cargo_metadata"
 version = "0.5.4"
@@ -305,15 +288,17 @@ dependencies = [
 
 [[package]]
 name = "clippy"
-version = "0.0.197"
+version = "0.0.198"
 dependencies = [
+ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "clippy-mini-macro-test 0.2.0",
- "clippy_lints 0.0.197",
+ "clippy_lints 0.0.198",
  "compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -326,6 +311,7 @@ version = "0.2.0"
 [[package]]
 name = "clippy_lints"
 version = "0.0.197"
+source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -343,6 +329,26 @@ dependencies = [
  "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "clippy_lints"
+version = "0.0.198"
+dependencies = [
+ "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "cmake"
 version = "0.1.30"
@@ -417,7 +423,7 @@ dependencies = [
  "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -551,12 +557,12 @@ version = "0.1.0"
 
 [[package]]
 name = "derive-new"
-version = "0.5.2"
+version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -564,11 +570,6 @@ name = "diff"
 version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "difference"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "difference"
 version = "2.0.0"
@@ -1169,7 +1170,7 @@ dependencies = [
  "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1429,14 +1430,6 @@ dependencies = [
  "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "proc-macro2"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "proc-macro2"
 version = "0.3.6"
@@ -1488,14 +1481,6 @@ name = "quote"
 version = "0.3.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "quote"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "quote"
 version = "0.5.1"
@@ -1565,7 +1550,7 @@ dependencies = [
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1601,6 +1586,18 @@ dependencies = [
  "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "regex"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "regex-syntax"
 version = "0.5.5"
@@ -1609,6 +1606,14 @@ dependencies = [
  "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "regex-syntax"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "remote-test-client"
 version = "0.1.0"
@@ -1631,7 +1636,7 @@ version = "0.127.0"
 dependencies = [
  "cargo 0.28.0",
  "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "clippy_lints 0.0.197",
+ "clippy_lints 0.0.197 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1660,7 +1665,7 @@ name = "rls-analysis"
 version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1839,6 +1844,27 @@ dependencies = [
  "rustc_target 0.0.0",
 ]
 
+[[package]]
+name = "rustc-rayon"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-rayon-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc-rayon-core"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "rustc-serialize"
 version = "0.3.24"
@@ -1906,6 +1932,7 @@ dependencies = [
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_cratesio_shim 0.0.0",
  "serialize 0.0.0",
  "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1921,6 +1948,7 @@ dependencies = [
  "graphviz 0.0.0",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
+ "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_allocator 0.0.0",
  "rustc_borrowck 0.0.0",
  "rustc_data_structures 0.0.0",
@@ -1938,6 +1966,7 @@ dependencies = [
  "rustc_traits 0.0.0",
  "rustc_trans_utils 0.0.0",
  "rustc_typeck 0.0.0",
+ "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serialize 0.0.0",
  "syntax 0.0.0",
  "syntax_ext 0.0.0",
@@ -2218,6 +2247,14 @@ dependencies = [
  "syntax_pos 0.0.0",
 ]
 
+[[package]]
+name = "rustc_version"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "rustdoc"
 version = "0.0.0"
@@ -2252,9 +2289,9 @@ dependencies = [
 name = "rustfmt-nightly"
 version = "0.6.1"
 dependencies = [
- "assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "assert_cli 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2275,15 +2312,6 @@ dependencies = [
  "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "same-file"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "same-file"
 version = "1.0.2"
@@ -2311,15 +2339,6 @@ name = "scopeguard"
 version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "semver"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "semver"
 version = "0.9.0"
@@ -2397,21 +2416,6 @@ name = "siphasher"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "skeptic"
-version = "0.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "smallvec"
 version = "0.6.0"
@@ -2522,16 +2526,6 @@ dependencies = [
  "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "syn"
-version = "0.12.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "syn"
 version = "0.13.1"
@@ -2590,6 +2584,7 @@ dependencies = [
 name = "syntax_pos"
 version = "0.0.0"
 dependencies = [
+ "arena 0.0.0",
  "rustc_data_structures 0.0.0",
  "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serialize 0.0.0",
@@ -2654,7 +2649,7 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.0.1"
+version = "3.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2915,16 +2910,6 @@ name = "void"
 version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "walkdir"
-version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "walkdir"
 version = "2.1.4"
@@ -3002,7 +2987,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
 "checksum ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35c7a5669cb64f085739387e1308b74e6d44022464b7f1b63bbd4ceb6379ec31"
 "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
-"checksum assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72342c21057a3cb5f7c2d849bf7999a83795434dd36d74fa8c24680581bd1930"
+"checksum assert_cli 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8ca6beaa44a3520407b28a4a779a19b1364fcadcb2f258c41a7baf3102ced0"
 "checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4"
 "checksum backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe525f66f42d207968308ee86bc2dd60aa5fab535b22e616323a173d097d8e"
 "checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"
@@ -3010,14 +2995,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
 "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
 "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32"
-"checksum bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af27422163679dea46a1a7239dffff64d3dcdc3ba5fe9c49c789fbfe0eb949de"
 "checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87"
-"checksum cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f56ec3e469bca7c276f2eea015aa05c5e381356febdbb0683c2580189604537"
 "checksum cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebd6272a2ca4fd39dbabbd6611eb03df45c2259b3b80b39a9ff8fbdcf42a4b3"
 "checksum cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebb87d1116151416c0cf66a0e3fb6430cccd120fd6300794b4dfaa050ac40ba"
 "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
 "checksum chrono 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ba5f60682a4c264e7f8d77b82e7788938a76befdf949d4a98026d19099c9d873"
 "checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
+"checksum clippy_lints 0.0.197 (registry+https://github.com/rust-lang/crates.io-index)" = "ee3b543abb36b1557180d41dd3758581254644d85d021df7f8f8cb395054581c"
 "checksum cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5cf678ceebedde428000cb3a34465cf3606d1a48da17014948a916deac39da7c"
 "checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc"
 "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007"
@@ -3033,9 +3017,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf20bbe084f285f215eef2165feed70d6b75ba29cad24469badb853a4a287d0"
 "checksum curl-sys 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71c63a540a9ee4e15e56c3ed9b11a2f121239b9f6d7b7fe30f616e048148df9a"
 "checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3"
-"checksum derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fcb923bab47a948f1b01cec2f758fdebba95c9ebc255458654b2b88efe59d71"
+"checksum derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ceed73957c449214f8440eec8ad7fa282b67dc9eacbb24a3085b15d60397a17a"
 "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a"
-"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8"
 "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
 "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
 "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
@@ -3126,13 +3109,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
 "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 "checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6"
-"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0"
 "checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118"
 "checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32"
 "checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
 "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45"
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
-"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408"
 "checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a"
 "checksum racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "40d44bc30fc8d403b665286b2c9a83466ddbf69297668fb02b785c3e58eb8e0d"
 "checksum radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "03d0d770481e8af620ca61d3d304bf014f965d7f78e923dc58545e6a545070a9"
@@ -3143,7 +3124,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
 "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
 "checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb"
+"checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3"
 "checksum regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd90079345f4a4c3409214734ae220fd773c6f2e8a543d07370c6c1c369cfbfb"
+"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b"
 "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
 "checksum rls-analysis 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a41488cf5dc99d6ce383319d2978756567b70d4ed0539eb0d9ce07763e732e46"
 "checksum rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a9cc2545ccb7e05b355bfe047b8039a6ec12270d5f3c996b766b340a50f7d2"
@@ -3159,14 +3142,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum rustc-ap-syntax 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b50671adb9b0a7c57a4690ac6a40cb614879f543b64aada42f55b66212492323"
 "checksum rustc-ap-syntax_pos 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "55793c2a775230c42661194c48d44b35d4c8439d79ad8528e56651e854c48c63"
 "checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb"
+"checksum rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1aa5cd8c3a706edb19b6ec6aa7b056bdc635b6e99c5cf7014f9af9d92f15e99"
+"checksum rustc-rayon-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d69983f8613a9c3ba1a3bbf5e8bdf2fd5c42317b1d8dd8623ca8030173bf8a6b"
 "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
+"checksum rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a54aa04a10c68c1c4eacb4337fd883b435997ede17a9385784b990777686b09a"
 "checksum rustfix 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "165a212dd11124d7070892da20f71d82970ef1d1dd41cd804b70f39740a21c85"
-"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
 "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
 "checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade"
 "checksum scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8674d439c964889e2476f474a3bf198cc9e199e77499960893bac5de7e9218a4"
 "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
-"checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b"
 "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
 "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
 "checksum serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "29465552c9b767d0cb44be3ddf4c3214be15d34975a7750f6cf4f409835f0248"
@@ -3177,7 +3161,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9"
 "checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
 "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
-"checksum skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c8431f8fca168e2db4be547bd8329eac70d095dff1444fee4b0fa0fabc7df75a"
 "checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9"
 "checksum socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ff606e0486e88f5fc6cfeb3966e434fb409abbc7a3ab495238f70a1ca97f789d"
 "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
@@ -3188,7 +3171,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "099e21b5dd6dd07b5adcf8c4b723a7c0b7efd7a9359bf963d58c0caae8532545"
 "checksum strum_macros 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd9bd569e88028750e3ae5c25616b8278ac16a8e61aba4339195c72396d49e1"
 "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
-"checksum syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5"
 "checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
 "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
 "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd"
@@ -3197,7 +3179,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde"
 "checksum tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6af6b94659f9a571bf769a5b71f54079393585ee0bfdd71b691be22d7d6b1d18"
 "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
-"checksum tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8cddbd26c5686ece823b507f304c8f188daef548b4cb753512d929ce478a093c"
+"checksum tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47776f63b85777d984a50ce49d6b9e58826b6a3766a449fc95bc66cd5663c15b"
 "checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508"
 "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
 "checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561"
@@ -3227,7 +3209,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ed0f6789c8a85ca41bbc1c9d175422116a9869bd1cf31bb08e1493ecce60380"
 "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
 "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
-"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
 "checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369"
 "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
 "checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
index 3f97accaa4d84088ecbd8524e359d653dda4aa6c..76d0e6e28aeda75e779ea703e8563dc01e2b4004 100644 (file)
@@ -268,6 +268,15 @@ fn main() {
         if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
             cmd.arg(format!("-Clinker={}", host_linker));
         }
+
+        if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
+            if s == "true" {
+                cmd.arg("-C").arg("target-feature=+crt-static");
+            }
+            if s == "false" {
+                cmd.arg("-C").arg("target-feature=-crt-static");
+            }
+        }
     }
 
     if env::var_os("RUSTC_PARALLEL_QUERIES").is_some() {
index 487440becf630de7471c0228bab09c014e33d2ac..28f5192f2cdf455d9e6730f64ce324ab679a8af5 100644 (file)
@@ -489,7 +489,7 @@ class RustBuild(object):
         """
         return os.path.join(self.build_dir, self.build, "stage0")
 
-    def get_toml(self, key):
+    def get_toml(self, key, section=None):
         """Returns the value of the given key in config.toml, otherwise returns None
 
         >>> rb = RustBuild()
@@ -501,12 +501,29 @@ class RustBuild(object):
 
         >>> rb.get_toml("key3") is None
         True
+
+        Optionally also matches the section the key appears in
+
+        >>> rb.config_toml = '[a]\\nkey = "value1"\\n[b]\\nkey = "value2"'
+        >>> rb.get_toml('key', 'a')
+        'value1'
+        >>> rb.get_toml('key', 'b')
+        'value2'
+        >>> rb.get_toml('key', 'c') is None
+        True
         """
+
+        cur_section = None
         for line in self.config_toml.splitlines():
+            section_match = re.match(r'^\s*\[(.*)\]\s*$', line)
+            if section_match is not None:
+                cur_section = section_match.group(1)
+
             match = re.match(r'^{}\s*=(.*)$'.format(key), line)
             if match is not None:
                 value = match.group(1)
-                return self.get_string(value) or value.strip()
+                if section is None or section == cur_section:
+                    return self.get_string(value) or value.strip()
         return None
 
     def cargo(self):
@@ -589,7 +606,17 @@ class RustBuild(object):
         env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
             (os.pathsep + env["LIBRARY_PATH"]) \
             if "LIBRARY_PATH" in env else ""
-        env["RUSTFLAGS"] = "-Cdebuginfo=2"
+        env["RUSTFLAGS"] = "-Cdebuginfo=2 "
+
+        build_section = "target.{}".format(self.build_triple())
+        target_features = []
+        if self.get_toml("crt-static", build_section) == "true":
+            target_features += ["+crt-static"]
+        elif self.get_toml("crt-static", build_section) == "false":
+            target_features += ["-crt-static"]
+        if target_features:
+            env["RUSTFLAGS"] += "-C target-feature=" + (",".join(target_features)) + " "
+
         env["PATH"] = os.path.join(self.bin_root(), "bin") + \
             os.pathsep + env["PATH"]
         if not os.path.isfile(self.cargo()):
index f87436504c6c62a03cab9a5705fb989f82bdf255..17f19222e6ea65637828e5cae38dbb0ab8e604d2 100644 (file)
@@ -690,6 +690,10 @@ pub fn cargo(&self,
             cargo.env("RUSTC_CRT_STATIC", x.to_string());
         }
 
+        if let Some(x) = self.crt_static(compiler.host) {
+            cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string());
+        }
+
         // Enable usage of unstable features
         cargo.env("RUSTC_BOOTSTRAP", "1");
         self.add_rust_test_threads(&mut cargo);
index 3fed0175371a7d494ec1d1bdaf790a7e73b4588d..d71d5daf8113bf4abb59d51101467e85985fc250 100755 (executable)
@@ -23,6 +23,8 @@ SIX_WEEK_CYCLE="$(( ($(date +%s) / 604800 - 3) % 6 ))"
 
 touch "$TOOLSTATE_FILE"
 
+# Try to test all the tools and store the build/test success in the TOOLSTATE_FILE
+
 set +e
 python2.7 "$X_PY" test --no-fail-fast \
     src/doc/book \
@@ -38,6 +40,7 @@ set -e
 cat "$TOOLSTATE_FILE"
 echo
 
+# This function checks that if a tool's submodule changed, the tool's state must improve
 verify_status() {
     echo "Verifying status of $1..."
     if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]$2$"; then
@@ -57,17 +60,36 @@ verify_status() {
     fi
 }
 
+# deduplicates the submodule check and the assertion that on beta some tools MUST be passing
+check_dispatch() {
+    if [ "$1" = submodule_changed ]; then
+        # ignore $2 (branch id)
+        verify_status $3 $4
+    elif [ "$2" = beta ]; then
+        echo "Requiring test passing for $3..."
+        if grep -q '"'"$3"'":"\(test\|build\)-fail"' "$TOOLSTATE_FILE"; then
+            exit 4
+        fi
+    fi
+}
+
+# list all tools here
+status_check() {
+    check_dispatch $1 beta book src/doc/book
+    check_dispatch $1 beta nomicon src/doc/nomicon
+    check_dispatch $1 beta reference src/doc/reference
+    check_dispatch $1 beta rust-by-example src/doc/rust-by-example
+    check_dispatch $1 beta rls src/tool/rls
+    check_dispatch $1 beta rustfmt src/tool/rustfmt
+    # these tools are not required for beta to successfully branch
+    check_dispatch $1 nightly clippy-driver src/tool/clippy
+    check_dispatch $1 nightly miri src/tool/miri
+}
+
 # If this PR is intended to update one of these tools, do not let the build pass
 # when they do not test-pass.
 
-verify_status book src/doc/book
-verify_status nomicon src/doc/nomicon
-verify_status reference src/doc/reference
-verify_status rust-by-example src/doc/rust-by-example
-verify_status rls src/tool/rls
-verify_status rustfmt src/tool/rustfmt
-verify_status clippy-driver src/tool/clippy
-verify_status miri src/tool/miri
+status_check "submodule_changed"
 
 if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then
     . "$(dirname $0)/repo.sh"
@@ -86,6 +108,6 @@ $COMMIT\t$(cat "$TOOLSTATE_FILE")
     exit 0
 fi
 
-if grep -q fail "$TOOLSTATE_FILE"; then
-    exit 4
-fi
+# abort compilation if an important tool doesn't build
+# (this code is reachable if not on the nightly channel)
+status_check "beta_required"
index 3984379ea860dd3eabbb099da3c691cb78fcab61..bb2c68a27ba308f3ba1e825d57bbabd678e20cc4 100644 (file)
@@ -246,6 +246,7 @@ fn take(&mut self, key: &Q) -> Option<K> {
     }
 
     fn replace(&mut self, key: K) -> Option<K> {
+        self.ensure_root_is_owned();
         match search::search_tree::<marker::Mut, K, (), K>(self.root.as_mut(), &key) {
             Found(handle) => Some(mem::replace(handle.into_kv_mut().0, key)),
             GoDown(handle) => {
@@ -523,7 +524,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new() -> BTreeMap<K, V> {
         BTreeMap {
-            root: node::Root::new_leaf(),
+            root: node::Root::shared_empty_root(),
             length: 0,
         }
     }
@@ -544,7 +545,6 @@ pub fn new() -> BTreeMap<K, V> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn clear(&mut self) {
-        // FIXME(gereeter) .clear() allocates
         *self = BTreeMap::new();
     }
 
@@ -890,6 +890,8 @@ pub fn range_mut<T: ?Sized, R>(&mut self, range: R) -> RangeMut<K, V>
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn entry(&mut self, key: K) -> Entry<K, V> {
+        // FIXME(@porglezomp) Avoid allocating if we don't insert
+        self.ensure_root_is_owned();
         match search::search_tree(self.root.as_mut(), &key) {
             Found(handle) => {
                 Occupied(OccupiedEntry {
@@ -910,6 +912,7 @@ pub fn entry(&mut self, key: K) -> Entry<K, V> {
     }
 
     fn from_sorted_iter<I: Iterator<Item = (K, V)>>(&mut self, iter: I) {
+        self.ensure_root_is_owned();
         let mut cur_node = last_leaf_edge(self.root.as_mut()).into_node();
         // Iterate through all key-value pairs, pushing them into nodes at the right level.
         for (key, value) in iter {
@@ -1019,6 +1022,7 @@ pub fn split_off<Q: ?Sized + Ord>(&mut self, key: &Q) -> Self
         let total_num = self.len();
 
         let mut right = Self::new();
+        right.root = node::Root::new_leaf();
         for _ in 0..(self.root.as_ref().height()) {
             right.root.push_level();
         }
@@ -1153,6 +1157,13 @@ fn fix_left_border(&mut self) {
 
         self.fix_top();
     }
+
+    /// If the root node is the shared root node, allocate our own node.
+    fn ensure_root_is_owned(&mut self) {
+        if self.root.is_shared_root() {
+            self.root = node::Root::new_leaf();
+        }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1290,6 +1301,10 @@ fn drop(&mut self) {
         self.for_each(drop);
         unsafe {
             let leaf_node = ptr::read(&self.front).into_node();
+            if leaf_node.is_shared_root() {
+                return;
+            }
+
             if let Some(first_parent) = leaf_node.deallocate_and_ascend() {
                 let mut cur_node = first_parent.into_node();
                 while let Some(parent) = cur_node.deallocate_and_ascend() {
index d6346662314e65ae993a498ff4ffba1fb9579f30..431695c32ab68f8f9d35bef16a9442cb6a35d5cb 100644 (file)
 ///
 /// See also rust-lang/rfcs#197, which would make this structure significantly more safe by
 /// avoiding accidentally dropping unused and uninitialized keys and values.
+///
+/// We put the metadata first so that its position is the same for every `K` and `V`, in order
+/// to statically allocate a single dummy node to avoid allocations. This struct is `repr(C)` to
+/// prevent them from being reordered.
+#[repr(C)]
 struct LeafNode<K, V> {
-    /// The arrays storing the actual data of the node. Only the first `len` elements of each
-    /// array are initialized and valid.
-    keys: [K; CAPACITY],
-    vals: [V; CAPACITY],
-
     /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`.
     /// This either points to an actual node or is null.
     parent: *const InternalNode<K, V>,
@@ -77,10 +77,14 @@ struct LeafNode<K, V> {
 
     /// The number of keys and values this node stores.
     ///
-    /// This is at the end of the node's representation and next to `parent_idx` to encourage
-    /// the compiler to join `len` and `parent_idx` into the same 32-bit word, reducing space
-    /// overhead.
+    /// This next to `parent_idx` to encourage the compiler to join `len` and
+    /// `parent_idx` into the same 32-bit word, reducing space overhead.
     len: u16,
+
+    /// The arrays storing the actual data of the node. Only the first `len` elements of each
+    /// array are initialized and valid.
+    keys: [K; CAPACITY],
+    vals: [V; CAPACITY],
 }
 
 impl<K, V> LeafNode<K, V> {
@@ -97,8 +101,26 @@ unsafe fn new() -> Self {
             len: 0
         }
     }
+
+    fn is_shared_root(&self) -> bool {
+        self as *const _ == &EMPTY_ROOT_NODE as *const _ as *const LeafNode<K, V>
+    }
 }
 
+// We need to implement Sync here in order to make a static instance.
+unsafe impl Sync for LeafNode<(), ()> {}
+
+// An empty node used as a placeholder for the root node, to avoid allocations.
+// We use () in order to save space, since no operation on an empty tree will
+// ever take a pointer past the first key.
+static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode {
+    parent: ptr::null(),
+    parent_idx: 0,
+    len: 0,
+    keys: [(); CAPACITY],
+    vals: [(); CAPACITY],
+};
+
 /// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden
 /// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an
 /// `InternalNode` can be directly casted to a pointer to the underlying `LeafNode` portion of the
@@ -168,6 +190,21 @@ unsafe impl<K: Sync, V: Sync> Sync for Root<K, V> { }
 unsafe impl<K: Send, V: Send> Send for Root<K, V> { }
 
 impl<K, V> Root<K, V> {
+    pub fn is_shared_root(&self) -> bool {
+        self.as_ref().is_shared_root()
+    }
+
+    pub fn shared_empty_root() -> Self {
+        Root {
+            node: unsafe {
+                BoxedNode::from_ptr(NonNull::new_unchecked(
+                    &EMPTY_ROOT_NODE as *const _ as *const LeafNode<K, V> as *mut _
+                ))
+            },
+            height: 0,
+        }
+    }
+
     pub fn new_leaf() -> Self {
         Root {
             node: BoxedNode::from_leaf(Box::new(unsafe { LeafNode::new() })),
@@ -209,6 +246,7 @@ pub fn into_ref(self)
     /// new node the root. This increases the height by 1 and is the opposite of `pop_level`.
     pub fn push_level(&mut self)
             -> NodeRef<marker::Mut, K, V, marker::Internal> {
+        debug_assert!(!self.is_shared_root());
         let mut new_node = Box::new(unsafe { InternalNode::new() });
         new_node.edges[0] = unsafe { BoxedNode::from_ptr(self.node.as_ptr()) };
 
@@ -353,12 +391,16 @@ fn as_leaf(&self) -> &LeafNode<K, V> {
         }
     }
 
+    pub fn is_shared_root(&self) -> bool {
+        self.as_leaf().is_shared_root()
+    }
+
     pub fn keys(&self) -> &[K] {
-        self.reborrow().into_slices().0
+        self.reborrow().into_key_slice()
     }
 
-    pub fn vals(&self) -> &[V] {
-        self.reborrow().into_slices().1
+    fn vals(&self) -> &[V] {
+        self.reborrow().into_val_slice()
     }
 
     /// Finds the parent of the current node. Returns `Ok(handle)` if the current
@@ -433,6 +475,7 @@ pub unsafe fn deallocate_and_ascend(self) -> Option<
             marker::Edge
         >
     > {
+        debug_assert!(!self.is_shared_root());
         let node = self.node;
         let ret = self.ascend().ok();
         Global.dealloc(node.as_opaque(), Layout::new::<LeafNode<K, V>>());
@@ -500,30 +543,51 @@ fn as_leaf_mut(&mut self) -> &mut LeafNode<K, V> {
         }
     }
 
-    pub fn keys_mut(&mut self) -> &mut [K] {
-        unsafe { self.reborrow_mut().into_slices_mut().0 }
+    fn keys_mut(&mut self) -> &mut [K] {
+        unsafe { self.reborrow_mut().into_key_slice_mut() }
     }
 
-    pub fn vals_mut(&mut self) -> &mut [V] {
-        unsafe { self.reborrow_mut().into_slices_mut().1 }
+    fn vals_mut(&mut self) -> &mut [V] {
+        unsafe { self.reborrow_mut().into_val_slice_mut() }
     }
 }
 
 impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
-    pub fn into_slices(self) -> (&'a [K], &'a [V]) {
-        unsafe {
-            (
+    fn into_key_slice(self) -> &'a [K] {
+        // When taking a pointer to the keys, if our key has a stricter
+        // alignment requirement than the shared root does, then the pointer
+        // would be out of bounds, which LLVM assumes will not happen. If the
+        // alignment is more strict, we need to make an empty slice that doesn't
+        // use an out of bounds pointer.
+        if mem::align_of::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() {
+            &[]
+        } else {
+            // Here either it's not the root, or the alignment is less strict,
+            // in which case the keys pointer will point "one-past-the-end" of
+            // the node, which is allowed by LLVM.
+            unsafe {
                 slice::from_raw_parts(
                     self.as_leaf().keys.as_ptr(),
                     self.len()
-                ),
-                slice::from_raw_parts(
-                    self.as_leaf().vals.as_ptr(),
-                    self.len()
                 )
+            }
+        }
+    }
+
+    fn into_val_slice(self) -> &'a [V] {
+        debug_assert!(!self.is_shared_root());
+        unsafe {
+            slice::from_raw_parts(
+                self.as_leaf().vals.as_ptr(),
+                self.len()
             )
         }
     }
+
+    fn into_slices(self) -> (&'a [K], &'a [V]) {
+        let k = unsafe { ptr::read(&self) };
+        (k.into_key_slice(), self.into_val_slice())
+    }
 }
 
 impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
@@ -535,20 +599,33 @@ pub fn into_root_mut(self) -> &'a mut Root<K, V> {
         }
     }
 
-    pub fn into_slices_mut(mut self) -> (&'a mut [K], &'a mut [V]) {
-        unsafe {
-            (
+    fn into_key_slice_mut(mut self) -> &'a mut [K] {
+        if mem::align_of::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() {
+            &mut []
+        } else {
+            unsafe {
                 slice::from_raw_parts_mut(
                     &mut self.as_leaf_mut().keys as *mut [K] as *mut K,
                     self.len()
-                ),
-                slice::from_raw_parts_mut(
-                    &mut self.as_leaf_mut().vals as *mut [V] as *mut V,
-                    self.len()
                 )
+            }
+        }
+    }
+
+    fn into_val_slice_mut(mut self) -> &'a mut [V] {
+        debug_assert!(!self.is_shared_root());
+        unsafe {
+            slice::from_raw_parts_mut(
+                &mut self.as_leaf_mut().vals as *mut [V] as *mut V,
+                self.len()
             )
         }
     }
+
+    fn into_slices_mut(self) -> (&'a mut [K], &'a mut [V]) {
+        let k = unsafe { ptr::read(&self) };
+        (k.into_key_slice_mut(), self.into_val_slice_mut())
+    }
 }
 
 impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
@@ -556,6 +633,7 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
     pub fn push(&mut self, key: K, val: V) {
         // Necessary for correctness, but this is an internal module
         debug_assert!(self.len() < CAPACITY);
+        debug_assert!(!self.is_shared_root());
 
         let idx = self.len();
 
@@ -571,6 +649,7 @@ pub fn push(&mut self, key: K, val: V) {
     pub fn push_front(&mut self, key: K, val: V) {
         // Necessary for correctness, but this is an internal module
         debug_assert!(self.len() < CAPACITY);
+        debug_assert!(!self.is_shared_root());
 
         unsafe {
             slice_insert(self.keys_mut(), 0, key);
@@ -884,6 +963,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge
     fn insert_fit(&mut self, key: K, val: V) -> *mut V {
         // Necessary for correctness, but in a private module
         debug_assert!(self.node.len() < CAPACITY);
+        debug_assert!(!self.node.is_shared_root());
 
         unsafe {
             slice_insert(self.node.keys_mut(), self.idx, key);
@@ -1061,6 +1141,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV>
     ///   allocated node.
     pub fn split(mut self)
             -> (NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, K, V, Root<K, V>) {
+        debug_assert!(!self.node.is_shared_root());
         unsafe {
             let mut new_node = Box::new(LeafNode::new());
 
@@ -1098,6 +1179,7 @@ pub fn split(mut self)
     /// now adjacent key/value pairs to the left and right of this handle.
     pub fn remove(mut self)
             -> (Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>, K, V) {
+        debug_assert!(!self.node.is_shared_root());
         unsafe {
             let k = slice_remove(self.node.keys_mut(), self.idx);
             let v = slice_remove(self.node.vals_mut(), self.idx);
index 042c523f25f25badec26e7737654afeb65de94ee..0f3b95236f069a5432daaf029dcec5d5a61af1f8 100644 (file)
@@ -23,9 +23,43 @@ fn creation() {
 #[test]
 fn secs() {
     assert_eq!(Duration::new(0, 0).as_secs(), 0);
+    assert_eq!(Duration::new(0, 500_000_005).as_secs(), 0);
+    assert_eq!(Duration::new(0, 1_050_000_001).as_secs(), 1);
     assert_eq!(Duration::from_secs(1).as_secs(), 1);
     assert_eq!(Duration::from_millis(999).as_secs(), 0);
     assert_eq!(Duration::from_millis(1001).as_secs(), 1);
+    assert_eq!(Duration::from_micros(999_999).as_secs(), 0);
+    assert_eq!(Duration::from_micros(1_000_001).as_secs(), 1);
+    assert_eq!(Duration::from_nanos(999_999_999).as_secs(), 0);
+    assert_eq!(Duration::from_nanos(1_000_000_001).as_secs(), 1);
+}
+
+#[test]
+fn millis() {
+    assert_eq!(Duration::new(0, 0).subsec_millis(), 0);
+    assert_eq!(Duration::new(0, 500_000_005).subsec_millis(), 500);
+    assert_eq!(Duration::new(0, 1_050_000_001).subsec_millis(), 50);
+    assert_eq!(Duration::from_secs(1).subsec_millis(), 0);
+    assert_eq!(Duration::from_millis(999).subsec_millis(), 999);
+    assert_eq!(Duration::from_millis(1001).subsec_millis(), 1);
+    assert_eq!(Duration::from_micros(999_999).subsec_millis(), 999);
+    assert_eq!(Duration::from_micros(1_001_000).subsec_millis(), 1);
+    assert_eq!(Duration::from_nanos(999_999_999).subsec_millis(), 999);
+    assert_eq!(Duration::from_nanos(1_001_000_000).subsec_millis(), 1);
+}
+
+#[test]
+fn micros() {
+    assert_eq!(Duration::new(0, 0).subsec_micros(), 0);
+    assert_eq!(Duration::new(0, 500_000_005).subsec_micros(), 500_000);
+    assert_eq!(Duration::new(0, 1_050_000_001).subsec_micros(), 50_000);
+    assert_eq!(Duration::from_secs(1).subsec_micros(), 0);
+    assert_eq!(Duration::from_millis(999).subsec_micros(), 999_000);
+    assert_eq!(Duration::from_millis(1001).subsec_micros(), 1_000);
+    assert_eq!(Duration::from_micros(999_999).subsec_micros(), 999_999);
+    assert_eq!(Duration::from_micros(1_000_001).subsec_micros(), 1);
+    assert_eq!(Duration::from_nanos(999_999_999).subsec_micros(), 999_999);
+    assert_eq!(Duration::from_nanos(1_000_001_000).subsec_micros(), 1);
 }
 
 #[test]
@@ -34,8 +68,12 @@ fn nanos() {
     assert_eq!(Duration::new(0, 5).subsec_nanos(), 5);
     assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1);
     assert_eq!(Duration::from_secs(1).subsec_nanos(), 0);
-    assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000);
-    assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000);
+    assert_eq!(Duration::from_millis(999).subsec_nanos(), 999_000_000);
+    assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1_000_000);
+    assert_eq!(Duration::from_micros(999_999).subsec_nanos(), 999_999_000);
+    assert_eq!(Duration::from_micros(1_000_001).subsec_nanos(), 1000);
+    assert_eq!(Duration::from_nanos(999_999_999).subsec_nanos(), 999_999_999);
+    assert_eq!(Duration::from_nanos(1_000_000_001).subsec_nanos(), 1);
 }
 
 #[test]
index 8e8b1691c657a3bc0edaa12e336332e82f55a3db..c0b2b2a0bc682abf3fbe56df4108fef764b1fcdd 100644 (file)
@@ -203,8 +203,9 @@ pub const fn from_nanos(nanos: u64) -> Duration {
     ///
     /// [`subsec_nanos`]: #method.subsec_nanos
     #[stable(feature = "duration", since = "1.3.0")]
+    #[rustc_const_unstable(feature="duration_getters")]
     #[inline]
-    pub fn as_secs(&self) -> u64 { self.secs }
+    pub const fn as_secs(&self) -> u64 { self.secs }
 
     /// Returns the fractional part of this `Duration`, in milliseconds.
     ///
@@ -222,8 +223,9 @@ pub fn as_secs(&self) -> u64 { self.secs }
     /// assert_eq!(duration.subsec_millis(), 432);
     /// ```
     #[stable(feature = "duration_extras", since = "1.27.0")]
+    #[rustc_const_unstable(feature="duration_getters")]
     #[inline]
-    pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
+    pub const fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
 
     /// Returns the fractional part of this `Duration`, in microseconds.
     ///
@@ -241,8 +243,9 @@ pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
     /// assert_eq!(duration.subsec_micros(), 234_567);
     /// ```
     #[stable(feature = "duration_extras", since = "1.27.0")]
+    #[rustc_const_unstable(feature="duration_getters")]
     #[inline]
-    pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
+    pub const fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
 
     /// Returns the fractional part of this `Duration`, in nanoseconds.
     ///
@@ -260,8 +263,9 @@ pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
     /// assert_eq!(duration.subsec_nanos(), 10_000_000);
     /// ```
     #[stable(feature = "duration", since = "1.3.0")]
+    #[rustc_const_unstable(feature="duration_getters")]
     #[inline]
-    pub fn subsec_nanos(&self) -> u32 { self.nanos }
+    pub const fn subsec_nanos(&self) -> u32 { self.nanos }
 
     /// Checked `Duration` addition. Computes `self + other`, returning [`None`]
     /// if overflow occurred.
index e4f432e7caf494d789bd520299e6774db9cb22bd..4847a7f4ddbec4e6b5f98f9c0e58f6bf44704523 100644 (file)
@@ -60,7 +60,7 @@
 //! user of the `DepNode` API of having to know how to compute the expected
 //! fingerprint for a given set of node parameters.
 
-use mir::interpret::{GlobalId};
+use mir::interpret::{GlobalId, ConstValue};
 use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
 use hir::map::DefPathHash;
 use hir::{HirId, ItemLocalId};
@@ -621,13 +621,14 @@ pub fn fingerprint_needed_for_crate_hash(self) -> bool {
     [input] UsedCrateSource(CrateNum),
     [input] PostorderCnums,
 
-    // This query is not expected to have inputs -- as a result, it's
-    // not a good candidate for "replay" because it's essentially a
-    // pure function of its input (and hence the expectation is that
-    // no caller would be green **apart** from just this
-    // query). Making it anonymous avoids hashing the result, which
+    // These queries are not expected to have inputs -- as a result, they
+    // are not good candidates for "replay" because they are essentially
+    // pure functions of their input (and hence the expectation is that
+    // no caller would be green **apart** from just these
+    // queries). Making them anonymous avoids hashing the result, which
     // may save a bit of time.
     [anon] EraseRegionsTy { ty: Ty<'tcx> },
+    [anon] ConstValueToAllocation { val: ConstValue<'tcx>, ty: Ty<'tcx> },
 
     [input] Freevars(DefId),
     [input] MaybeUnusedTraitImport(DefId),
index 03aff6410055815a27c1d63bd1b43a8e92b6fe2e..797332e699d4b99705cdaf4b9ce446b3cf728f0d 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use rustc_data_structures::small_vec::SmallVec;
-use rustc_data_structures::sync::{Lrc, RwLock, ReadGuard, Lock};
+use rustc_data_structures::sync::{Lrc, Lock};
 use std::env;
 use std::hash::Hash;
 use ty::{self, TyCtxt};
@@ -80,9 +80,6 @@ struct DepGraphData {
     /// this map. We can later look for and extract that data.
     previous_work_products: FxHashMap<WorkProductId, WorkProduct>,
 
-    /// Work-products that we generate in this run.
-    work_products: RwLock<FxHashMap<WorkProductId, WorkProduct>>,
-
     dep_node_debug: Lock<FxHashMap<DepNode, String>>,
 
     // Used for testing, only populated when -Zquery-dep-graph is specified.
@@ -103,7 +100,6 @@ pub fn new(prev_graph: PreviousDepGraph,
         DepGraph {
             data: Some(Lrc::new(DepGraphData {
                 previous_work_products: prev_work_products,
-                work_products: RwLock::new(FxHashMap()),
                 dep_node_debug: Lock::new(FxHashMap()),
                 current: Lock::new(CurrentDepGraph::new()),
                 previous: prev_graph,
@@ -462,19 +458,6 @@ pub fn prev_dep_node_index_of(&self, dep_node: &DepNode) -> SerializedDepNodeInd
         self.data.as_ref().unwrap().previous.node_to_index(dep_node)
     }
 
-    /// Indicates that we created the given work-product in this run
-    /// for `v`. This record will be preserved and loaded in the next
-    /// run.
-    pub fn insert_work_product(&self, v: &WorkProductId, data: WorkProduct) {
-        debug!("insert_work_product({:?}, {:?})", v, data);
-        self.data
-            .as_ref()
-            .unwrap()
-            .work_products
-            .borrow_mut()
-            .insert(v.clone(), data);
-    }
-
     /// Check whether a previous work product exists for `v` and, if
     /// so, return the path that leads to it. Used to skip doing work.
     pub fn previous_work_product(&self, v: &WorkProductId) -> Option<WorkProduct> {
@@ -485,12 +468,6 @@ pub fn previous_work_product(&self, v: &WorkProductId) -> Option<WorkProduct> {
             })
     }
 
-    /// Access the map of work-products created during this run. Only
-    /// used during saving of the dep-graph.
-    pub fn work_products(&self) -> ReadGuard<FxHashMap<WorkProductId, WorkProduct>> {
-        self.data.as_ref().unwrap().work_products.borrow()
-    }
-
     /// Access the map of work-products created during the cached run. Only
     /// used during saving of the dep-graph.
     pub fn previous_work_products(&self) -> &FxHashMap<WorkProductId, WorkProduct> {
index 2221ecf07b434913b079643d283b48afeeed7d5f..a62000e10c79f8374116269b5eeb45c534307cea 100644 (file)
@@ -88,3 +88,33 @@ fn visit_impl_item(&mut self, impl_item: &'hir ImplItem) {
         self.visitor.visit_impl_item(impl_item);
     }
 }
+
+/// A parallel variant of ItemLikeVisitor
+pub trait ParItemLikeVisitor<'hir> {
+    fn visit_item(&self, item: &'hir Item);
+    fn visit_trait_item(&self, trait_item: &'hir TraitItem);
+    fn visit_impl_item(&self, impl_item: &'hir ImplItem);
+}
+
+pub trait IntoVisitor<'hir> {
+    type Visitor: Visitor<'hir>;
+    fn into_visitor(&self) -> Self::Visitor;
+}
+
+pub struct ParDeepVisitor<V>(pub V);
+
+impl<'hir, V> ParItemLikeVisitor<'hir> for ParDeepVisitor<V>
+    where V: IntoVisitor<'hir>
+{
+    fn visit_item(&self, item: &'hir Item) {
+        self.0.into_visitor().visit_item(item);
+    }
+
+    fn visit_trait_item(&self, trait_item: &'hir TraitItem) {
+        self.0.into_visitor().visit_trait_item(trait_item);
+    }
+
+    fn visit_impl_item(&self, impl_item: &'hir ImplItem) {
+        self.0.into_visitor().visit_impl_item(impl_item);
+    }
+}
index 0dc89d64bd50116b02d71039e34e6e32c05eb4d3..33076267dbc9d427009475ef677d8c99b3966b36 100644 (file)
@@ -48,6 +48,7 @@
 use ty::maps::Providers;
 
 use rustc_data_structures::indexed_vec;
+use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync, scope};
 
 use serialize::{self, Encoder, Encodable, Decoder, Decodable};
 use std::collections::BTreeMap;
@@ -720,6 +721,31 @@ pub fn visit_all_item_likes<'hir, V>(&'hir self, visitor: &mut V)
         }
     }
 
+    /// A parallel version of visit_all_item_likes
+    pub fn par_visit_all_item_likes<'hir, V>(&'hir self, visitor: &V)
+        where V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send
+    {
+        scope(|s| {
+            s.spawn(|_| {
+                par_iter(&self.items).for_each(|(_, item)| {
+                    visitor.visit_item(item);
+                });
+            });
+
+            s.spawn(|_| {
+                par_iter(&self.trait_items).for_each(|(_, trait_item)| {
+                    visitor.visit_trait_item(trait_item);
+                });
+            });
+
+            s.spawn(|_| {
+                par_iter(&self.impl_items).for_each(|(_, impl_item)| {
+                    visitor.visit_impl_item(impl_item);
+                });
+            });
+        });
+    }
+
     pub fn body(&self, id: BodyId) -> &Body {
         &self.bodies[&id]
     }
index a7adf28c481b95c3fa352aa6345254df6f6a15be..f56f4e12e7a02b9b16ffa34c2f9119ad0c492235 100644 (file)
@@ -67,7 +67,7 @@ pub fn decode_opaque<'a>(decoder: &mut Decoder<'a>) -> Result<Fingerprint, Strin
 }
 
 impl ::std::fmt::Display for Fingerprint {
-    fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
+    fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         write!(formatter, "{:x}-{:x}", self.0, self.1)
     }
 }
index d0d0ab093c87ffbd976c77489d6beebc9a7f89da..1036eae9b856b0092ec949d94aa3655a33dcfb17 100644 (file)
@@ -384,6 +384,30 @@ fn hash_stable<W: StableHasherResult>(&self,
     }
 }
 
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
+for ::mir::interpret::ConstValue<'gcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
+        use mir::interpret::ConstValue::*;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            ByVal(val) => {
+                val.hash_stable(hcx, hasher);
+            }
+            ByValPair(a, b) => {
+                a.hash_stable(hcx, hasher);
+                b.hash_stable(hcx, hasher);
+            }
+            ByRef(alloc) => {
+                alloc.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
 impl_stable_hash_for!(enum mir::interpret::Value {
     ByVal(v),
     ByValPair(a, b),
index 398d7d5704c7fb4be1f0ca15388f30546efe65d1..4f015ed1ce161c5163c7b1fe8b61306e91f606f9 100644 (file)
 declare_lint! {
     pub SINGLE_USE_LIFETIME,
     Allow,
-   "detects single use lifetimes"
+    "detects lifetime parameters that are only used once"
+}
+
+declare_lint! {
+    pub UNUSED_LIFETIME,
+    Allow,
+    "detects lifetime parameters that are never used"
 }
 
 declare_lint! {
@@ -318,6 +324,7 @@ fn get_lints(&self) -> LintArray {
             UNUSED_UNSAFE,
             UNUSED_MUT,
             SINGLE_USE_LIFETIME,
+            UNUSED_LIFETIME,
             TYVAR_BEHIND_RAW_POINTER,
             ELIDED_LIFETIME_IN_PATH,
             BARE_TRAIT_OBJECT,
index 0ecab50dda22989faeb57d53f0bc642ff068e37d..3a76f75d01833a8dbb9ad6cf0653d2e8fd0c7b10 100644 (file)
@@ -11,7 +11,7 @@
 use hir::def_id::DefId;
 use ty::{self, TyCtxt, layout};
 use ty::subst::Substs;
-use mir::interpret::{Value, PrimVal};
+use mir::interpret::ConstValue;
 use errors::DiagnosticBuilder;
 
 use graphviz::IntoCow;
 #[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
 pub enum ConstVal<'tcx> {
     Unevaluated(DefId, &'tcx Substs<'tcx>),
-    Value(Value),
-}
-
-impl<'tcx> ConstVal<'tcx> {
-    pub fn to_raw_bits(&self) -> Option<u128> {
-        match *self {
-            ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
-                Some(b)
-            },
-            _ => None,
-        }
-    }
-    pub fn unwrap_u64(&self) -> u64 {
-        match self.to_raw_bits() {
-            Some(val) => {
-                assert_eq!(val as u64 as u128, val);
-                val as u64
-            },
-            None => bug!("expected constant u64, got {:#?}", self),
-        }
-    }
+    Value(ConstValue<'tcx>),
 }
 
 #[derive(Clone, Debug)]
index 4400ebc294fd89f4afd114926bb98e17198c6dbf..61c8470b616f833f2284fede138d1002232b44c2 100644 (file)
@@ -38,7 +38,7 @@
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
 use rustc_target::spec::Target;
-use rustc_data_structures::sync::{MetadataRef, Lrc};
+use rustc_data_structures::sync::{self, MetadataRef, Lrc};
 
 pub use self::NativeLibraryKind::*;
 
@@ -255,6 +255,8 @@ fn encode_metadata<'a, 'tcx>(&self,
     fn metadata_encoding_version(&self) -> &[u8];
 }
 
+pub type CrateStoreDyn = CrateStore + sync::Sync;
+
 // FIXME: find a better place for this?
 pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
     let mut err_count = 0;
index 3875770a5ff5c50298de2c1154e0d2be4d243241..a4c38333da19e8343550ba11ee954756ecb9333a 100644 (file)
@@ -945,7 +945,7 @@ pub fn cat_rvalue_node(&self,
 
         // Always promote `[T; 0]` (even when e.g. borrowed mutably).
         let promotable = match expr_ty.sty {
-            ty::TyArray(_, len) if len.val.to_raw_bits() == Some(0) => true,
+            ty::TyArray(_, len) if len.assert_usize(self.tcx) == Some(0) => true,
             _ => promotable,
         };
 
index ceda72dcd7ae0ab51976be10386baf0c636bd5fb..8c19a19523275d226692e95be3fa0d1349ed5323 100644 (file)
 //! used between functions, and they operate in a purely top-down
 //! way. Therefore we break lifetime name resolution into a separate pass.
 
-use hir::map::Map;
 use hir::def::Def;
 use hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use hir::map::Map;
 use hir::ItemLocalId;
 use hir::LifetimeName;
 use ty::{self, TyCtxt};
 
+use errors::DiagnosticBuilder;
+use rustc::lint;
+use rustc_data_structures::sync::Lrc;
+use session::Session;
 use std::cell::Cell;
 use std::mem::replace;
-use rustc_data_structures::sync::Lrc;
+use std::slice;
 use syntax::ast;
 use syntax::attr;
 use syntax::ptr::P;
 use syntax_pos::Span;
-use errors::DiagnosticBuilder;
 use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
-use session::Session;
-use std::slice;
-use rustc::lint;
 
-use hir::{self, GenericParamsExt};
 use hir::intravisit::{self, NestedVisitorMap, Visitor};
+use hir::{self, GenericParamsExt};
 
 /// The origin of a named lifetime definition.
 ///
@@ -230,33 +230,34 @@ struct LifetimeContext<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     map: &'a mut NamedRegionMap,
     scope: ScopeRef<'a>,
-    // Deep breath. Our representation for poly trait refs contains a single
-    // binder and thus we only allow a single level of quantification. However,
-    // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
-    // and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
-    // correct when representing these constraints, we should only introduce one
-    // scope. However, we want to support both locations for the quantifier and
-    // during lifetime resolution we want precise information (so we can't
-    // desugar in an earlier phase).
-
-    // SO, if we encounter a quantifier at the outer scope, we set
-    // trait_ref_hack to true (and introduce a scope), and then if we encounter
-    // a quantifier at the inner scope, we error. If trait_ref_hack is false,
-    // then we introduce the scope at the inner quantifier.
-
-    // I'm sorry.
+
+    /// Deep breath. Our representation for poly trait refs contains a single
+    /// binder and thus we only allow a single level of quantification. However,
+    /// the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
+    /// and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
+    /// correct when representing these constraints, we should only introduce one
+    /// scope. However, we want to support both locations for the quantifier and
+    /// during lifetime resolution we want precise information (so we can't
+    /// desugar in an earlier phase).
+    ///
+    /// SO, if we encounter a quantifier at the outer scope, we set
+    /// trait_ref_hack to true (and introduce a scope), and then if we encounter
+    /// a quantifier at the inner scope, we error. If trait_ref_hack is false,
+    /// then we introduce the scope at the inner quantifier.
+    ///
+    /// I'm sorry.
     trait_ref_hack: bool,
 
-    // Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
+    /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
     is_in_fn_syntax: bool,
 
-    // List of labels in the function/method currently under analysis.
+    /// List of labels in the function/method currently under analysis.
     labels_in_fn: Vec<(ast::Name, Span)>,
 
-    // Cache for cross-crate per-definition object lifetime defaults.
+    /// Cache for cross-crate per-definition object lifetime defaults.
     xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
 
-    lifetime_uses: DefIdMap<LifetimeUseSet<'tcx>>,
+    lifetime_uses: &'a mut DefIdMap<LifetimeUseSet<'tcx>>,
 }
 
 #[derive(Debug)]
@@ -272,6 +273,11 @@ enum Scope<'a> {
         /// we should use for an early-bound region?
         next_early_index: u32,
 
+        /// Flag is set to true if, in this binder, `'_` would be
+        /// equivalent to a "single-use region". This is true on
+        /// impls, but not other kinds of items.
+        track_lifetime_uses: bool,
+
         /// Whether or not this binder would serve as the parent
         /// binder for abstract types introduced within. For example:
         ///
@@ -432,7 +438,7 @@ fn krate<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> NamedRegionMap {
             is_in_fn_syntax: false,
             labels_in_fn: vec![],
             xcrate_object_lifetime_defaults: DefIdMap(),
-            lifetime_uses: DefIdMap(),
+            lifetime_uses: &mut DefIdMap(),
         };
         for (_, item) in &krate.items {
             visitor.visit_item(item);
@@ -497,6 +503,12 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
             | hir::ItemTrait(_, _, ref generics, ..)
             | hir::ItemTraitAlias(ref generics, ..)
             | hir::ItemImpl(_, _, _, ref generics, ..) => {
+                // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name".
+                // This is not true for other kinds of items.x
+                let track_lifetime_uses = match item.node {
+                    hir::ItemImpl(..) => true,
+                    _ => false,
+                };
                 // These kinds of items have only early bound lifetime parameters.
                 let mut index = if let hir::ItemTrait(..) = item.node {
                     1 // Self comes before lifetimes
@@ -512,6 +524,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
                     lifetimes,
                     next_early_index,
                     abstract_type_parent: true,
+                    track_lifetime_uses,
                     s: ROOT_SCOPE,
                 };
                 self.with(scope, |old_scope, this| {
@@ -539,7 +552,7 @@ fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        debug!("visit_ty: ty={:?}", ty);
+        debug!("visit_ty: id={:?} ty={:?}", ty.id, ty);
         match ty.node {
             hir::TyBareFn(ref c) => {
                 let next_early_index = self.next_early_index();
@@ -552,6 +565,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
                         .collect(),
                     s: self.scope,
                     next_early_index,
+                    track_lifetime_uses: true,
                     abstract_type_parent: false,
                 };
                 self.with(scope, |old_scope, this| {
@@ -673,6 +687,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
                             lifetimes,
                             next_early_index,
                             s: this.scope,
+                            track_lifetime_uses: true,
                             abstract_type_parent: false,
                         };
                         this.with(scope, |_old_scope, this| {
@@ -687,6 +702,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
                         lifetimes,
                         next_early_index,
                         s: self.scope,
+                        track_lifetime_uses: true,
                         abstract_type_parent: false,
                     };
                     self.with(scope, |_old_scope, this| {
@@ -727,6 +743,7 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
                     lifetimes,
                     next_early_index,
                     s: self.scope,
+                    track_lifetime_uses: true,
                     abstract_type_parent: true,
                 };
                 self.with(scope, |_old_scope, this| {
@@ -773,6 +790,7 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
                     lifetimes,
                     next_early_index,
                     s: self.scope,
+                    track_lifetime_uses: true,
                     abstract_type_parent: true,
                 };
                 self.with(scope, |_old_scope, this| {
@@ -846,6 +864,7 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
                                 .collect(),
                             s: self.scope,
                             next_early_index,
+                            track_lifetime_uses: true,
                             abstract_type_parent: false,
                         };
                         let result = self.with(scope, |old_scope, this| {
@@ -912,6 +931,7 @@ fn visit_poly_trait_ref(
                     .collect(),
                 s: self.scope,
                 next_early_index,
+                track_lifetime_uses: true,
                 abstract_type_parent: false,
             };
             self.with(scope, |old_scope, this| {
@@ -1103,10 +1123,7 @@ fn check_if_label_shadows_lifetime(
                 }
 
                 Scope::Binder {
-                    ref lifetimes,
-                    s,
-                    next_early_index: _,
-                    abstract_type_parent: _,
+                    ref lifetimes, s, ..
                 } => {
                     // FIXME (#24278): non-hygienic comparison
                     if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) {
@@ -1254,33 +1271,70 @@ fn with<F>(&mut self, wrap_scope: Scope, f: F)
         F: for<'b> FnOnce(ScopeRef, &mut LifetimeContext<'b, 'tcx>),
     {
         let LifetimeContext {
-            tcx, ref mut map, ..
-        } = *self;
+            tcx,
+            map,
+            lifetime_uses,
+            ..
+        } = self;
         let labels_in_fn = replace(&mut self.labels_in_fn, vec![]);
         let xcrate_object_lifetime_defaults =
             replace(&mut self.xcrate_object_lifetime_defaults, DefIdMap());
         let mut this = LifetimeContext {
-            tcx,
-            map: *map,
+            tcx: *tcx,
+            map: map,
             scope: &wrap_scope,
             trait_ref_hack: self.trait_ref_hack,
             is_in_fn_syntax: self.is_in_fn_syntax,
             labels_in_fn,
             xcrate_object_lifetime_defaults,
-            lifetime_uses: DefIdMap(),
+            lifetime_uses: lifetime_uses,
         };
         debug!("entering scope {:?}", this.scope);
         f(self.scope, &mut this);
+        this.check_uses_for_lifetimes_defined_by_scope();
         debug!("exiting scope {:?}", this.scope);
         self.labels_in_fn = this.labels_in_fn;
         self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
+    }
+
+    fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
+        let defined_by = match self.scope {
+            Scope::Binder { lifetimes, .. } => lifetimes,
+            _ => {
+                debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope");
+                return;
+            }
+        };
 
-        for (def_id, lifetimeuseset) in &this.lifetime_uses {
+        let mut def_ids: Vec<_> = defined_by.values()
+            .flat_map(|region| match region {
+                Region::EarlyBound(_, def_id, _)
+                | Region::LateBound(_, def_id, _)
+                | Region::Free(_, def_id) => Some(*def_id),
+
+                Region::LateBoundAnon(..) | Region::Static => None,
+            })
+            .collect();
+
+        // ensure that we issue lints in a repeatable order
+        def_ids.sort_by_key(|&def_id| self.tcx.def_path_hash(def_id));
+
+        for def_id in def_ids {
+            debug!(
+                "check_uses_for_lifetimes_defined_by_scope: def_id = {:?}",
+                def_id,
+            );
+
+            let lifetimeuseset = self.lifetime_uses.remove(&def_id);
+            debug!(
+                "check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}",
+                lifetimeuseset
+            );
             match lifetimeuseset {
-                &LifetimeUseSet::One(_) => {
-                    let node_id = this.tcx.hir.as_local_node_id(*def_id).unwrap();
+                Some(LifetimeUseSet::One(_)) => {
+                    let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
                     debug!("node id first={:?}", node_id);
-                    if let hir::map::NodeLifetime(hir_lifetime) = this.tcx.hir.get(node_id) {
+                    if let hir::map::NodeLifetime(hir_lifetime) = self.tcx.hir.get(node_id) {
                         let span = hir_lifetime.span;
                         let id = hir_lifetime.id;
                         debug!(
@@ -1288,22 +1342,41 @@ fn with<F>(&mut self, wrap_scope: Scope, f: F)
                             node_id, span, hir_lifetime
                         );
 
-                        this.tcx
+                        self.tcx
                             .struct_span_lint_node(
                                 lint::builtin::SINGLE_USE_LIFETIME,
                                 id,
                                 span,
                                 &format!(
-                                    "lifetime name `{}` only used once",
+                                    "lifetime parameter `{}` only used once",
                                     hir_lifetime.name.name()
                                 ),
                             )
                             .emit();
                     }
                 }
-                _ => {
+                Some(LifetimeUseSet::Many) => {
                     debug!("Not one use lifetime");
                 }
+                None => {
+                    let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
+                    if let hir::map::NodeLifetime(hir_lifetime) = self.tcx.hir.get(node_id) {
+                        let span = hir_lifetime.span;
+                        let id = hir_lifetime.id;
+
+                        self.tcx
+                            .struct_span_lint_node(
+                                lint::builtin::UNUSED_LIFETIME,
+                                id,
+                                span,
+                                &format!(
+                                    "lifetime parameter `{}` never used",
+                                    hir_lifetime.name.name()
+                                ),
+                            )
+                            .emit();
+                    }
+                }
             }
         }
     }
@@ -1371,6 +1444,7 @@ fn visit_early_late<F>(
             next_early_index,
             s: self.scope,
             abstract_type_parent: true,
+            track_lifetime_uses: false,
         };
         self.with(scope, move |old_scope, this| {
             this.check_lifetime_params(old_scope, &generics.params);
@@ -1436,10 +1510,7 @@ fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
                 }
 
                 Scope::Binder {
-                    ref lifetimes,
-                    s,
-                    next_early_index: _,
-                    abstract_type_parent: _,
+                    ref lifetimes, s, ..
                 } => {
                     if let Some(&def) = lifetimes.get(&lifetime_ref.name) {
                         break Some(def.shifted(late_depth));
@@ -1630,6 +1701,7 @@ fn visit_fn_like_elision(
         inputs: &'tcx [P<hir::Ty>],
         output: Option<&'tcx P<hir::Ty>>,
     ) {
+        debug!("visit_fn_like_elision: enter");
         let mut arg_elide = Elide::FreshLateAnon(Cell::new(0));
         let arg_scope = Scope::Elision {
             elide: arg_elide.clone(),
@@ -1652,6 +1724,8 @@ fn visit_fn_like_elision(
             None => return,
         };
 
+        debug!("visit_fn_like_elision: determine output");
+
         // Figure out if there's a body we can get argument names from,
         // and whether there's a `self` argument (treated specially).
         let mut assoc_item_kind = None;
@@ -1811,11 +1885,14 @@ fn visit_fn_like_elision(
             Elide::Error(arg_lifetimes)
         };
 
+        debug!("visit_fn_like_elision: elide={:?}", elide);
+
         let scope = Scope::Elision {
             elide,
             s: self.scope,
         };
         self.with(scope, |_, this| this.visit_ty(output));
+        debug!("visit_fn_like_elision: exit");
 
         struct GatherLifetimes<'a> {
             map: &'a NamedRegionMap,
@@ -2086,8 +2163,9 @@ fn check_lifetime_params(&mut self, old_scope: ScopeRef, params: &'tcx [hir::Gen
                         );
                         err.emit();
                     }
-                    hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit |
-                    hir::LifetimeName::Name(_) => {}
+                    hir::LifetimeName::Fresh(_)
+                    | hir::LifetimeName::Implicit
+                    | hir::LifetimeName::Name(_) => {}
                 }
             }
 
@@ -2139,8 +2217,9 @@ fn check_lifetime_params(&mut self, old_scope: ScopeRef, params: &'tcx [hir::Gen
                             ))
                             .emit();
                     }
-                    hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit |
-                    hir::LifetimeName::Name(_) => {
+                    hir::LifetimeName::Fresh(_)
+                    | hir::LifetimeName::Implicit
+                    | hir::LifetimeName::Name(_) => {
                         self.resolve_lifetime_ref(bound);
                     }
                 }
@@ -2179,10 +2258,7 @@ fn check_lifetime_def_for_shadowing(
                 }
 
                 Scope::Binder {
-                    ref lifetimes,
-                    s,
-                    next_early_index: _,
-                    abstract_type_parent: _,
+                    ref lifetimes, s, ..
                 } => {
                     if let Some(&def) = lifetimes.get(&lifetime.name) {
                         let node_id = self.tcx.hir.as_local_node_id(def.id().unwrap()).unwrap();
@@ -2202,6 +2278,50 @@ fn check_lifetime_def_for_shadowing(
         }
     }
 
+    /// Returns true if, in the current scope, replacing `'_` would be
+    /// equivalent to a single-use lifetime.
+    fn track_lifetime_uses(&self) -> bool {
+        let mut scope = self.scope;
+        loop {
+            match *scope {
+                Scope::Root => break false,
+
+                // Inside of items, it depends on the kind of item.
+                Scope::Binder {
+                    track_lifetime_uses,
+                    ..
+                } => break track_lifetime_uses,
+
+                // Inside a body, `'_` will use an inference variable,
+                // should be fine.
+                Scope::Body { .. } => break true,
+
+                // A lifetime only used in a fn argument could as well
+                // be replaced with `'_`, as that would generate a
+                // fresh name, too.
+                Scope::Elision {
+                    elide: Elide::FreshLateAnon(_),
+                    ..
+                } => break true,
+
+                // In the return type or other such place, `'_` is not
+                // going to make a fresh name, so we cannot
+                // necessarily replace a single-use lifetime with
+                // `'_`.
+                Scope::Elision {
+                    elide: Elide::Exact(_),
+                    ..
+                } => break false,
+                Scope::Elision {
+                    elide: Elide::Error(_),
+                    ..
+                } => break false,
+
+                Scope::ObjectLifetimeDefault { s, .. } => scope = s,
+            }
+        }
+    }
+
     fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
         if lifetime_ref.id == ast::DUMMY_NODE_ID {
             span_bug!(
@@ -2228,11 +2348,31 @@ fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
             | Region::LateBound(_, def_id, _)
             | Region::EarlyBound(_, def_id, _) => {
                 // A lifetime declared by the user.
-                if !self.lifetime_uses.contains_key(&def_id) {
-                    self.lifetime_uses
-                        .insert(def_id, LifetimeUseSet::One(lifetime_ref));
+                let def_local_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
+                if def_local_id == lifetime_ref.id {
+                    // This is weird. Because the HIR defines a
+                    // lifetime *definition* as wrapping a Lifetime,
+                    // we wind up invoking this method also for the
+                    // definitions in some cases (notably
+                    // higher-ranked types). This means that a
+                    // lifetime with one use (e.g., `for<'a> fn(&'a
+                    // u32)`) wind up being counted as two uses.  To
+                    // avoid that, we just ignore the lifetime that
+                    // corresponds to the definition.
                 } else {
-                    self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
+                    let track_lifetime_uses = self.track_lifetime_uses();
+                    debug!(
+                        "insert_lifetime: track_lifetime_uses={}",
+                        track_lifetime_uses
+                    );
+                    if track_lifetime_uses && !self.lifetime_uses.contains_key(&def_id) {
+                        debug!("insert_lifetime: first use of {:?}", def_id);
+                        self.lifetime_uses
+                            .insert(def_id, LifetimeUseSet::One(lifetime_ref));
+                    } else {
+                        debug!("insert_lifetime: many uses of {:?}", def_id);
+                        self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
+                    }
                 }
             }
         }
index 279908d2b675fae372bbb13780bf293d39fc7220..d6a7d5e8472ac086dab3b6dec23b6cc37664f8cd 100644 (file)
@@ -764,7 +764,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
                                      "unions with `Drop` implementations are unstable");
                 } else {
                     let param_env = self.tcx.param_env(def_id);
-                    if !param_env.can_type_implement_copy(self.tcx, ty, item.span).is_ok() {
+                    if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() {
                         emit_feature_err(&self.tcx.sess.parse_sess,
                                         "untagged_unions", item.span, GateIssue::Language,
                                         "unions with non-`Copy` fields are unstable");
index 546c7a920d538fd6d12a653ea0c41ccf9f510088..afdd1c167c6dc781b488a0c06d55be60e757952b 100644 (file)
@@ -10,7 +10,7 @@ macro_rules! err {
 
 pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage};
 
-pub use self::value::{PrimVal, PrimValKind, Value, Pointer};
+pub use self::value::{PrimVal, PrimValKind, Value, Pointer, ConstValue};
 
 use std::collections::BTreeMap;
 use std::fmt;
@@ -20,8 +20,10 @@ macro_rules! err {
 use ty::layout::{self, Align, HasDataLayout};
 use middle::region;
 use std::iter;
+use std::io;
 use syntax::ast::Mutability;
 use rustc_serialize::{Encoder, Decoder, Decodable, Encodable};
+use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian};
 
 #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum Lock {
@@ -235,7 +237,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-#[derive(Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
 pub struct Allocation {
     /// The actual bytes of the allocation.
     /// Note that the bytes of a pointer represent the offset of the pointer
@@ -254,17 +256,69 @@ pub struct Allocation {
 }
 
 impl Allocation {
-    pub fn from_bytes(slice: &[u8]) -> Self {
+    pub fn from_bytes(slice: &[u8], align: Align) -> Self {
         let mut undef_mask = UndefMask::new(0);
         undef_mask.grow(slice.len() as u64, true);
         Self {
             bytes: slice.to_owned(),
             relocations: BTreeMap::new(),
             undef_mask,
-            align: Align::from_bytes(1, 1).unwrap(),
+            align,
             runtime_mutability: Mutability::Immutable,
         }
     }
+
+    pub fn from_byte_aligned_bytes(slice: &[u8]) -> Self {
+        Allocation::from_bytes(slice, Align::from_bytes(1, 1).unwrap())
+    }
+
+    pub fn undef(size: u64, align: Align) -> Self {
+        assert_eq!(size as usize as u64, size);
+        Allocation {
+            bytes: vec![0; size as usize],
+            relocations: BTreeMap::new(),
+            undef_mask: UndefMask::new(size),
+            align,
+            runtime_mutability: Mutability::Immutable,
+        }
+    }
+}
+
+impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {}
+
+////////////////////////////////////////////////////////////////////////////////
+// Methods to access integers in the target endianness
+////////////////////////////////////////////////////////////////////////////////
+
+pub fn write_target_uint(
+    endianness: layout::Endian,
+    mut target: &mut [u8],
+    data: u128,
+) -> Result<(), io::Error> {
+    let len = target.len();
+    match endianness {
+        layout::Endian::Little => target.write_uint128::<LittleEndian>(data, len),
+        layout::Endian::Big => target.write_uint128::<BigEndian>(data, len),
+    }
+}
+
+pub fn write_target_int(
+    endianness: layout::Endian,
+    mut target: &mut [u8],
+    data: i128,
+) -> Result<(), io::Error> {
+    let len = target.len();
+    match endianness {
+        layout::Endian::Little => target.write_int128::<LittleEndian>(data, len),
+        layout::Endian::Big => target.write_int128::<BigEndian>(data, len),
+    }
+}
+
+pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
+    match endianness {
+        layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
+        layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()),
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
index 7289d74bfbb1bd653fa529cd7951ff7da8a11bb6..2cd4bf9d18ca55ef3b3aad375bf292561f818f86 100644 (file)
@@ -3,7 +3,69 @@
 use ty::layout::{Align, HasDataLayout};
 use ty;
 
-use super::{EvalResult, MemoryPointer, PointerArithmetic};
+use super::{EvalResult, MemoryPointer, PointerArithmetic, Allocation};
+
+/// Represents a constant value in Rust. ByVal and ByValPair are optimizations which
+/// matches Value's optimizations for easy conversions between these two types
+#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
+pub enum ConstValue<'tcx> {
+    // Used only for types with layout::abi::Scalar ABI and ZSTs which use PrimVal::Undef
+    ByVal(PrimVal),
+    // Used only for types with layout::abi::ScalarPair
+    ByValPair(PrimVal, PrimVal),
+    // Used only for the remaining cases
+    ByRef(&'tcx Allocation),
+}
+
+impl<'tcx> ConstValue<'tcx> {
+    #[inline]
+    pub fn from_byval_value(val: Value) -> Self {
+        match val {
+            Value::ByRef(..) => bug!(),
+            Value::ByValPair(a, b) => ConstValue::ByValPair(a, b),
+            Value::ByVal(val) => ConstValue::ByVal(val),
+        }
+    }
+
+    #[inline]
+    pub fn to_byval_value(&self) -> Option<Value> {
+        match *self {
+            ConstValue::ByRef(..) => None,
+            ConstValue::ByValPair(a, b) => Some(Value::ByValPair(a, b)),
+            ConstValue::ByVal(val) => Some(Value::ByVal(val)),
+        }
+    }
+
+    #[inline]
+    pub fn from_primval(val: PrimVal) -> Self {
+        ConstValue::ByVal(val)
+    }
+
+    #[inline]
+    pub fn to_primval(&self) -> Option<PrimVal> {
+        match *self {
+            ConstValue::ByRef(..) => None,
+            ConstValue::ByValPair(..) => None,
+            ConstValue::ByVal(val) => Some(val),
+        }
+    }
+
+    #[inline]
+    pub fn to_bits(&self) -> Option<u128> {
+        match self.to_primval() {
+            Some(PrimVal::Bytes(val)) => Some(val),
+            _ => None,
+        }
+    }
+
+    #[inline]
+    pub fn to_ptr(&self) -> Option<MemoryPointer> {
+        match self.to_primval() {
+            Some(PrimVal::Ptr(ptr)) => Some(ptr),
+            _ => None,
+        }
+    }
+}
 
 /// A `Value` represents a single self-contained Rust value.
 ///
index 11e25322f00726b2e2226f7ae09bfed9f81cf96b..eb12444bcb4c92cc7279bd59a22efcdff47add05 100644 (file)
@@ -13,7 +13,6 @@
 //! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir.html
 
 use graphviz::IntoCow;
-use middle::const_val::ConstVal;
 use middle::region;
 use rustc_data_structures::sync::{Lrc};
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@@ -1549,11 +1548,7 @@ pub fn function_handle<'a>(
             span,
             ty,
             literal: Literal::Value {
-                value: tcx.mk_const(ty::Const {
-                    // ZST function type
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
-                    ty
-                })
+                value: ty::Const::zero_sized(tcx, ty),
             },
         })
     }
@@ -1881,11 +1876,17 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
 }
 
 /// Write a `ConstVal` in a way closer to the original source code than the `Debug` output.
-fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
-    use middle::const_val::ConstVal::*;
+pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
+    use middle::const_val::ConstVal;
     match const_val.val {
-        Unevaluated(..) => write!(fmt, "{:?}", const_val),
-        Value(val) => print_miri_value(val, const_val.ty, fmt),
+        ConstVal::Unevaluated(..) => write!(fmt, "{:?}", const_val),
+        ConstVal::Value(val) => {
+            if let Some(value) = val.to_byval_value() {
+                print_miri_value(value, const_val.ty, fmt)
+            } else {
+                write!(fmt, "{:?}:{}", val, const_val.ty)
+            }
+        },
     }
 }
 
index 6a9ff39c5f56b191163d8e59256b10a020501ade..67dfad50f4435ee0c67890e913c1517f2ddd9ca1 100644 (file)
@@ -69,7 +69,7 @@ pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                 PlaceTy::Ty {
                     ty: match ty.sty {
                         ty::TyArray(inner, size) => {
-                            let size = size.val.unwrap_u64();
+                            let size = size.unwrap_usize(tcx);
                             let len = size - (from as u64) - (to as u64);
                             tcx.mk_array(inner, len)
                         }
index 23f84881c798098355513316001a1cb34bee001c..bbf873290a928f76a277fb5ef8213fc7b8adb831 100644 (file)
@@ -869,10 +869,16 @@ pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -
         ret
     }
 
+    /// Returns the number of query threads that should be used for this
+    /// compilation
+    pub fn query_threads_from_opts(opts: &config::Options) -> usize {
+        opts.debugging_opts.query_threads.unwrap_or(1)
+    }
+
     /// Returns the number of query threads that should be used for this
     /// compilation
     pub fn query_threads(&self) -> usize {
-        self.opts.debugging_opts.query_threads.unwrap_or(1)
+        Self::query_threads_from_opts(&self.opts)
     }
 
     /// Returns the number of codegen units that should be used for this
index 10d88063ac35faea1c358253ffb82fbb42207169..a765ffe2396bf471db0e385e17a0bc36286bd5a6 100644 (file)
@@ -674,7 +674,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // we move over to lazy normalization *anyway*.
         let fulfill_cx = FulfillmentContext::new_ignoring_regions();
 
-        let predicates = match fully_normalize_with_fulfillcx(
+        let predicates = match fully_normalize(
             &infcx,
             fulfill_cx,
             cause,
@@ -734,31 +734,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     })
 }
 
-pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                          cause: ObligationCause<'tcx>,
-                                          param_env: ty::ParamEnv<'tcx>,
-                                          value: &T)
-                                          -> Result<T, Vec<FulfillmentError<'tcx>>>
-    where T : TypeFoldable<'tcx>
-{
-    // FIXME (@jroesch) ISSUE 26721
-    // I'm not sure if this is a bug or not, needs further investigation.
-    // It appears that by reusing the fulfillment_cx here we incur more
-    // obligations and later trip an assertion on regionck.rs line 337.
-    //
-    // The two possibilities I see is:
-    //      - normalization is not actually fully happening and we
-    //        have a bug else where
-    //      - we are adding a duplicate bound into the list causing
-    //        its size to change.
-    //
-    // I think we should probably land this refactor and then come
-    // back to this is a follow-up patch.
-    let fulfillcx = FulfillmentContext::new();
-    fully_normalize_with_fulfillcx(infcx, fulfillcx, cause, param_env, value)
-}
-
-pub fn fully_normalize_with_fulfillcx<'a, 'gcx, 'tcx, T>(
+pub fn fully_normalize<'a, 'gcx, 'tcx, T>(
     infcx: &InferCtxt<'a, 'gcx, 'tcx>,
     mut fulfill_cx: FulfillmentContext<'tcx>,
     cause: ObligationCause<'tcx>,
@@ -779,13 +755,7 @@ pub fn fully_normalize_with_fulfillcx<'a, 'gcx, 'tcx, T>(
     }
 
     debug!("fully_normalize: select_all_or_error start");
-    match fulfill_cx.select_all_or_error(infcx) {
-        Ok(()) => { }
-        Err(e) => {
-            debug!("fully_normalize: error={:?}", e);
-            return Err(e);
-        }
-    }
+    fulfill_cx.select_all_or_error(infcx)?;
     debug!("fully_normalize: select_all_or_error complete");
     let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value);
     debug!("fully_normalize: resolved_value={:?}", resolved_value);
index 30b2c55afa1948c5c9f24277655d78d5d15fae8e..d33806285142e4ba90de19eeac6cf240684892f0 100644 (file)
@@ -196,6 +196,7 @@ pub(super) fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // that this always succeeds.
         let impl1_trait_ref =
             match traits::fully_normalize(&infcx,
+                                          FulfillmentContext::new(),
                                           ObligationCause::dummy(),
                                           penv,
                                           &impl1_trait_ref) {
index 4e15f0711a5aa2a6b88bc71cde1635b801215117..d911f32ed3f1f7bc227d5f08ab4854de38011233 100644 (file)
@@ -24,6 +24,7 @@
 use std::intrinsics;
 use ty::{self, Ty, TyCtxt};
 use ty::subst::Substs;
+use mir::interpret::Allocation;
 
 /// The shorthand encoding uses an enum's variant index `usize`
 /// and is offset by this value so it never matches a real variant.
@@ -262,6 +263,15 @@ pub fn decode_const<'a, 'tcx, D>(decoder: &mut D)
     Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?))
 }
 
+#[inline]
+pub fn decode_allocation<'a, 'tcx, D>(decoder: &mut D)
+                                 -> Result<&'tcx Allocation, D::Error>
+    where D: TyDecoder<'a, 'tcx>,
+          'tcx: 'a,
+{
+    Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?))
+}
+
 #[macro_export]
 macro_rules! __impl_decoder_methods {
     ($($name:ident -> $ty:ty;)*) => {
@@ -393,6 +403,15 @@ fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
                     decode_const(self)
                 }
             }
+
+            impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::mir::interpret::Allocation>
+            for $DecoderName<$($typaram),*> {
+                fn specialized_decode(
+                    &mut self
+                ) -> Result<&'tcx $crate::mir::interpret::Allocation, Self::Error> {
+                    decode_allocation(self)
+                }
+            }
         }
     }
 }
index 36eb091cb6e5bcefc5d6f5b34ba14b1706e41199..dcd20465fbb9a1537954f701501564de942c0a43 100644 (file)
 use ich::{StableHashingContext, NodeIdHashingMode};
 use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
 use infer::outlives::free_region_map::FreeRegionMap;
-use middle::const_val::ConstVal;
-use middle::cstore::{CrateStore, LinkMeta};
+use middle::cstore::{CrateStoreDyn, LinkMeta};
 use middle::cstore::EncodedMetadata;
 use middle::lang_items;
 use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
 use middle::stability;
 use mir::{self, Mir, interpret};
-use mir::interpret::{Value, PrimVal};
 use ty::subst::{Kind, Substs, Subst};
 use ty::ReprOptions;
 use ty::Instance;
@@ -162,66 +160,65 @@ fn new(arena: &'tcx SyncDroplessArena) -> CtxtInterners<'tcx> {
         }
     }
 
-    /// Intern a type. global_interners is Some only if this is
-    /// a local interner and global_interners is its counterpart.
-    fn intern_ty(&self, st: TypeVariants<'tcx>,
-                 global_interners: Option<&CtxtInterners<'gcx>>)
-                 -> Ty<'tcx> {
-        let ty = {
-            let mut interner = self.type_.borrow_mut();
+    /// Intern a type
+    fn intern_ty(
+        local: &CtxtInterners<'tcx>,
+        global: &CtxtInterners<'gcx>,
+        st: TypeVariants<'tcx>
+    ) -> Ty<'tcx> {
+        let flags = super::flags::FlagComputation::for_sty(&st);
+
+        // HACK(eddyb) Depend on flags being accurate to
+        // determine that all contents are in the global tcx.
+        // See comments on Lift for why we can't use that.
+        if flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) {
+            let mut interner = local.type_.borrow_mut();
             if let Some(&Interned(ty)) = interner.get(&st) {
                 return ty;
             }
-            let global_interner = global_interners.map(|interners| {
-                (interners.type_.borrow_mut(), &interners.arena)
-            });
-            if let Some((ref type_, _)) = global_interner {
-                if let Some(&Interned(ty)) = type_.get(&st) {
-                    return ty;
-                }
-            }
 
-            let flags = super::flags::FlagComputation::for_sty(&st);
             let ty_struct = TyS {
                 sty: st,
                 flags: flags.flags,
                 region_depth: flags.depth,
             };
 
-            // HACK(eddyb) Depend on flags being accurate to
-            // determine that all contents are in the global tcx.
-            // See comments on Lift for why we can't use that.
-            if !flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) {
-                if let Some((mut type_, arena)) = global_interner {
-                    let ty_struct: TyS<'gcx> = unsafe {
-                        mem::transmute(ty_struct)
-                    };
-                    let ty: Ty<'gcx> = arena.alloc(ty_struct);
-                    type_.insert(Interned(ty));
-                    return ty;
-                }
-            } else {
-                // Make sure we don't end up with inference
-                // types/regions in the global tcx.
-                if global_interner.is_none() {
-                    drop(interner);
-                    bug!("Attempted to intern `{:?}` which contains \
-                          inference types/regions in the global type context",
-                         &ty_struct);
-                }
+            // Make sure we don't end up with inference
+            // types/regions in the global interner
+            if local as *const _ as usize == global as *const _ as usize {
+                bug!("Attempted to intern `{:?}` which contains \
+                    inference types/regions in the global type context",
+                    &ty_struct);
             }
 
             // Don't be &mut TyS.
-            let ty: Ty<'tcx> = self.arena.alloc(ty_struct);
+            let ty: Ty<'tcx> = local.arena.alloc(ty_struct);
             interner.insert(Interned(ty));
             ty
-        };
+        } else {
+            let mut interner = global.type_.borrow_mut();
+            if let Some(&Interned(ty)) = interner.get(&st) {
+                return ty;
+            }
 
-        debug!("Interned type: {:?} Pointer: {:?}",
-            ty, ty as *const TyS);
-        ty
-    }
+            let ty_struct = TyS {
+                sty: st,
+                flags: flags.flags,
+                region_depth: flags.depth,
+            };
+
+            // This is safe because all the types the ty_struct can point to
+            // already is in the global arena
+            let ty_struct: TyS<'gcx> = unsafe {
+                mem::transmute(ty_struct)
+            };
 
+            // Don't be &mut TyS.
+            let ty: Ty<'gcx> = global.arena.alloc(ty_struct);
+            interner.insert(Interned(ty));
+            ty
+        }
+    }
 }
 
 pub struct CommonTypes<'tcx> {
@@ -796,7 +793,7 @@ fn hash_stable<W: StableHasherResult>(&self,
 
 impl<'tcx> CommonTypes<'tcx> {
     fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
-        let mk = |sty| interners.intern_ty(sty, None);
+        let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty);
         let mk_region = |r| {
             if let Some(r) = interners.region.borrow().get(&r) {
                 return r.0;
@@ -855,7 +852,7 @@ pub struct GlobalCtxt<'tcx> {
     global_arenas: &'tcx GlobalArenas<'tcx>,
     global_interners: CtxtInterners<'tcx>,
 
-    cstore: &'tcx dyn CrateStore,
+    cstore: &'tcx CrateStoreDyn,
 
     pub sess: &'tcx Session,
 
@@ -1132,7 +1129,7 @@ pub fn allocate_cached(self, bytes: &[u8]) -> interpret::AllocId {
             return alloc_id;
         }
         // create an allocation that just contains these bytes
-        let alloc = interpret::Allocation::from_bytes(bytes);
+        let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes);
         let alloc = self.intern_const_alloc(alloc);
 
         // the next unique id
@@ -1191,7 +1188,7 @@ 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,
-                                  cstore: &'tcx dyn CrateStore,
+                                  cstore: &'tcx CrateStoreDyn,
                                   local_providers: ty::maps::Providers<'tcx>,
                                   extern_providers: ty::maps::Providers<'tcx>,
                                   arenas: &'tcx AllArenas<'tcx>,
@@ -1803,9 +1800,11 @@ fn span_debug(span: syntax_pos::Span, f: &mut fmt::Formatter) -> fmt::Result {
     /// in librustc otherwise. It is used to when diagnostic messages are
     /// emitted and stores them in the current query, if there is one.
     fn track_diagnostic(diagnostic: &Diagnostic) {
-        with_context(|context| {
-            if let Some(ref query) = context.query {
-                query.diagnostics.lock().push(diagnostic.clone());
+        with_context_opt(|icx| {
+            if let Some(icx) = icx {
+                if let Some(ref query) = icx.query {
+                    query.diagnostics.lock().push(diagnostic.clone());
+                }
             }
         })
     }
@@ -2130,31 +2129,17 @@ macro_rules! intern_method {
                                             $keep_in_local_tcx:expr) -> $ty:ty) => {
         impl<'a, 'gcx, $lt_tcx> TyCtxt<'a, 'gcx, $lt_tcx> {
             pub fn $method(self, v: $alloc) -> &$lt_tcx $ty {
-                {
-                    let key = ($alloc_to_key)(&v);
-                    if let Some(i) = self.interners.$name.borrow().get(key) {
-                        return i.0;
-                    }
-                    if !self.is_global() {
-                        if let Some(i) = self.global_interners.$name.borrow().get(key) {
-                            return i.0;
-                        }
-                    }
-                }
+                let key = ($alloc_to_key)(&v);
 
                 // HACK(eddyb) Depend on flags being accurate to
                 // determine that all contents are in the global tcx.
                 // See comments on Lift for why we can't use that.
-                if !($keep_in_local_tcx)(&v) {
-                    if !self.is_global() {
-                        let v = unsafe {
-                            mem::transmute(v)
-                        };
-                        let i = ($alloc_to_ret)(self.global_interners.arena.$alloc_method(v));
-                        self.global_interners.$name.borrow_mut().insert(Interned(i));
-                        return i;
+                if ($keep_in_local_tcx)(&v) {
+                    let mut interner = self.interners.$name.borrow_mut();
+                    if let Some(&Interned(v)) = interner.get(key) {
+                        return v;
                     }
-                } else {
+
                     // Make sure we don't end up with inference
                     // types/regions in the global tcx.
                     if self.is_global() {
@@ -2162,11 +2147,24 @@ pub fn $method(self, v: $alloc) -> &$lt_tcx $ty {
                               inference types/regions in the global type context",
                              v);
                     }
-                }
 
-                let i = ($alloc_to_ret)(self.interners.arena.$alloc_method(v));
-                self.interners.$name.borrow_mut().insert(Interned(i));
-                i
+                    let i = ($alloc_to_ret)(self.interners.arena.$alloc_method(v));
+                    interner.insert(Interned(i));
+                    i
+                } else {
+                    let mut interner = self.global_interners.$name.borrow_mut();
+                    if let Some(&Interned(v)) = interner.get(key) {
+                        return v;
+                    }
+
+                    // This transmutes $alloc<'tcx> to $alloc<'gcx>
+                    let v = unsafe {
+                        mem::transmute(v)
+                    };
+                    let i = ($alloc_to_ret)(self.global_interners.arena.$alloc_method(v));
+                    interner.insert(Interned(i));
+                    i
+                }
             }
         }
     }
@@ -2274,15 +2272,8 @@ pub fn coerce_closure_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
         self.mk_fn_ptr(converted_sig)
     }
 
-    // Interns a type/name combination, stores the resulting box in cx.interners,
-    // and returns the box as cast to an unsafe ptr (see comments for Ty above).
-    pub fn mk_ty(self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
-        let global_interners = if !self.is_global() {
-            Some(&self.global_interners)
-        } else {
-            None
-        };
-        self.interners.intern_ty(st, global_interners)
+    pub fn mk_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
+        CtxtInterners::intern_ty(&self.interners, &self.global_interners, st)
     }
 
     pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> {
@@ -2375,10 +2366,7 @@ pub fn mk_nil_ptr(self) -> Ty<'tcx> {
     }
 
     pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
-        self.mk_ty(TyArray(ty, self.mk_const(ty::Const {
-            val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.into()))),
-            ty: self.types.usize
-        })))
+        self.mk_ty(TyArray(ty, ty::Const::from_usize(self, n)))
     }
 
     pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> {
index cfde35de93c3b1ac2963dd0186bb2b628d74f93a..7dfdc592647dbafaa7cdd610c1dcbf60abc5983d 100644 (file)
@@ -182,7 +182,7 @@ pub fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String {
             ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
             ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)),
             ty::TyArray(_, n) => {
-                match n.val.to_raw_bits() {
+                match n.assert_usize(tcx) {
                     Some(n) => format!("array of {} elements", n),
                     None => "array".to_string(),
                 }
index 17a3d0011eddfe5276eadb910ff9dc214583568f..19e5406cd0d0a0aadf1d14224914d7280cac8dcb 100644 (file)
@@ -262,7 +262,7 @@ fn uninhabited_from(
                 }))
             },
             TyArray(ty, len) => {
-                match len.val.to_raw_bits() {
+                match len.assert_usize(tcx) {
                     // If the array is definitely non-empty, it's uninhabited if
                     // the type of its elements is uninhabited.
                     Some(n) if n != 0 => ty.uninhabited_from(visited, tcx),
index 0688dcabe5585db0d83089b372f918c30b07dbb3..9cbee143990791d7cca7e799f1f4a8eb6d4d70ba 100644 (file)
@@ -543,7 +543,7 @@ enum StructKind {
                 }
 
                 let element = self.layout_of(element)?;
-                let count = count.val.unwrap_u64();
+                let count = count.unwrap_usize(tcx);
                 let size = element.size.checked_mul(count, dl)
                     .ok_or(LayoutError::SizeOverflow(ty))?;
 
index 57c8c4f34e70e66c72ad4a8724972d8a989d6f74..4e104692d859b78f75a0efd5a30ae0e13a847f23 100644 (file)
@@ -11,7 +11,7 @@
 use dep_graph::SerializedDepNodeIndex;
 use dep_graph::DepNode;
 use hir::def_id::{CrateNum, DefId, DefIndex};
-use mir::interpret::{GlobalId};
+use mir::interpret::{GlobalId, ConstValue};
 use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal};
 use ty::{self, ParamEnvAnd, Ty, TyCtxt};
 use ty::subst::Substs;
@@ -137,6 +137,12 @@ fn describe(tcx: TyCtxt, def_id: DefId) -> String {
     }
 }
 
+impl<'tcx> QueryDescription<'tcx> for queries::const_value_to_allocation<'tcx> {
+    fn describe(_tcx: TyCtxt, (val, ty): (ConstValue<'tcx>, Ty<'tcx>)) -> String {
+        format!("converting value `{:?}` ({}) to an allocation", val, ty)
+    }
+}
+
 impl<'tcx> QueryDescription<'tcx> for queries::erase_regions_ty<'tcx> {
     fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String {
         format!("erasing regions from `{:?}`", ty)
index da29f23589e85e7a5f464cc5d325d1fbc8b49787..3510a1b7a028f55a04d4ded97028b1a8fe47bde1 100644 (file)
@@ -145,6 +145,15 @@ fn default_span(&self, tcx: TyCtxt) -> Span {
     }
 }
 
+impl<'tcx> Key for (mir::interpret::ConstValue<'tcx>, Ty<'tcx>) {
+    fn map_crate(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+    fn default_span(&self, _: TyCtxt) -> Span {
+        DUMMY_SP
+    }
+}
+
 impl<'tcx> Key for Ty<'tcx> {
     fn map_crate(&self) -> CrateNum {
         LOCAL_CRATE
index d89846a75ef51a8050c0af043e60045f2830666f..6e419627dd8b5bfe6ed04ecd6fac754fdb18c0f4 100644 (file)
@@ -28,7 +28,7 @@
 use middle::const_val::EvalResult;
 use mir::mono::{CodegenUnit, Stats};
 use mir;
-use mir::interpret::{GlobalId};
+use mir::interpret::{GlobalId, Allocation, ConstValue};
 use session::{CompileResult, CrateDisambiguator};
 use session::config::OutputFilenames;
 use traits::{self, Vtable};
     [] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
         -> EvalResult<'tcx>,
 
+    /// Converts a constant value to an constant allocation
+    [] fn const_value_to_allocation: const_value_to_allocation(
+        (ConstValue<'tcx>, Ty<'tcx>)
+    ) -> &'tcx Allocation,
+
     [] fn check_match: CheckMatch(DefId)
         -> Result<(), ErrorReported>,
 
@@ -478,6 +483,12 @@ fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> {
     DepConstructor::EraseRegionsTy { ty }
 }
 
+fn const_value_to_allocation<'tcx>(
+    (val, ty): (ConstValue<'tcx>, Ty<'tcx>)
+) -> DepConstructor<'tcx> {
+    DepConstructor::ConstValueToAllocation { val, ty }
+}
+
 fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
     DepConstructor::TypeParamPredicates {
         item_id,
index 37950463f74446d1f9b486224e416832a04e8f9b..65dcb7311d336fd76885afc62aa53c50be118b50 100644 (file)
@@ -956,6 +956,7 @@ macro_rules! force {
         DepKind::FulfillObligation |
         DepKind::VtableMethods |
         DepKind::EraseRegionsTy |
+        DepKind::ConstValueToAllocation |
         DepKind::NormalizeProjectionTy |
         DepKind::NormalizeTyAfterErasingRegions |
         DepKind::DropckOutlives |
index 7076112e3715a285b6377140e3319d40332fcff3..eede7bd2ea619ac230f5a63aa0371c1879cafbeb 100644 (file)
 use ich::Fingerprint;
 use ich::StableHashingContext;
 use infer::canonical::{Canonical, Canonicalize};
-use middle::const_val::ConstVal;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::privacy::AccessLevels;
 use middle::resolve_lifetime::ObjectLifetimeDefault;
 use mir::Mir;
-use mir::interpret::{GlobalId, Value, PrimVal};
+use mir::interpret::GlobalId;
 use mir::GeneratorLayout;
 use session::CrateDisambiguator;
 use traits::{self, Reveal};
@@ -1933,27 +1932,23 @@ pub fn eval_explicit_discr(
             promoted: None
         };
         match tcx.const_eval(param_env.and(cid)) {
-            Ok(&ty::Const {
-                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
-                ty,
-            }) => {
-                trace!("discriminants: {} ({:?})", b, repr_type);
-                Some(Discr {
-                    val: b,
-                    ty,
-                })
-            },
-            Ok(&ty::Const {
-                val: ConstVal::Value(other),
-                ..
-            }) => {
-                info!("invalid enum discriminant: {:#?}", other);
-                ::middle::const_val::struct_error(
-                    tcx,
-                    tcx.def_span(expr_did),
-                    "constant evaluation of enum discriminant resulted in non-integer",
-                ).emit();
-                None
+            Ok(val) => {
+                // FIXME: Find the right type and use it instead of `val.ty` here
+                if let Some(b) = val.assert_bits(val.ty) {
+                    trace!("discriminants: {} ({:?})", b, repr_type);
+                    Some(Discr {
+                        val: b,
+                        ty: val.ty,
+                    })
+                } else {
+                    info!("invalid enum discriminant: {:#?}", val);
+                    ::middle::const_val::struct_error(
+                        tcx,
+                        tcx.def_span(expr_did),
+                        "constant evaluation of enum discriminant resulted in non-integer",
+                    ).emit();
+                    None
+                }
             }
             Err(err) => {
                 err.report(tcx, tcx.def_span(expr_did), "enum discriminant");
@@ -1964,7 +1959,6 @@ pub fn eval_explicit_discr(
                 }
                 None
             }
-            _ => span_bug!(tcx.def_span(expr_did), "const eval "),
         }
     }
 
index 109dfebf154de67730d3e0294d5cf092af1dee30..4a33f1a1f54d2d268bfa3c2319e28fa0aa46780f 100644 (file)
@@ -18,7 +18,7 @@
 use ty::subst::{Kind, UnpackedKind, Substs};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::error::{ExpectedFound, TypeError};
-use mir::interpret::{GlobalId, Value, PrimVal};
+use mir::interpret::GlobalId;
 use util::common::ErrorReported;
 use std::rc::Rc;
 use std::iter;
@@ -469,8 +469,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
             assert_eq!(sz_a.ty, tcx.types.usize);
             assert_eq!(sz_b.ty, tcx.types.usize);
             let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result<u64, ErrorReported> {
+                if let Some(s) = x.assert_usize(tcx) {
+                    return Ok(s);
+                }
                 match x.val {
-                    ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()),
                     ConstVal::Unevaluated(def_id, substs) => {
                         // FIXME(eddyb) get the right param_env.
                         let param_env = ty::ParamEnv::empty();
@@ -487,15 +489,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
                                         instance,
                                         promoted: None
                                     };
-                                    match tcx.const_eval(param_env.and(cid)) {
-                                        Ok(&ty::Const {
-                                            val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
-                                            ..
-                                        }) => {
-                                            assert_eq!(b as u64 as u128, b);
-                                            return Ok(b as u64);
-                                        }
-                                        _ => {}
+                                    if let Some(s) = tcx.const_eval(param_env.and(cid))
+                                                        .ok()
+                                                        .map(|c| c.unwrap_usize(tcx)) {
+                                        return Ok(s)
                                     }
                                 }
                             },
index 7518f008fb316515be6f8b4ce65e1f2ffe442b6d..f0a7ce54971661db1768ba9e0d71467addb88bfc 100644 (file)
@@ -19,6 +19,7 @@
 use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
 use ty::{Slice, TyS};
 use util::captures::Captures;
+use mir::interpret::{Allocation, PrimVal, MemoryPointer, Value, ConstValue};
 
 use std::iter;
 use std::cmp::Ordering;
@@ -1730,4 +1731,156 @@ pub struct Const<'tcx> {
     pub val: ConstVal<'tcx>,
 }
 
+impl<'tcx> Const<'tcx> {
+    pub fn unevaluated(
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        def_id: DefId,
+        substs: &'tcx Substs<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> &'tcx Self {
+        tcx.mk_const(Const {
+            val: ConstVal::Unevaluated(def_id, substs),
+            ty,
+        })
+    }
+
+    #[inline]
+    pub fn from_const_val(
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        val: ConstVal<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> &'tcx Self {
+        tcx.mk_const(Const {
+            val,
+            ty,
+        })
+    }
+
+    #[inline]
+    pub fn from_const_value(
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        val: ConstValue<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> &'tcx Self {
+        Self::from_const_val(tcx, ConstVal::Value(val), ty)
+    }
+
+    #[inline]
+    pub fn from_alloc(
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        alloc: &'tcx Allocation,
+        ty: Ty<'tcx>,
+    ) -> &'tcx Self {
+        Self::from_const_value(tcx, ConstValue::ByRef(alloc), ty)
+    }
+
+    #[inline]
+    pub fn from_byval_value(
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        val: Value,
+        ty: Ty<'tcx>,
+    ) -> &'tcx Self {
+        Self::from_const_value(tcx, ConstValue::from_byval_value(val), ty)
+    }
+
+    #[inline]
+    pub fn from_primval(
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        val: PrimVal,
+        ty: Ty<'tcx>,
+    ) -> &'tcx Self {
+        Self::from_const_value(tcx, ConstValue::from_primval(val), ty)
+    }
+
+    #[inline]
+    pub fn from_bits(
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        val: u128,
+        ty: Ty<'tcx>,
+    ) -> &'tcx Self {
+        Self::from_primval(tcx, PrimVal::Bytes(val), ty)
+    }
+
+    #[inline]
+    pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
+        Self::from_primval(tcx, PrimVal::Undef, ty)
+    }
+
+    #[inline]
+    pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> &'tcx Self {
+        Self::from_bits(tcx, v as u128, tcx.types.bool)
+    }
+
+    #[inline]
+    pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> &'tcx Self {
+        Self::from_bits(tcx, n as u128, tcx.types.usize)
+    }
+
+    #[inline]
+    pub fn to_bits(&self, ty: Ty<'_>) -> Option<u128> {
+        if self.ty != ty {
+            return None;
+        }
+        match self.val {
+            ConstVal::Value(val) => val.to_bits(),
+            _ => None,
+        }
+    }
+
+    #[inline]
+    pub fn to_ptr(&self) -> Option<MemoryPointer> {
+        match self.val {
+            ConstVal::Value(val) => val.to_ptr(),
+            _ => None,
+        }
+    }
+
+    #[inline]
+    pub fn to_primval(&self) -> Option<PrimVal> {
+        match self.val {
+            ConstVal::Value(val) => val.to_primval(),
+            _ => None,
+        }
+    }
+
+    #[inline]
+    pub fn assert_bits(&self, ty: Ty<'_>) -> Option<u128> {
+        assert_eq!(self.ty, ty);
+        match self.val {
+            ConstVal::Value(val) => val.to_bits(),
+            _ => None,
+        }
+    }
+
+    #[inline]
+    pub fn assert_bool(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<bool> {
+        self.assert_bits(tcx.types.bool).and_then(|v| match v {
+            0 => Some(false),
+            1 => Some(true),
+            _ => None,
+        })
+    }
+
+    #[inline]
+    pub fn assert_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<u64> {
+        self.assert_bits(tcx.types.usize).map(|v| v as u64)
+    }
+
+    #[inline]
+    pub fn unwrap_bits(&self, ty: Ty<'_>) -> u128 {
+        match self.assert_bits(ty) {
+            Some(val) => val,
+            None => bug!("expected bits of {}, got {:#?}", ty, self),
+        }
+    }
+
+    #[inline]
+    pub fn unwrap_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> u64 {
+        match self.assert_usize(tcx) {
+            Some(val) => val,
+            None => bug!("expected constant usize, got {:#?}", self),
+        }
+    }
+}
+
 impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {}
index 80dc3b2b452ce4047370fcf5683b9da55872d8fa..fdd0754730febb72bf0d37a73f73d95bf00c864f 100644 (file)
@@ -16,7 +16,7 @@
 use hir;
 use ich::NodeIdHashingMode;
 use middle::const_val::ConstVal;
-use traits;
+use traits::{self, ObligationCause};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::fold::TypeVisitor;
 use ty::subst::UnpackedKind;
@@ -25,7 +25,6 @@
 use ty::layout::{Integer, IntegerExt};
 use util::common::ErrorReported;
 use middle::lang_items;
-use mir::interpret::{Value, PrimVal};
 
 use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
                                            HashStable};
@@ -167,9 +166,9 @@ fn disr_incr<'a, 'tcx>(
 }
 
 
-#[derive(Copy, Clone)]
+#[derive(Clone)]
 pub enum CopyImplementationError<'tcx> {
-    InfrigingField(&'tcx ty::FieldDef),
+    InfrigingFields(Vec<&'tcx ty::FieldDef>),
     NotAnAdt,
     HasDestructor,
 }
@@ -192,7 +191,7 @@ pub enum Representability {
 impl<'tcx> ty::ParamEnv<'tcx> {
     pub fn can_type_implement_copy<'a>(self,
                                        tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                       self_type: Ty<'tcx>, span: Span)
+                                       self_type: Ty<'tcx>)
                                        -> Result<(), CopyImplementationError<'tcx>> {
         // FIXME: (@jroesch) float this code up
         tcx.infer_ctxt().enter(|infcx| {
@@ -208,22 +207,29 @@ pub fn can_type_implement_copy<'a>(self,
                 _ => return Err(CopyImplementationError::NotAnAdt),
             };
 
-            let field_implements_copy = |field: &ty::FieldDef| {
-                let cause = traits::ObligationCause::dummy();
-                match traits::fully_normalize(&infcx, cause, self, &field.ty(tcx, substs)) {
-                    Ok(ty) => !infcx.type_moves_by_default(self, ty, span),
-                    Err(..) => false,
-                }
-            };
-
+            let mut infringing = Vec::new();
             for variant in &adt.variants {
                 for field in &variant.fields {
-                    if !field_implements_copy(field) {
-                        return Err(CopyImplementationError::InfrigingField(field));
+                    let span = tcx.def_span(field.did);
+                    let ty = field.ty(tcx, substs);
+                    if ty.references_error() {
+                        continue;
                     }
+                    let cause = ObligationCause { span, ..ObligationCause::dummy() };
+                    let ctx = traits::FulfillmentContext::new();
+                    match traits::fully_normalize(&infcx, ctx, cause, self, &ty) {
+                        Ok(ty) => if infcx.type_moves_by_default(self, ty, span) {
+                            infringing.push(field);
+                        }
+                        Err(errors) => {
+                            infcx.report_fulfillment_errors(&errors, None, false);
+                        }
+                    };
                 }
             }
-
+            if !infringing.is_empty() {
+                return Err(CopyImplementationError::InfrigingFields(infringing));
+            }
             if adt.has_dtor(tcx) {
                 return Err(CopyImplementationError::HasDestructor);
             }
@@ -659,9 +665,8 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
             TyArray(_, n) => {
                 self.hash_discriminant_u8(&n.val);
                 match n.val {
-                    ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b),
+                    ConstVal::Value(alloc) => self.hash(alloc),
                     ConstVal::Unevaluated(def_id, _) => self.def_id(def_id),
-                    _ => bug!("arrays should not have {:?} as length", n)
                 }
             }
             TyRawPtr(m) => self.hash(m.mutbl),
index 4fb1017035168497b5d42b9534251e736a9e2e43..a6eb468e33836fc43fcddf6ae9e209a95b174c82 100644 (file)
@@ -21,7 +21,6 @@
 use ty::{TyDynamic, TyInt, TyUint, TyInfer};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use util::nodemap::FxHashSet;
-use mir::interpret::{Value, PrimVal};
 
 use std::cell::Cell;
 use std::fmt;
@@ -1183,15 +1182,12 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 TyArray(ty, sz) => {
                     print!(f, cx, write("["), print(ty), write("; "))?;
                     match sz.val {
-                        ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => {
-                            write!(f, "{}", sz)?;
-                        }
+                        ConstVal::Value(..) => ty::tls::with(|tcx| {
+                            write!(f, "{}", sz.unwrap_usize(tcx))
+                        })?,
                         ConstVal::Unevaluated(_def_id, _substs) => {
                             write!(f, "_")?;
                         }
-                        _ => {
-                            write!(f, "{:?}", sz)?;
-                        }
                     }
                     write!(f, "]")
                 }
index 9178d0d00faa49ae0c34f68e9d2a214b32ae047c..6f1cbcad2f46c3bec9f83df0dd1614a4548d612c 100644 (file)
@@ -16,6 +16,7 @@ serialize = { path = "../libserialize" }
 cfg-if = "0.1.2"
 stable_deref_trait = "1.0.0"
 parking_lot_core = "0.2.8"
+rustc-rayon = "0.1.0"
 
 [dependencies.parking_lot]
 version = "0.5"
index dc487f1162ca9d074b8735937e069b846a7dbc60..54407658e6ccc85f77e27682800529d98db3fba0 100644 (file)
@@ -175,7 +175,7 @@ pub fn children(&self, node: Node) -> &[Node] {
 }
 
 impl<Node: Idx> fmt::Debug for DominatorTree<Node> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         fmt::Debug::fmt(&DominatorTreeNode {
                             tree: self,
                             node: self.root,
@@ -190,7 +190,7 @@ struct DominatorTreeNode<'tree, Node: Idx> {
 }
 
 impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         let subtrees: Vec<_> = self.tree
             .children(self.node)
             .iter()
index 597d1627ada03da578556f761897937181a063c7..b2e7450e76cdf4a9063e4dbb9e5bf6c147d9165d 100644 (file)
@@ -44,6 +44,7 @@
 #[macro_use]
 extern crate cfg_if;
 extern crate stable_deref_trait;
+extern crate rustc_rayon as rayon;
 
 // See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
 #[allow(unused_extern_crates)]
index c466b8f8ad1b5acb716db8b2720dd2cadb25c08f..aa113fac9fb7dff28baa92dfba7bfe5f0b80b50b 100644 (file)
@@ -1002,7 +1002,7 @@ impl<O, T: ?Sized> Debug for OwningRef<O, T>
     where O: Debug,
           T: Debug,
 {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f,
                "OwningRef {{ owner: {:?}, reference: {:?} }}",
                self.owner(),
@@ -1014,7 +1014,7 @@ impl<O, T: ?Sized> Debug for OwningRefMut<O, T>
     where O: Debug,
           T: Debug,
 {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f,
                "OwningRefMut {{ owner: {:?}, reference: {:?} }}",
                self.owner(),
@@ -1047,7 +1047,7 @@ unsafe impl<O, T: ?Sized> Sync for OwningRefMut<O, T>
     where O: Sync, for<'a> (&'a mut T): Sync {}
 
 impl Debug for Erased {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "<Erased>",)
     }
 }
index 3b7d6efbdae1e760694fced946ac9031bd2db2ec..3661763133014b593f42fd30f0bc1bbd345f3c44 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! This mdoule defines types which are thread safe if cfg!(parallel_queries) is true.
+//! This module defines types which are thread safe if cfg!(parallel_queries) is true.
 //!
 //! `Lrc` is an alias of either Rc or Arc.
 //!
 use std::ops::{Deref, DerefMut};
 use owning_ref::{Erased, OwningRef};
 
+pub fn serial_join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
+    where A: FnOnce() -> RA,
+          B: FnOnce() -> RB
+{
+    (oper_a(), oper_b())
+}
+
+pub struct SerialScope;
+
+impl SerialScope {
+    pub fn spawn<F>(&self, f: F)
+        where F: FnOnce(&SerialScope)
+    {
+        f(self)
+    }
+}
+
+pub fn serial_scope<F, R>(f: F) -> R
+    where F: FnOnce(&SerialScope) -> R
+{
+    f(&SerialScope)
+}
+
 cfg_if! {
     if #[cfg(not(parallel_queries))] {
         pub auto trait Send {}
@@ -55,9 +78,19 @@ macro_rules! rustc_erase_owner {
             }
         }
 
+        pub use self::serial_join as join;
+        pub use self::serial_scope as scope;
+
+        pub use std::iter::Iterator as ParallelIterator;
+
+        pub fn par_iter<T: IntoIterator>(t: T) -> T::IntoIter {
+            t.into_iter()
+        }
+
         pub type MetadataRef = OwningRef<Box<Erased>, [u8]>;
 
         pub use std::rc::Rc as Lrc;
+        pub use std::rc::Weak as Weak;
         pub use std::cell::Ref as ReadGuard;
         pub use std::cell::RefMut as WriteGuard;
         pub use std::cell::RefMut as LockGuard;
@@ -160,6 +193,7 @@ pub fn take(&self) -> Option<T> {
         pub use parking_lot::MutexGuard as LockGuard;
 
         pub use std::sync::Arc as Lrc;
+        pub use std::sync::Weak as Weak;
 
         pub use self::Lock as MTLock;
 
@@ -167,6 +201,14 @@ pub fn take(&self) -> Option<T> {
         use parking_lot::RwLock as InnerRwLock;
 
         use std::thread;
+        pub use rayon::{join, scope};
+
+        pub use rayon::iter::ParallelIterator;
+        use rayon::iter::IntoParallelIterator;
+
+        pub fn par_iter<T: IntoParallelIterator>(t: T) -> T::Iter {
+            t.into_par_iter()
+        }
 
         pub type MetadataRef = OwningRef<Box<Erased + Send + Sync>, [u8]>;
 
index 5aae1bcad896f18fdee8a2d9ac60f8e7d27ab865..1827533f0acb5977be80b10f24c89e85f7291980 100644 (file)
@@ -13,6 +13,8 @@ arena = { path = "../libarena" }
 graphviz = { path = "../libgraphviz" }
 log = "0.4"
 env_logger = { version = "0.5", default-features = false }
+rustc-rayon = "0.1.0"
+scoped-tls = { version = "0.1.1", features = ["nightly"] }
 rustc = { path = "../librustc" }
 rustc_allocator = { path = "../librustc_allocator" }
 rustc_target = { path = "../librustc_target" }
index 1e74039503d51c5760498d1fd3f8de3f75e7b5d5..62b3accc46f18e6bfc85600df45e1def21ef59c2 100644 (file)
@@ -20,7 +20,7 @@
 use rustc::session::search_paths::PathKind;
 use rustc::lint;
 use rustc::middle::{self, reachable, resolve_lifetime, stability};
-use rustc::middle::cstore::CrateStore;
+use rustc::middle::cstore::CrateStoreDyn;
 use rustc::middle::privacy::AccessLevels;
 use rustc::ty::{self, AllArenas, Resolutions, TyCtxt};
 use rustc::traits;
@@ -49,7 +49,7 @@
 use std::io::{self, Write};
 use std::iter;
 use std::path::{Path, PathBuf};
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{self, Lrc};
 use std::sync::mpsc;
 use syntax::{self, ast, attr, diagnostics, visit};
 use syntax::ext::base::ExtCtxt;
 
 use profile;
 
+#[cfg(not(parallel_queries))]
+pub fn spawn_thread_pool<F: FnOnce(config::Options) -> R + sync::Send, R: sync::Send>(
+    opts: config::Options,
+    f: F
+) -> R {
+    f(opts)
+}
+
+#[cfg(parallel_queries)]
+pub fn spawn_thread_pool<F: FnOnce(config::Options) -> R + sync::Send, R: sync::Send>(
+    opts: config::Options,
+    f: F
+) -> R {
+    use syntax;
+    use syntax_pos;
+    use rayon::{ThreadPoolBuilder, ThreadPool};
+
+    let config = ThreadPoolBuilder::new().num_threads(Session::query_threads_from_opts(&opts))
+                                         .stack_size(16 * 1024 * 1024);
+
+    let with_pool = move |pool: &ThreadPool| {
+        pool.install(move || f(opts))
+    };
+
+    syntax::GLOBALS.with(|syntax_globals| {
+        syntax_pos::GLOBALS.with(|syntax_pos_globals| {
+            // The main handler run for each Rayon worker thread and sets up
+            // the thread local rustc uses. syntax_globals and syntax_pos_globals are
+            // captured and set on the new threads. ty::tls::with_thread_locals sets up
+            // thread local callbacks from libsyntax
+            let main_handler = move |worker: &mut FnMut()| {
+                syntax::GLOBALS.set(syntax_globals, || {
+                    syntax_pos::GLOBALS.set(syntax_pos_globals, || {
+                        ty::tls::with_thread_locals(|| {
+                            worker()
+                        })
+                    })
+                })
+            };
+
+            ThreadPool::scoped_pool(config, main_handler, with_pool).unwrap()
+        })
+    })
+}
+
 pub fn compile_input(
     trans: Box<TransCrate>,
     sess: &Session,
@@ -1047,7 +1092,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(
     trans: &TransCrate,
     control: &CompileController,
     sess: &'tcx Session,
-    cstore: &'tcx CrateStore,
+    cstore: &'tcx CrateStoreDyn,
     hir_map: hir_map::Map<'tcx>,
     mut analysis: ty::CrateAnalysis,
     resolutions: Resolutions,
index a1052ca6c3ca9520fc7cf8f4e38ebc106f8263a7..148fbd73e9bd8ffc7d1e9cafea1c8cf684c0b684 100644 (file)
 #![feature(rustc_stack_internals)]
 #![feature(no_debug)]
 
+#![recursion_limit="256"]
+
 extern crate arena;
 extern crate getopts;
 extern crate graphviz;
 extern crate env_logger;
 #[cfg(unix)]
 extern crate libc;
+extern crate rustc_rayon as rayon;
 extern crate rustc;
 extern crate rustc_allocator;
 extern crate rustc_target;
@@ -51,6 +54,7 @@
 extern crate rustc_traits;
 extern crate rustc_trans_utils;
 extern crate rustc_typeck;
+extern crate scoped_tls;
 extern crate serialize;
 #[macro_use]
 extern crate log;
@@ -64,7 +68,7 @@
 use rustc_resolve as resolve;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{self, Lrc};
 use rustc_data_structures::OnDrop;
 use rustc::session::{self, config, Session, build_session, CompileResult};
 use rustc::session::CompileIncomplete;
@@ -448,22 +452,33 @@ fn GetModuleFileNameW(hModule: usize,
 // See comments on CompilerCalls below for details about the callbacks argument.
 // The FileLoader provides a way to load files from sources other than the file system.
 pub fn run_compiler<'a>(args: &[String],
-                        callbacks: &mut CompilerCalls<'a>,
+                        callbacks: &mut (CompilerCalls<'a> + sync::Send),
                         file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
                         emitter_dest: Option<Box<Write + Send>>)
                         -> (CompileResult, Option<Session>)
 {
     syntax::with_globals(|| {
-        run_compiler_impl(args, callbacks, file_loader, emitter_dest)
+        let matches = match handle_options(args) {
+            Some(matches) => matches,
+            None => return (Ok(()), None),
+        };
+
+        let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
+
+        driver::spawn_thread_pool(sopts, |sopts| {
+            run_compiler_with_pool(matches, sopts, cfg, callbacks, file_loader, emitter_dest)
+        })
     })
 }
 
-fn run_compiler_impl<'a>(args: &[String],
-                         callbacks: &mut CompilerCalls<'a>,
-                         file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
-                         emitter_dest: Option<Box<Write + Send>>)
-                         -> (CompileResult, Option<Session>)
-{
+fn run_compiler_with_pool<'a>(
+    matches: getopts::Matches,
+    sopts: config::Options,
+    cfg: ast::CrateConfig,
+    callbacks: &mut (CompilerCalls<'a> + sync::Send),
+    file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
+    emitter_dest: Option<Box<Write + Send>>
+) -> (CompileResult, Option<Session>) {
     macro_rules! do_or_return {($expr: expr, $sess: expr) => {
         match $expr {
             Compilation::Stop => return (Ok(()), $sess),
@@ -471,13 +486,6 @@ macro_rules! do_or_return {($expr: expr, $sess: expr) => {
         }
     }}
 
-    let matches = match handle_options(args) {
-        Some(matches) => matches,
-        None => return (Ok(()), None),
-    };
-
-    let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
-
     let descriptions = diagnostics_registry();
 
     do_or_return!(callbacks.early_callback(&matches,
index 70b73ebb8cdeb476f5b978bdf9579a8e017542a7..108b47623383c0e3e27755fca3c4dd01f4bbd1d0 100644 (file)
@@ -20,7 +20,7 @@
 use rustc::ty::{self, TyCtxt, Resolutions, AllArenas};
 use rustc::cfg;
 use rustc::cfg::graphviz::LabelledCFG;
-use rustc::middle::cstore::CrateStore;
+use rustc::middle::cstore::CrateStoreDyn;
 use rustc::session::Session;
 use rustc::session::config::{Input, OutputFilenames};
 use rustc_borrowck as borrowck;
@@ -199,7 +199,7 @@ fn call_with_pp_support<'tcx, A, F>(&self,
     }
     fn call_with_pp_support_hir<'tcx, A, F>(&self,
                                                sess: &'tcx Session,
-                                               cstore: &'tcx CrateStore,
+                                               cstore: &'tcx CrateStoreDyn,
                                                hir_map: &hir_map::Map<'tcx>,
                                                analysis: &ty::CrateAnalysis,
                                                resolutions: &Resolutions,
@@ -912,7 +912,7 @@ pub fn print_after_parsing(sess: &Session,
 }
 
 pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
-                                                cstore: &'tcx CrateStore,
+                                                cstore: &'tcx CrateStoreDyn,
                                                 hir_map: &hir_map::Map<'tcx>,
                                                 analysis: &ty::CrateAnalysis,
                                                 resolutions: &Resolutions,
@@ -1068,7 +1068,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
 // with a different callback than the standard driver, so that isn't easy.
 // Instead, we call that function ourselves.
 fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
-                                       cstore: &'a CrateStore,
+                                       cstore: &'a CrateStoreDyn,
                                        hir_map: &hir_map::Map<'tcx>,
                                        analysis: &ty::CrateAnalysis,
                                        resolutions: &Resolutions,
index d2ee3d8743c2cd74886d8e3b3a5d18098c5d22e7..7ae26e9e9798e72c15b8f64e70d1459c0b90e6c5 100644 (file)
@@ -99,20 +99,25 @@ fn test_env<F>(source_string: &str,
     where F: FnOnce(Env)
 {
     syntax::with_globals(|| {
-        test_env_impl(source_string, args, body)
+        let mut options = config::basic_options();
+        options.debugging_opts.verbose = true;
+        options.unstable_features = UnstableFeatures::Allow;
+
+        driver::spawn_thread_pool(options, |options| {
+            test_env_with_pool(options, source_string, args, body)
+        })
     });
 }
 
-fn test_env_impl<F>(source_string: &str,
-                    (emitter, expected_err_count): (Box<Emitter + sync::Send>, usize),
-                    body: F)
+fn test_env_with_pool<F>(
+    options: config::Options,
+    source_string: &str,
+    (emitter, expected_err_count): (Box<Emitter + sync::Send>, usize),
+    body: F
+)
     where F: FnOnce(Env)
 {
-    let mut options = config::basic_options();
-    options.debugging_opts.verbose = true;
-    options.unstable_features = UnstableFeatures::Allow;
     let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
-
     let sess = session::build_session_(options,
                                        None,
                                        diagnostic_handler,
index c2b442e949758a19c64f4b2aa73dc8d7264f6282..fd90e1cbe0866b16bdbfaefb2dfd20c4e6055a20 100644 (file)
@@ -232,7 +232,7 @@ pub fn raise(self) -> ! {
 }
 
 impl fmt::Display for FatalError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "parser fatal error")
     }
 }
@@ -249,7 +249,7 @@ fn description(&self) -> &str {
 pub struct ExplicitBug;
 
 impl fmt::Display for ExplicitBug {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "parser internal bug")
     }
 }
index a5e07bcec24bb65c242de5765c68c6ad9c3792a9..ababce69e3170d850e939df33dfefdc3b4039ad6 100644 (file)
@@ -36,9 +36,9 @@
 pub use persist::load_dep_graph;
 pub use persist::load_query_result_cache;
 pub use persist::LoadResult;
+pub use persist::copy_cgu_workproducts_to_incr_comp_cache_dir;
 pub use persist::save_dep_graph;
-pub use persist::save_trans_partition;
-pub use persist::save_work_products;
+pub use persist::save_work_product_index;
 pub use persist::in_incr_comp_dir;
 pub use persist::prepare_session_directory;
 pub use persist::finalize_session_directory;
index 755a550b5bca31e4af3a120cd56d4b6ce22dd204..e1f00db56d5cbc0572214a3a15d94941e7a8b09e 100644 (file)
@@ -29,6 +29,6 @@
 pub use self::load::load_query_result_cache;
 pub use self::load::LoadResult;
 pub use self::save::save_dep_graph;
-pub use self::save::save_work_products;
-pub use self::work_product::save_trans_partition;
+pub use self::save::save_work_product_index;
+pub use self::work_product::copy_cgu_workproducts_to_incr_comp_cache_dir;
 pub use self::work_product::delete_workproduct_files;
index e524fcecf9094a3edce0a932d97ee83f2878272c..be725b17933215661af70724ba01e6b4c432a7b7 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::dep_graph::{DepGraph, DepKind};
+use rustc::dep_graph::{DepGraph, DepKind, WorkProduct, WorkProductId};
 use rustc::session::Session;
 use rustc::ty::TyCtxt;
 use rustc::util::common::time;
@@ -55,22 +55,22 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     })
 }
 
-pub fn save_work_products(sess: &Session, dep_graph: &DepGraph) {
+pub fn save_work_product_index(sess: &Session,
+                               dep_graph: &DepGraph,
+                               new_work_products: FxHashMap<WorkProductId, WorkProduct>) {
     if sess.opts.incremental.is_none() {
         return;
     }
 
-    debug!("save_work_products()");
+    debug!("save_work_product_index()");
     dep_graph.assert_ignored();
     let path = work_products_path(sess);
-    save_in(sess, path, |e| encode_work_products(dep_graph, e));
+    save_in(sess, path, |e| encode_work_product_index(&new_work_products, e));
 
     // We also need to clean out old work-products, as not all of them are
     // deleted during invalidation. Some object files don't change their
     // content, they are just not needed anymore.
-    let new_work_products = dep_graph.work_products();
     let previous_work_products = dep_graph.previous_work_products();
-
     for (id, wp) in previous_work_products.iter() {
         if !new_work_products.contains_key(id) {
             work_product::delete_workproduct_files(sess, wp);
@@ -234,10 +234,9 @@ struct Stat {
     Ok(())
 }
 
-fn encode_work_products(dep_graph: &DepGraph,
-                        encoder: &mut Encoder) -> io::Result<()> {
-    let work_products: Vec<_> = dep_graph
-        .work_products()
+fn encode_work_product_index(work_products: &FxHashMap<WorkProductId, WorkProduct>,
+                             encoder: &mut Encoder) -> io::Result<()> {
+    let serialized_products: Vec<_> = work_products
         .iter()
         .map(|(id, work_product)| {
             SerializedWorkProduct {
@@ -247,7 +246,7 @@ fn encode_work_products(dep_graph: &DepGraph,
         })
         .collect();
 
-    work_products.encode(encoder)
+    serialized_products.encode(encoder)
 }
 
 fn encode_query_cache(tcx: TyCtxt,
index 879132bcacfcfcd86a3c6426152e7fc95d016e75..d0c7766cbae08bd3338ba2db91baa965c359ec1a 100644 (file)
 //! This module contains files for saving intermediate work-products.
 
 use persist::fs::*;
-use rustc::dep_graph::{WorkProduct, WorkProductId, DepGraph, WorkProductFileKind};
+use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind};
 use rustc::session::Session;
 use rustc::util::fs::link_or_copy;
 use std::path::PathBuf;
 use std::fs as std_fs;
 
-pub fn save_trans_partition(sess: &Session,
-                            dep_graph: &DepGraph,
-                            cgu_name: &str,
-                            files: &[(WorkProductFileKind, PathBuf)]) {
-    debug!("save_trans_partition({:?},{:?})",
+pub fn copy_cgu_workproducts_to_incr_comp_cache_dir(
+    sess: &Session,
+    cgu_name: &str,
+    files: &[(WorkProductFileKind, PathBuf)]
+) -> Option<(WorkProductId, WorkProduct)> {
+    debug!("copy_cgu_workproducts_to_incr_comp_cache_dir({:?},{:?})",
            cgu_name,
            files);
     if sess.opts.incremental.is_none() {
-        return
+        return None
     }
     let work_product_id = WorkProductId::from_cgu_name(cgu_name);
 
@@ -53,8 +54,8 @@ pub fn save_trans_partition(sess: &Session,
              })
              .collect();
     let saved_files = match saved_files {
+        None => return None,
         Some(v) => v,
-        None => return,
     };
 
     let work_product = WorkProduct {
@@ -62,7 +63,7 @@ pub fn save_trans_partition(sess: &Session,
         saved_files,
     };
 
-    dep_graph.insert_work_product(&work_product_id, work_product);
+    Some((work_product_id, work_product))
 }
 
 pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
index 5102bfe766eeff2370e63610b3043b9fa2357797..cbb0177fe4f4eefe6401d43634228f4a60dbdd9c 100644 (file)
@@ -541,7 +541,7 @@ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
         if !ty.moves_by_default(cx.tcx, param_env, item.span) {
             return;
         }
-        if param_env.can_type_implement_copy(cx.tcx, ty, item.span).is_ok() {
+        if param_env.can_type_implement_copy(cx.tcx, ty).is_ok() {
             cx.span_lint(MISSING_COPY_IMPLEMENTATIONS,
                          item.span,
                          "type could implement `Copy`; consider adding `impl \
@@ -1287,32 +1287,27 @@ fn get_lints(&self) -> LintArray {
 
 impl UnreachablePub {
     fn perform_lint(&self, cx: &LateContext, what: &str, id: ast::NodeId,
-                    vis: &hir::Visibility, span: Span, exportable: bool) {
+                    vis: &hir::Visibility, span: Span, exportable: bool,
+                    mut applicability: Applicability) {
         if !cx.access_levels.is_reachable(id) && *vis == hir::Visibility::Public {
+            if span.ctxt().outer().expn_info().is_some() {
+                applicability = Applicability::MaybeIncorrect;
+            }
             let def_span = cx.tcx.sess.codemap().def_span(span);
             let mut err = cx.struct_span_lint(UNREACHABLE_PUB, def_span,
                                               &format!("unreachable `pub` {}", what));
-            // visibility is token at start of declaration (can be macro
-            // variable rather than literal `pub`)
+            // We are presuming that visibility is token at start of
+            // declaration (can be macro variable rather than literal `pub`)
             let pub_span = cx.tcx.sess.codemap().span_until_char(def_span, ' ');
             let replacement = if cx.tcx.features().crate_visibility_modifier {
                 "crate"
             } else {
                 "pub(crate)"
             }.to_owned();
-            let app = if span.ctxt().outer().expn_info().is_none() {
-                // even if macros aren't involved the suggestion
-                // may be incorrect -- the user may have mistakenly
-                // hidden it behind a private module and this lint is
-                // a helpful way to catch that. However, we're trying
-                // not to change the nature of the code with this lint
-                // so it's marked as machine applicable.
-                Applicability::MachineApplicable
-            } else {
-                Applicability::MaybeIncorrect
-            };
-            err.span_suggestion_with_applicability(pub_span, "consider restricting its visibility",
-                                                   replacement, app);
+            err.span_suggestion_with_applicability(pub_span,
+                                                   "consider restricting its visibility",
+                                                   replacement,
+                                                   applicability);
             if exportable {
                 err.help("or consider exporting it for use by other crates");
             }
@@ -1321,21 +1316,31 @@ fn perform_lint(&self, cx: &LateContext, what: &str, id: ast::NodeId,
     }
 }
 
+
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub {
     fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
-        self.perform_lint(cx, "item", item.id, &item.vis, item.span, true);
+        let applicability = match item.node {
+            // suggestion span-manipulation is inadequate for `pub use
+            // module::{item}` (Issue #50455)
+            hir::ItemUse(..) => Applicability::MaybeIncorrect,
+            _ => Applicability::MachineApplicable,
+        };
+        self.perform_lint(cx, "item", item.id, &item.vis, item.span, true, applicability);
     }
 
     fn check_foreign_item(&mut self, cx: &LateContext, foreign_item: &hir::ForeignItem) {
-        self.perform_lint(cx, "item", foreign_item.id, &foreign_item.vis, foreign_item.span, true);
+        self.perform_lint(cx, "item", foreign_item.id, &foreign_item.vis,
+                          foreign_item.span, true, Applicability::MachineApplicable);
     }
 
     fn check_struct_field(&mut self, cx: &LateContext, field: &hir::StructField) {
-        self.perform_lint(cx, "field", field.id, &field.vis, field.span, false);
+        self.perform_lint(cx, "field", field.id, &field.vis, field.span, false,
+                          Applicability::MachineApplicable);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) {
-        self.perform_lint(cx, "item", impl_item.id, &impl_item.vis, impl_item.span, false);
+        self.perform_lint(cx, "item", impl_item.id, &impl_item.vis, impl_item.span, false,
+                          Applicability::MachineApplicable);
     }
 }
 
@@ -1543,6 +1548,9 @@ fn get_lints(&self) -> LintArray {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExternCrate {
     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+        if !cx.tcx.features().extern_absolute_paths {
+            return
+        }
         if let hir::ItemExternCrate(ref orig) =  it.node {
             if it.attrs.iter().any(|a| a.check_name("macro_use")) {
                 return
index 4403e1e3358b288bc174d42211a887d1cc112da4..39f550a4b459a7d0501d31e9d04845441af00cdb 100644 (file)
@@ -179,7 +179,7 @@ macro_rules! add_lint_group {
                     UNUSED_PARENS);
 
     add_lint_group!(sess,
-                    "rust_2018_migration",
+                    "rust_2018_idioms",
                     BARE_TRAIT_OBJECT,
                     UNREACHABLE_PUB,
                     UNNECESSARY_EXTERN_CRATE);
index dba2e918f6f3a10a3fb44618bfcd55d6909de825..c1e32c7c0226ed94898566f5e3423e9579563392 100644 (file)
@@ -1651,6 +1651,7 @@ pub fn LLVMRustConfigurePassManagerBuilder(PMB: PassManagerBuilderRef,
                                                MergeFunctions: bool,
                                                SLPVectorize: bool,
                                                LoopVectorize: bool,
+                                               PrepareForThinLTO: bool,
                                                PGOGenPath: *const c_char,
                                                PGOUsePath: *const c_char);
     pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef,
index 4d1f3e2b4300ab30a8ed6927cfe0029b6f78bca9..57b8824191f7b86ab50e1e02148e1eb35c129fcc 100644 (file)
@@ -1185,7 +1185,7 @@ fn new(origin: RegionVariableOrigin) -> Self {
 }
 
 impl fmt::Debug for Constraint {
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         write!(
             formatter,
             "({:?}: {:?} @ {:?}) due to {:?}",
index 42a1745addff75de36333f0f7047e59e2af05aea..1014299c708ddbcb4eb33d6ccda25cef9e0c71c6 100644 (file)
@@ -425,7 +425,7 @@ fn sanitize_projection(
             ProjectionElem::Subslice { from, to } => PlaceTy::Ty {
                 ty: match base_ty.sty {
                     ty::TyArray(inner, size) => {
-                        let size = size.val.unwrap_u64();
+                        let size = size.unwrap_usize(tcx);
                         let min_size = (from as u64) + (to as u64);
                         if let Some(rest_size) = size.checked_sub(min_size) {
                             tcx.mk_array(inner, rest_size)
index 648746b6e9047d9e21978a1940990ff77c0a9187..20e11abca9fa0cf9eff30aa1ac1c92453151d7df 100644 (file)
 use build::{BlockAnd, BlockAndExtension, Builder};
 use build::expr::category::{Category, RvalueFunc};
 use hair::*;
-use rustc::middle::const_val::ConstVal;
 use rustc::middle::region;
 use rustc::ty::{self, Ty, UpvarSubsts};
 use rustc::mir::*;
-use rustc::mir::interpret::{Value, PrimVal, EvalErrorKind};
+use rustc::mir::interpret::EvalErrorKind;
 use syntax_pos::Span;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
@@ -200,10 +199,10 @@ fn expr_as_rvalue(&mut self,
                             span: expr_span,
                             ty: this.hir.tcx().types.u32,
                             literal: Literal::Value {
-                                value: this.hir.tcx().mk_const(ty::Const {
-                                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
-                                    ty: this.hir.tcx().types.u32
-                                }),
+                                value: ty::Const::from_bits(
+                                    this.hir.tcx(),
+                                    0,
+                                    this.hir.tcx().types.u32),
                             },
                         }));
                         box AggregateKind::Generator(closure_id, substs, movability)
@@ -378,10 +377,7 @@ fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
         let bits = self.hir.integer_bit_width(ty);
         let n = (!0u128) >> (128 - bits);
         let literal = Literal::Value {
-            value: self.hir.tcx().mk_const(ty::Const {
-                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
-                ty
-            })
+            value: ty::Const::from_bits(self.hir.tcx(), n, ty)
         };
 
         self.literal_operand(span, ty, literal)
@@ -393,10 +389,7 @@ fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
         let bits = self.hir.integer_bit_width(ty);
         let n = 1 << (bits - 1);
         let literal = Literal::Value {
-            value: self.hir.tcx().mk_const(ty::Const {
-                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
-                ty
-            })
+            value: ty::Const::from_bits(self.hir.tcx(), n, ty)
         };
 
         self.literal_operand(span, ty, literal)
index d6ddfea1f19fb7dfd137360f0dcbd7a700f2b58b..913cb944835550be0e97234721aa643bcc5607ed 100644 (file)
@@ -122,12 +122,9 @@ pub fn add_cases_to_switch<'pat>(&mut self,
 
         match *match_pair.pattern.kind {
             PatternKind::Constant { value } => {
-                // if the places match, the type should match
-                assert_eq!(match_pair.pattern.ty, switch_ty);
-
                 indices.entry(value)
                        .or_insert_with(|| {
-                           options.push(value.val.to_raw_bits().expect("switching on int"));
+                           options.push(value.unwrap_bits(switch_ty));
                            options.len() - 1
                        });
                 true
index 6e10c2307c8e6879e29bf8b2e74ff7e6e1d6db07..6501dd00fe817493cf4fe50064ad697b7e0ea566 100644 (file)
@@ -13,9 +13,7 @@
 
 use build::Builder;
 
-use rustc::middle::const_val::ConstVal;
 use rustc::ty::{self, Ty};
-use rustc::mir::interpret::{Value, PrimVal};
 
 use rustc::mir::*;
 use syntax_pos::{Span, DUMMY_SP};
@@ -64,10 +62,7 @@ pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
             }
         }
         let literal = Literal::Value {
-            value: self.hir.tcx().mk_const(ty::Const {
-                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
-                ty
-            })
+            value: ty::Const::from_bits(self.hir.tcx(), 0, ty)
         };
 
         self.literal_operand(span, ty, literal)
index 76605a7aa04840a05aac63af6f619f3a5a5883b8..e3ff67703bd4ed2fd440dc5065b2d99316fa8b42 100644 (file)
@@ -14,8 +14,7 @@
 use hair::cx::block;
 use hair::cx::to_ref::ToRef;
 use rustc::hir::def::{Def, CtorKind};
-use rustc::middle::const_val::ConstVal;
-use rustc::mir::interpret::{GlobalId, Value, PrimVal};
+use rustc::mir::interpret::GlobalId;
 use rustc::ty::{self, AdtKind, Ty};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::cast::CastKind as TyCastKind;
@@ -522,7 +521,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 promoted: None
             };
             let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and(global_id)) {
-                Ok(cv) => cv.val.unwrap_u64(),
+                Ok(cv) => cv.unwrap_usize(cx.tcx),
                 Err(e) => {
                     e.report(cx.tcx, cx.tcx.def_span(def_id), "array length");
                     0
@@ -635,22 +634,17 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         span: expr.span,
                         kind: ExprKind::Literal {
                             literal: Literal::Value {
-                                value: cx.tcx().mk_const(ty::Const {
-                                    val,
-                                    ty,
-                                }),
+                                value: val,
                             },
                         },
                     }.to_ref();
-                    let offset = mk_const(
-                        ConstVal::Value(Value::ByVal(PrimVal::Bytes(offset as u128))),
-                    );
+                    let offset = mk_const(ty::Const::from_bits(cx.tcx, offset as u128, ty));
                     match did {
                         Some(did) => {
                             // in case we are offsetting from a computed discriminant
                             // and not the beginning of discriminants (which is always `0`)
                             let substs = Substs::identity_for_item(cx.tcx(), did);
-                            let lhs = mk_const(ConstVal::Unevaluated(did, substs));
+                            let lhs = mk_const(ty::Const::unevaluated(cx.tcx(), did, substs, ty));
                             let bin = ExprKind::Binary {
                                 op: BinOp::Add,
                                 lhs,
@@ -707,10 +701,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         span: expr.span,
         kind: ExprKind::Literal {
             literal: Literal::Value {
-                value: cx.tcx().mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
-                    ty
-                }),
+                value: ty::Const::zero_sized(cx.tcx(), ty),
             },
         },
     }
@@ -764,20 +755,20 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         Def::StructCtor(_, CtorKind::Fn) |
         Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal {
             literal: Literal::Value {
-                value: cx.tcx.mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
-                    ty: cx.tables().node_id_to_type(expr.hir_id)
-                }),
+                value: ty::Const::zero_sized(
+                    cx.tcx,
+                    cx.tables().node_id_to_type(expr.hir_id)),
             },
         },
 
         Def::Const(def_id) |
         Def::AssociatedConst(def_id) => ExprKind::Literal {
             literal: Literal::Value {
-                value: cx.tcx.mk_const(ty::Const {
-                    val: ConstVal::Unevaluated(def_id, substs),
-                    ty: cx.tables().node_id_to_type(expr.hir_id)
-                }),
+                value: ty::Const::unevaluated(
+                    cx.tcx,
+                    def_id,
+                    substs,
+                    cx.tables().node_id_to_type(expr.hir_id))
             },
         },
 
index 5890ea5c9d0c653cc8d186986dbb1c4dd303ade1..4765a82d85b6c1bae1eeb5272e7a4b3badb3131f 100644 (file)
@@ -16,7 +16,6 @@
 
 use hair::*;
 
-use rustc::middle::const_val::ConstVal;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::hir::map::blocks::FnLikeNode;
@@ -31,7 +30,6 @@
 use syntax::symbol::Symbol;
 use rustc::hir;
 use rustc_data_structures::sync::Lrc;
-use rustc::mir::interpret::{Value, PrimVal};
 use hair::pattern::parse_float;
 
 #[derive(Clone)]
@@ -117,10 +115,7 @@ pub fn usize_ty(&mut self) -> Ty<'tcx> {
 
     pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
         Literal::Value {
-            value: self.tcx.mk_const(ty::Const {
-                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))),
-                ty: self.tcx.types.usize
-            })
+            value: ty::Const::from_usize(self.tcx, value),
         }
     }
 
@@ -134,19 +129,13 @@ pub fn unit_ty(&mut self) -> Ty<'tcx> {
 
     pub fn true_literal(&mut self) -> Literal<'tcx> {
         Literal::Value {
-            value: self.tcx.mk_const(ty::Const {
-                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))),
-                ty: self.tcx.types.bool
-            })
+            value: ty::Const::from_bool(self.tcx, true),
         }
     }
 
     pub fn false_literal(&mut self) -> Literal<'tcx> {
         Literal::Value {
-            value: self.tcx.mk_const(ty::Const {
-                val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
-                ty: self.tcx.types.bool
-            })
+            value: ty::Const::from_bool(self.tcx, false),
         }
     }
 
@@ -162,6 +151,7 @@ pub fn integer_bit_width(
         layout::Integer::from_attr(self.tcx, ty).size().bits()
     }
 
+    // FIXME: Combine with rustc_mir::hair::pattern::lit_to_const
     pub fn const_eval_literal(
         &mut self,
         lit: &'tcx ast::LitKind,
@@ -171,7 +161,7 @@ pub fn const_eval_literal(
     ) -> Literal<'tcx> {
         trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
 
-        let parse_float = |num, fty| -> Value {
+        let parse_float = |num, fty| -> ConstValue<'tcx> {
             parse_float(num, fty, neg).unwrap_or_else(|_| {
                 // FIXME(#31407) this is only necessary because float parsing is buggy
                 self.tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)");
@@ -193,7 +183,7 @@ pub fn const_eval_literal(
                 let s = s.as_str();
                 let id = self.tcx.allocate_cached(s.as_bytes());
                 let ptr = MemoryPointer::new(id, 0);
-                Value::ByValPair(
+                ConstValue::ByValPair(
                     PrimVal::Ptr(ptr),
                     PrimVal::from_u128(s.len() as u128),
                 )
@@ -201,16 +191,16 @@ pub fn const_eval_literal(
             LitKind::ByteStr(ref data) => {
                 let id = self.tcx.allocate_cached(data);
                 let ptr = MemoryPointer::new(id, 0);
-                Value::ByVal(PrimVal::Ptr(ptr))
+                ConstValue::ByVal(PrimVal::Ptr(ptr))
             },
-            LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
+            LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)),
             LitKind::Int(n, _) if neg => {
                 let n = n as i128;
                 let n = n.overflowing_neg().0;
                 let n = clamp(n as u128);
-                Value::ByVal(PrimVal::Bytes(n))
+                ConstValue::ByVal(PrimVal::Bytes(n))
             },
-            LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(clamp(n))),
+            LitKind::Int(n, _) => ConstValue::ByVal(PrimVal::Bytes(clamp(n))),
             LitKind::Float(n, fty) => {
                 parse_float(n, fty)
             }
@@ -221,14 +211,11 @@ pub fn const_eval_literal(
                 };
                 parse_float(n, fty)
             }
-            LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
-            LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
+            LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b as u128)),
+            LitKind::Char(c) => ConstValue::ByVal(PrimVal::Bytes(c as u128)),
         };
         Literal::Value {
-            value: self.tcx.mk_const(ty::Const {
-                val: ConstVal::Value(lit),
-                ty,
-            }),
+            value: ty::Const::from_const_value(self.tcx, lit, ty)
         }
     }
 
@@ -258,11 +245,7 @@ pub fn trait_method(&mut self,
                 let method_ty = method_ty.subst(self.tcx, substs);
                 return (method_ty,
                         Literal::Value {
-                            value: self.tcx.mk_const(ty::Const {
-                                // ZST function type
-                                val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
-                                ty: method_ty
-                            }),
+                            value: ty::Const::zero_sized(self.tcx, method_ty)
                         });
             }
         }
index 1245f506955c133a4ebc2f51fc3d44b9850797bb..f930d47dc0bd37e3658f71c8a43bf35eabae4e73 100644 (file)
@@ -25,7 +25,6 @@
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 
 use rustc::mir::Field;
-use rustc::mir::interpret::{Value, PrimVal};
 use rustc::util::common::ErrorReported;
 
 use syntax_pos::{Span, DUMMY_SP};
@@ -180,37 +179,34 @@ fn lower_byte_str_pattern<'p>(&mut self, pat: &'p Pattern<'tcx>) -> Vec<&'p Patt
         self.byte_array_map.entry(pat).or_insert_with(|| {
             match pat.kind {
                 box PatternKind::Constant {
-                    value: &ty::Const { val: ConstVal::Value(b), ty }
+                    value: const_val
                 } => {
-                    match b {
-                        Value::ByVal(PrimVal::Ptr(ptr)) => {
-                            let is_array_ptr = ty
-                                .builtin_deref(true)
-                                .and_then(|t| t.ty.builtin_index())
-                                .map_or(false, |t| t == tcx.types.u8);
-                            assert!(is_array_ptr);
-                            let alloc = tcx
-                                .interpret_interner
-                                .get_alloc(ptr.alloc_id)
-                                .unwrap();
-                            assert_eq!(ptr.offset, 0);
-                            // FIXME: check length
-                            alloc.bytes.iter().map(|b| {
-                                &*pattern_arena.alloc(Pattern {
-                                    ty: tcx.types.u8,
-                                    span: pat.span,
-                                    kind: box PatternKind::Constant {
-                                        value: tcx.mk_const(ty::Const {
-                                            val: ConstVal::Value(Value::ByVal(
-                                                PrimVal::Bytes(*b as u128),
-                                            )),
-                                            ty: tcx.types.u8
-                                        })
-                                    }
-                                })
-                            }).collect()
-                        },
-                        _ => bug!("not a byte str: {:?}", b),
+                    if let Some(ptr) = const_val.to_ptr() {
+                        let is_array_ptr = const_val.ty
+                            .builtin_deref(true)
+                            .and_then(|t| t.ty.builtin_index())
+                            .map_or(false, |t| t == tcx.types.u8);
+                        assert!(is_array_ptr);
+                        let alloc = tcx
+                            .interpret_interner
+                            .get_alloc(ptr.alloc_id)
+                            .unwrap();
+                        assert_eq!(ptr.offset, 0);
+                        // FIXME: check length
+                        alloc.bytes.iter().map(|b| {
+                            &*pattern_arena.alloc(Pattern {
+                                ty: tcx.types.u8,
+                                span: pat.span,
+                                kind: box PatternKind::Constant {
+                                    value: ty::Const::from_bits(
+                                        tcx,
+                                        *b as u128,
+                                        tcx.types.u8)
+                                }
+                            })
+                        }).collect()
+                    } else {
+                        bug!("not a byte str: {:?}", const_val)
                     }
                 }
                 _ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat)
@@ -439,14 +435,11 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
     match pcx.ty.sty {
         ty::TyBool => {
             [true, false].iter().map(|&b| {
-                ConstantValue(cx.tcx.mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))),
-                    ty: cx.tcx.types.bool
-                }))
+                ConstantValue(ty::Const::from_bool(cx.tcx, b))
             }).collect()
         }
-        ty::TyArray(ref sub_ty, len) if len.val.to_raw_bits().is_some() => {
-            let len = len.val.unwrap_u64();
+        ty::TyArray(ref sub_ty, len) if len.assert_usize(cx.tcx).is_some() => {
+            let len = len.unwrap_usize(cx.tcx);
             if len != 0 && cx.is_uninhabited(sub_ty) {
                 vec![]
             } else {
@@ -554,21 +547,23 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
     for row in patterns {
         match *row.kind {
             PatternKind::Constant {
-                value: &ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))),
-                    ty,
+                value: const_val @ &ty::Const {
+                    val: ConstVal::Value(..),
+                    ..
                 }
             } => {
-                let is_array_ptr = ty
-                    .builtin_deref(true)
-                    .and_then(|t| t.ty.builtin_index())
-                    .map_or(false, |t| t == cx.tcx.types.u8);
-                if is_array_ptr {
-                    let alloc = cx.tcx
-                        .interpret_interner
-                        .get_alloc(ptr.alloc_id)
-                        .unwrap();
-                    max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
+                if let Some(ptr) = const_val.to_ptr() {
+                    let is_array_ptr = const_val.ty
+                        .builtin_deref(true)
+                        .and_then(|t| t.ty.builtin_index())
+                        .map_or(false, |t| t == cx.tcx.types.u8);
+                    if is_array_ptr {
+                        let alloc = cx.tcx
+                            .interpret_interner
+                            .get_alloc(ptr.alloc_id)
+                            .unwrap();
+                        max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
+                    }
                 }
             }
             PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
@@ -836,7 +831,7 @@ 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<'tcx>(_cx: &mut MatchCheckCtxt,
+fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt,
                           pat: &Pattern<'tcx>,
                           pcx: PatternContext)
                           -> Option<Vec<Constructor<'tcx>>>
@@ -854,7 +849,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
             Some(vec![ConstantRange(lo, hi, end)]),
         PatternKind::Array { .. } => match pcx.ty.sty {
             ty::TyArray(_, length) => Some(vec![
-                Slice(length.val.unwrap_u64())
+                Slice(length.unwrap_usize(cx.tcx))
             ]),
             _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
         },
@@ -934,27 +929,31 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
     }
 }
 
-fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
-                                    ctor: &Constructor,
-                                    prefix: &[Pattern],
-                                    slice: &Option<Pattern>,
-                                    suffix: &[Pattern])
-                                    -> Result<bool, ErrorReported> {
+fn slice_pat_covered_by_constructor<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, '_>,
+    _span: Span,
+    ctor: &Constructor,
+    prefix: &[Pattern<'tcx>],
+    slice: &Option<Pattern<'tcx>>,
+    suffix: &[Pattern<'tcx>]
+) -> Result<bool, ErrorReported> {
     let data: &[u8] = match *ctor {
-        ConstantValue(&ty::Const { val: ConstVal::Value(
-            Value::ByVal(PrimVal::Ptr(ptr))
-        ), ty }) => {
-            let is_array_ptr = ty
-                .builtin_deref(true)
-                .and_then(|t| t.ty.builtin_index())
-                .map_or(false, |t| t == tcx.types.u8);
-            assert!(is_array_ptr);
-            tcx
-                .interpret_interner
-                .get_alloc(ptr.alloc_id)
-                .unwrap()
-                .bytes
-                .as_ref()
+        ConstantValue(const_val @ &ty::Const { val: ConstVal::Value(..), .. }) => {
+            if let Some(ptr) = const_val.to_ptr() {
+                let is_array_ptr = const_val.ty
+                    .builtin_deref(true)
+                    .and_then(|t| t.ty.builtin_index())
+                    .map_or(false, |t| t == tcx.types.u8);
+                assert!(is_array_ptr);
+                tcx
+                    .interpret_interner
+                    .get_alloc(ptr.alloc_id)
+                    .unwrap()
+                    .bytes
+                    .as_ref()
+            } else {
+                bug!()
+            }
         }
         _ => bug!()
     };
@@ -969,15 +968,13 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
             data[data.len()-suffix.len()..].iter().zip(suffix))
     {
         match pat.kind {
-            box PatternKind::Constant { value } => match value.val {
-                ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
-                    assert_eq!(b as u8 as u128, b);
-                    if b as u8 != *ch {
-                        return Ok(false);
-                    }
+            box PatternKind::Constant { value } => {
+                let b = value.unwrap_bits(pat.ty);
+                assert_eq!(b as u8 as u128, b);
+                if b as u8 != *ch {
+                    return Ok(false);
                 }
-                _ => span_bug!(pat.span, "bad const u8 {:?}", value)
-            },
+            }
             _ => {}
         }
     }
@@ -987,8 +984,8 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
 
 fn constructor_covered_by_range<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    ctor: &Constructor,
-    from: &ConstVal, to: &ConstVal,
+    ctor: &Constructor<'tcx>,
+    from: &'tcx ty::Const<'tcx>, to: &'tcx ty::Const<'tcx>,
     end: RangeEnd,
     ty: Ty<'tcx>,
 ) -> Result<bool, ErrorReported> {
@@ -1006,22 +1003,22 @@ macro_rules! some_or_ok {
     }
     match *ctor {
         ConstantValue(value) => {
-            let to = some_or_ok!(cmp_to(&value.val));
+            let to = some_or_ok!(cmp_to(value));
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Included && to == Ordering::Equal);
-            Ok(some_or_ok!(cmp_from(&value.val)) && end)
+            Ok(some_or_ok!(cmp_from(value)) && end)
         },
         ConstantRange(from, to, RangeEnd::Included) => {
-            let to = some_or_ok!(cmp_to(&to.val));
+            let to = some_or_ok!(cmp_to(to));
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Included && to == Ordering::Equal);
-            Ok(some_or_ok!(cmp_from(&from.val)) && end)
+            Ok(some_or_ok!(cmp_from(from)) && end)
         },
         ConstantRange(from, to, RangeEnd::Excluded) => {
-            let to = some_or_ok!(cmp_to(&to.val));
+            let to = some_or_ok!(cmp_to(to));
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Excluded && to == Ordering::Equal);
-            Ok(some_or_ok!(cmp_from(&from.val)) && end)
+            Ok(some_or_ok!(cmp_from(from)) && end)
         }
         Single => Ok(true),
         _ => bug!(),
@@ -1083,8 +1080,8 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
 
         PatternKind::Constant { value } => {
             match *constructor {
-                Slice(..) => match value.val {
-                    ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => {
+                Slice(..) => {
+                    if let Some(ptr) = value.to_ptr() {
                         let is_array_ptr = value.ty
                             .builtin_deref(true)
                             .and_then(|t| t.ty.builtin_index())
@@ -1101,14 +1098,15 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
                         } else {
                             None
                         }
-                    }
-                    _ => span_bug!(pat.span,
+                    } else {
+                        span_bug!(pat.span,
                         "unexpected const-val {:?} with ctor {:?}", value, constructor)
+                    }
                 },
                 _ => {
                     match constructor_covered_by_range(
                         cx.tcx,
-                        constructor, &value.val, &value.val, RangeEnd::Included,
+                        constructor, value, value, RangeEnd::Included,
                         value.ty,
                             ) {
                         Ok(true) => Some(vec![]),
@@ -1122,7 +1120,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
         PatternKind::Range { lo, hi, ref end } => {
             match constructor_covered_by_range(
                 cx.tcx,
-                constructor, &lo.val, &hi.val, end.clone(), lo.ty,
+                constructor, lo, hi, end.clone(), lo.ty,
             ) {
                 Ok(true) => Some(vec![]),
                 Ok(false) => None,
index 2585447fa0a04f6cdecfe14bb2777a7a04fb4d31..749e574ff7ad41ca5bfa7420f2ded0f12825491f 100644 (file)
@@ -19,8 +19,8 @@
 use interpret::{const_val_field, const_variant_index, self};
 
 use rustc::middle::const_val::ConstVal;
-use rustc::mir::{Field, BorrowKind, Mutability};
-use rustc::mir::interpret::{GlobalId, Value, PrimVal};
+use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
+use rustc::mir::interpret::{PrimVal, GlobalId, ConstValue};
 use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
 use rustc::ty::subst::{Substs, Kind};
 use rustc::hir::{self, PatKind, RangeEnd};
@@ -124,24 +124,11 @@ pub enum PatternKind<'tcx> {
 
 fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result {
     match value.val {
-        ConstVal::Value(v) => print_miri_value(v, value.ty, f),
+        ConstVal::Value(..) => fmt_const_val(f, value),
         ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value)
     }
 }
 
-fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result {
-    use rustc::ty::TypeVariants::*;
-    match (value, &ty.sty) {
-        (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"),
-        (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"),
-        (Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n),
-        (Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128),
-        (Value::ByVal(PrimVal::Bytes(n)), &TyChar) =>
-            write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()),
-        _ => bug!("{:?}: {} not printable in a pattern", value, ty),
-    }
-}
-
 impl<'tcx> fmt::Display for Pattern<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self.kind {
@@ -372,7 +359,7 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
                     (PatternKind::Constant { value: lo },
                      PatternKind::Constant { value: hi }) => {
                         use std::cmp::Ordering;
-                        match (end, compare_const_vals(self.tcx, &lo.val, &hi.val, ty).unwrap()) {
+                        match (end, compare_const_vals(self.tcx, lo, hi, ty).unwrap()) {
                             (RangeEnd::Excluded, Ordering::Less) =>
                                 PatternKind::Range { lo, hi, end },
                             (RangeEnd::Excluded, _) => {
@@ -616,7 +603,7 @@ fn slice_or_array_pattern(
 
             ty::TyArray(_, len) => {
                 // fixed-length array
-                let len = len.val.unwrap_u64();
+                let len = len.unwrap_usize(self.tcx);
                 assert!(len >= prefix.len() as u64 + suffix.len() as u64);
                 PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
             }
@@ -740,8 +727,7 @@ fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
                             self.tables.local_id_root.expect("literal outside any scope"),
                             self.substs,
                         );
-                        let cv = self.tcx.mk_const(ty::Const { val, ty });
-                        *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
+                        *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
                     },
                     Err(()) => {
                         self.errors.push(PatternError::FloatBug);
@@ -762,8 +748,7 @@ fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
                             self.tables.local_id_root.expect("literal outside any scope"),
                             self.substs,
                         );
-                        let cv = self.tcx.mk_const(ty::Const { val, ty });
-                        *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
+                        *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
                     },
                     Err(()) => {
                         self.errors.push(PatternError::FloatBug);
@@ -866,7 +851,7 @@ fn const_to_pat(
             }
             ty::TyArray(_, n) => {
                 PatternKind::Array {
-                    prefix: (0..n.val.unwrap_u64())
+                    prefix: (0..n.unwrap_usize(self.tcx))
                         .map(|i| adt_subpattern(i as usize, None))
                         .collect(),
                     slice: None,
@@ -1049,45 +1034,48 @@ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
 
 pub fn compare_const_vals<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    a: &ConstVal,
-    b: &ConstVal,
+    a: &'tcx ty::Const<'tcx>,
+    b: &'tcx ty::Const<'tcx>,
     ty: Ty<'tcx>,
 ) -> Option<Ordering> {
     trace!("compare_const_vals: {:?}, {:?}", a, b);
-    use rustc::mir::interpret::{Value, PrimVal};
-    match (a, b) {
-        (&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))),
-         &ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => {
-            use ::rustc_apfloat::Float;
-            match ty.sty {
-                ty::TyFloat(ast::FloatTy::F32) => {
-                    let l = ::rustc_apfloat::ieee::Single::from_bits(a);
-                    let r = ::rustc_apfloat::ieee::Single::from_bits(b);
-                    l.partial_cmp(&r)
-                },
-                ty::TyFloat(ast::FloatTy::F64) => {
-                    let l = ::rustc_apfloat::ieee::Double::from_bits(a);
-                    let r = ::rustc_apfloat::ieee::Double::from_bits(b);
-                    l.partial_cmp(&r)
-                },
-                ty::TyInt(_) => {
-                    let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt");
-                    let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt");
-                    Some((a as i128).cmp(&(b as i128)))
-                },
-                _ => Some(a.cmp(&b)),
-            }
-        },
-        _ if a == b => Some(Ordering::Equal),
-        _ => None,
+    // FIXME: This should use assert_bits(ty) instead of use_bits
+    // but triggers possibly bugs due to mismatching of arrays and slices
+    if let (Some(a), Some(b)) = (a.to_bits(ty), b.to_bits(ty)) {
+        use ::rustc_apfloat::Float;
+        match ty.sty {
+            ty::TyFloat(ast::FloatTy::F32) => {
+                let l = ::rustc_apfloat::ieee::Single::from_bits(a);
+                let r = ::rustc_apfloat::ieee::Single::from_bits(b);
+                l.partial_cmp(&r)
+            },
+            ty::TyFloat(ast::FloatTy::F64) => {
+                let l = ::rustc_apfloat::ieee::Double::from_bits(a);
+                let r = ::rustc_apfloat::ieee::Double::from_bits(b);
+                l.partial_cmp(&r)
+            },
+            ty::TyInt(_) => {
+                let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt");
+                let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt");
+                Some((a as i128).cmp(&(b as i128)))
+            },
+            _ => Some(a.cmp(&b)),
+        }
+    } else {
+        if a == b {
+            Some(Ordering::Equal)
+        } else {
+            None
+        }
     }
 }
 
+// FIXME: Combine with rustc_mir::hair::cx::const_eval_literal
 fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           ty: Ty<'tcx>,
                           neg: bool)
-                          -> Result<ConstVal<'tcx>, ()> {
+                          -> Result<&'tcx ty::Const<'tcx>, ()> {
     use syntax::ast::*;
 
     use rustc::mir::interpret::*;
@@ -1096,7 +1084,7 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
             let s = s.as_str();
             let id = tcx.allocate_cached(s.as_bytes());
             let ptr = MemoryPointer::new(id, 0);
-            Value::ByValPair(
+            ConstValue::ByValPair(
                 PrimVal::Ptr(ptr),
                 PrimVal::from_u128(s.len() as u128),
             )
@@ -1104,9 +1092,9 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
         LitKind::ByteStr(ref data) => {
             let id = tcx.allocate_cached(data);
             let ptr = MemoryPointer::new(id, 0);
-            Value::ByVal(PrimVal::Ptr(ptr))
+            ConstValue::ByVal(PrimVal::Ptr(ptr))
         },
-        LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
+        LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)),
         LitKind::Int(n, _) => {
             enum Int {
                 Signed(IntTy),
@@ -1119,31 +1107,28 @@ enum Int {
                 ty::TyUint(other) => Int::Unsigned(other),
                 _ => bug!(),
             };
+            // This converts from LitKind::Int (which is sign extended) to
+            // PrimVal::Bytes (which is zero extended)
             let n = match ty {
                 // FIXME(oli-obk): are these casts correct?
                 Int::Signed(IntTy::I8) if neg =>
-                    (n as i128 as i8).overflowing_neg().0 as i128 as u128,
+                    (n as i8).overflowing_neg().0 as u8 as u128,
                 Int::Signed(IntTy::I16) if neg =>
-                    (n as i128 as i16).overflowing_neg().0 as i128 as u128,
+                    (n as i16).overflowing_neg().0 as u16 as u128,
                 Int::Signed(IntTy::I32) if neg =>
-                    (n as i128 as i32).overflowing_neg().0 as i128 as u128,
+                    (n as i32).overflowing_neg().0 as u32 as u128,
                 Int::Signed(IntTy::I64) if neg =>
-                    (n as i128 as i64).overflowing_neg().0 as i128 as u128,
+                    (n as i64).overflowing_neg().0 as u64 as u128,
                 Int::Signed(IntTy::I128) if neg =>
                     (n as i128).overflowing_neg().0 as u128,
-                Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128,
-                Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128,
-                Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128,
-                Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128,
-                Int::Signed(IntTy::I128) => n,
-                Int::Unsigned(UintTy::U8) => n as u8 as u128,
-                Int::Unsigned(UintTy::U16) => n as u16 as u128,
-                Int::Unsigned(UintTy::U32) => n as u32 as u128,
-                Int::Unsigned(UintTy::U64) => n as u64 as u128,
-                Int::Unsigned(UintTy::U128) => n,
+                Int::Signed(IntTy::I8) | Int::Unsigned(UintTy::U8) => n as u8 as u128,
+                Int::Signed(IntTy::I16) | Int::Unsigned(UintTy::U16) => n as u16 as u128,
+                Int::Signed(IntTy::I32) | Int::Unsigned(UintTy::U32) => n as u32 as u128,
+                Int::Signed(IntTy::I64) | Int::Unsigned(UintTy::U64) => n as u64 as u128,
+                Int::Signed(IntTy::I128)| Int::Unsigned(UintTy::U128) => n,
                 _ => bug!(),
             };
-            Value::ByVal(PrimVal::Bytes(n))
+            ConstValue::ByVal(PrimVal::Bytes(n))
         },
         LitKind::Float(n, fty) => {
             parse_float(n, fty, neg)?
@@ -1155,17 +1140,17 @@ enum Int {
             };
             parse_float(n, fty, neg)?
         }
-        LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
-        LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
+        LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b as u128)),
+        LitKind::Char(c) => ConstValue::ByVal(PrimVal::Bytes(c as u128)),
     };
-    Ok(ConstVal::Value(lit))
+    Ok(ty::Const::from_const_value(tcx, lit, ty))
 }
 
-pub fn parse_float(
+pub fn parse_float<'tcx>(
     num: Symbol,
     fty: ast::FloatTy,
     neg: bool,
-) -> Result<Value, ()> {
+) -> Result<ConstValue<'tcx>, ()> {
     let num = num.as_str();
     use rustc_apfloat::ieee::{Single, Double};
     use rustc_apfloat::Float;
@@ -1192,5 +1177,5 @@ pub fn parse_float(
         }
     };
 
-    Ok(Value::ByVal(PrimVal::Bytes(bits)))
+    Ok(ConstValue::ByVal(PrimVal::Bytes(bits)))
 }
index dff9fa271aba52f99b6b03c7ad54dbc03889bbd0..6bf965aaf44630079178dd4536be7f565a31782c 100644 (file)
@@ -1,5 +1,5 @@
 use rustc::hir;
-use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
+use rustc::middle::const_val::{ConstEvalErr, ErrKind};
 use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError};
 use rustc::mir;
 use rustc::ty::{self, TyCtxt, Ty, Instance};
@@ -8,9 +8,13 @@
 
 use syntax::ast::Mutability;
 use syntax::codemap::Span;
+use syntax::codemap::DUMMY_SP;
 
-use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal, AllocId};
-use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory};
+use rustc::mir::interpret::{
+    EvalResult, EvalError, EvalErrorKind, GlobalId,
+    Value, Pointer, PrimVal, AllocId, Allocation, ConstValue,
+};
+use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory, MemoryKind};
 
 use std::fmt;
 use std::error::Error;
@@ -57,19 +61,21 @@ pub fn mk_eval_cx<'a, 'tcx>(
 }
 
 pub fn eval_promoted<'a, 'mir, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
     cid: GlobalId<'tcx>,
     mir: &'mir mir::Mir<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
 ) -> Option<(Value, Pointer, Ty<'tcx>)> {
-    let (res, ecx) = eval_body_and_ecx(tcx, cid, Some(mir), param_env);
-    match res {
-        Ok(val) => Some(val),
-        Err(mut err) => {
-            ecx.report(&mut err, false, None);
-            None
+    ecx.with_fresh_body(|ecx| {
+        let res = eval_body_using_ecx(ecx, cid, Some(mir), param_env);
+        match res {
+            Ok(val) => Some(val),
+            Err(mut err) => {
+                ecx.report(&mut err, false, None);
+                None
+            }
         }
-    }
+    })
 }
 
 pub fn eval_body<'a, 'tcx>(
@@ -87,19 +93,76 @@ pub fn eval_body<'a, 'tcx>(
     }
 }
 
+pub fn value_to_const_value<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    val: Value,
+    ty: Ty<'tcx>,
+) -> &'tcx ty::Const<'tcx> {
+    let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
+
+    if layout.is_zst() {
+        return ty::Const::from_const_value(
+            tcx,
+            ConstValue::ByVal(PrimVal::Undef),
+            ty);
+    }
+
+    let val = match layout.abi {
+        layout::Abi::Scalar(..) => {
+            if let Value::ByVal(val) = val {
+                ConstValue::ByVal(val)
+            } else {
+                bug!("expected ByVal value, got {:?}", val);
+            }
+        }
+        layout::Abi::ScalarPair(..) => {
+            if let Value::ByValPair(a, b) = val {
+                ConstValue::ByValPair(a, b)
+            } else {
+                bug!("expected ByValPair value, got {:?}", val);
+            }
+        }
+        _ => {
+            if let Value::ByRef(ptr, align) = val {
+                let ptr = ptr.primval.to_ptr().unwrap();
+                assert_eq!(ptr.offset, 0);
+                let alloc = tcx.interpret_interner
+                               .get_alloc(ptr.alloc_id)
+                               .expect("miri allocation never successfully created");
+                assert_eq!(align, alloc.align);
+                ConstValue::ByRef(alloc)
+            } else {
+                bug!("expected ByRef value, got {:?}", val);
+            }
+        },
+    };
+    ty::Const::from_const_value(tcx, val, ty)
+}
+
 fn eval_body_and_ecx<'a, 'mir, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     cid: GlobalId<'tcx>,
     mir: Option<&'mir mir::Mir<'tcx>>,
     param_env: ty::ParamEnv<'tcx>,
 ) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) {
-    debug!("eval_body: {:?}, {:?}", cid, param_env);
+    debug!("eval_body_and_ecx: {:?}, {:?}", cid, param_env);
     // we start out with the best span we have
     // and try improving it down the road when more information is available
     let span = tcx.def_span(cid.instance.def_id());
-    let mut span = mir.map(|mir| mir.span).unwrap_or(span);
+    let span = mir.map(|mir| mir.span).unwrap_or(span);
     let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
-    let res = (|| {
+    let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env);
+    (r, ecx)
+}
+
+fn eval_body_using_ecx<'a, 'mir, 'tcx>(
+    ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
+    cid: GlobalId<'tcx>,
+    mir: Option<&'mir mir::Mir<'tcx>>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> {
+    debug!("eval_body: {:?}, {:?}", cid, param_env);
+    let tcx = ecx.tcx.tcx;
         let mut mir = match mir {
             Some(mir) => mir,
             None => ecx.load_mir(cid.instance.def)?,
@@ -107,7 +170,6 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>(
         if let Some(index) = cid.promoted {
             mir = &mir.promoted[index];
         }
-        span = mir.span;
         let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
         assert!(!layout.is_unsized());
         let ptr = ecx.memory.allocate(
@@ -139,14 +201,11 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>(
         let ptr = ptr.into();
         // always try to read the value and report errors
         let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? {
-            // if it's a constant (so it needs no address, directly compute its value)
-            Some(val) if tcx.is_static(cid.instance.def_id()).is_none() => val,
+            Some(val) => val,
             // point at the allocation
             _ => Value::ByRef(ptr, layout.align),
         };
         Ok((value, ptr, layout.ty))
-    })();
-    (res, ecx)
 }
 
 pub struct CompileTimeEvaluator;
@@ -357,14 +416,16 @@ pub fn const_val_field<'a, 'tcx>(
     instance: ty::Instance<'tcx>,
     variant: Option<usize>,
     field: mir::Field,
-    value: Value,
+    value: ConstValue<'tcx>,
     ty: Ty<'tcx>,
 ) -> ::rustc::middle::const_val::EvalResult<'tcx> {
     trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
     let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
     let result = (|| {
+        let value = ecx.const_value_to_value(value, ty)?;
         let (mut field, ty) = match value {
-            Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
+            Value::ByValPair(..) | Value::ByVal(_) => 
+                ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
             Value::ByRef(ptr, align) => {
                 let place = Place::Ptr {
                     ptr,
@@ -385,10 +446,7 @@ pub fn const_val_field<'a, 'tcx>(
         Ok((field, ty))
     })();
     match result {
-        Ok((field, ty)) => Ok(tcx.mk_const(ty::Const {
-            val: ConstVal::Value(field),
-            ty,
-        })),
+        Ok((field, ty)) => Ok(value_to_const_value(tcx, field, ty)),
         Err(err) => {
             let (trace, span) = ecx.generate_stacktrace(None);
             let err = ErrKind::Miri(err, trace);
@@ -404,15 +462,15 @@ pub fn const_variant_index<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     instance: ty::Instance<'tcx>,
-    value: Value,
+    val: ConstValue<'tcx>,
     ty: Ty<'tcx>,
 ) -> EvalResult<'tcx, usize> {
-    trace!("const_variant_index: {:?}, {:?}, {:?}", instance, value, ty);
+    trace!("const_variant_index: {:?}, {:?}, {:?}", instance, val, ty);
     let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
+    let value = ecx.const_value_to_value(val, ty)?;
     let (ptr, align) = match value {
         Value::ByValPair(..) | Value::ByVal(_) => {
             let layout = ecx.layout_of(ty)?;
-            use super::MemoryKind;
             let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
             let ptr: Pointer = ptr.into();
             ecx.write_value_to_ptr(value, ptr, layout.align, ty)?;
@@ -424,6 +482,30 @@ pub fn const_variant_index<'a, 'tcx>(
     ecx.read_discriminant_as_variant_index(place, ty)
 }
 
+pub fn const_value_to_allocation_provider<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    (val, ty): (ConstValue<'tcx>, Ty<'tcx>),
+) -> &'tcx Allocation {
+    match val {
+        ConstValue::ByRef(alloc) => return alloc,
+        _ => ()
+    }
+    let result = || -> EvalResult<'tcx, &'tcx Allocation> {
+        let mut ecx = EvalContext::new(
+            tcx.at(DUMMY_SP),
+            ty::ParamEnv::reveal_all(),
+            CompileTimeEvaluator,
+            ());
+        let value = ecx.const_value_to_value(val, ty)?;
+        let layout = ecx.layout_of(ty)?;
+        let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
+        ecx.write_value_to_ptr(value, ptr.into(), layout.align, ty)?;
+        let alloc = ecx.memory.get(ptr.alloc_id)?;
+        Ok(tcx.intern_const_alloc(alloc.clone()))
+    };
+    result().expect("unable to convert ConstVal to Allocation")
+}
+
 pub fn const_eval_provider<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
@@ -432,17 +514,6 @@ pub fn const_eval_provider<'a, 'tcx>(
     let cid = key.value;
     let def_id = cid.instance.def.def_id();
 
-    if tcx.is_foreign_item(def_id) {
-        let id = tcx.interpret_interner.cache_static(def_id);
-        let ty = tcx.type_of(def_id);
-        let layout = tcx.layout_of(key.param_env.and(ty)).unwrap();
-        let ptr = MemoryPointer::new(id, 0);
-        return Ok(tcx.mk_const(ty::Const {
-            val: ConstVal::Value(Value::ByRef(ptr.into(), layout.align)),
-            ty,
-        }))
-    }
-
     if let Some(id) = tcx.hir.as_local_node_id(def_id) {
         let tables = tcx.typeck_tables_of(def_id);
         let span = tcx.def_span(def_id);
@@ -469,11 +540,8 @@ pub fn const_eval_provider<'a, 'tcx>(
     };
 
     let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
-    res.map(|(miri_value, _, miri_ty)| {
-        tcx.mk_const(ty::Const {
-            val: ConstVal::Value(miri_value),
-            ty: miri_ty,
-        })
+    res.map(|(val, _, miri_ty)| {
+        value_to_const_value(tcx, val, miri_ty)
     }).map_err(|mut err| {
         if tcx.is_static(def_id).is_some() {
             ecx.report(&mut err, true, None);
index 3d670acf98cb2d3f20993f9fc7f8f96268613625..03137619edaf48d72a0780b073a6446cc575ec53 100644 (file)
@@ -15,7 +15,7 @@
 use syntax::ast::Mutability;
 use rustc::mir::interpret::{
     GlobalId, Value, Pointer, PrimVal, PrimValKind,
-    EvalError, EvalResult, EvalErrorKind, MemoryPointer,
+    EvalError, EvalResult, EvalErrorKind, MemoryPointer, ConstValue,
 };
 use std::mem;
 
@@ -116,15 +116,6 @@ pub struct ValTy<'tcx> {
     pub ty: Ty<'tcx>,
 }
 
-impl<'tcx> ValTy<'tcx> {
-    pub fn from(val: &ty::Const<'tcx>) -> Option<Self> {
-        match val.val {
-            ConstVal::Value(value) => Some(ValTy { value, ty: val.ty }),
-            ConstVal::Unevaluated { .. } => None,
-        }
-    }
-}
-
 impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
     type Target = Value;
     fn deref(&self) -> &Value {
@@ -183,6 +174,8 @@ fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
     }
 }
 
+const MAX_TERMINATORS: usize = 1_000_000;
+
 impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     pub fn new(
         tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
@@ -197,10 +190,19 @@ pub fn new(
             memory: Memory::new(tcx, memory_data),
             stack: Vec::new(),
             stack_limit: tcx.sess.const_eval_stack_frame_limit,
-            terminators_remaining: 1_000_000,
+            terminators_remaining: MAX_TERMINATORS,
         }
     }
 
+    pub(crate) fn with_fresh_body<F: FnOnce(&mut Self) -> R, R>(&mut self, f: F) -> R {
+        let stack = mem::replace(&mut self.stack, Vec::new());
+        let terminators_remaining = mem::replace(&mut self.terminators_remaining, MAX_TERMINATORS);
+        let r = f(self);
+        self.stack = stack;
+        self.terminators_remaining = terminators_remaining;
+        r
+    }
+
     pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, MemoryPointer> {
         let layout = self.layout_of(ty)?;
         assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
@@ -235,7 +237,27 @@ pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
         ))
     }
 
-    pub(super) fn const_to_value(&self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
+    pub fn const_value_to_value(
+        &mut self,
+        val: ConstValue<'tcx>,
+        _ty: Ty<'tcx>,
+    ) -> EvalResult<'tcx, Value> {
+        match val {
+            ConstValue::ByRef(alloc) => {
+                // FIXME: Allocate new AllocId for all constants inside
+                let id = self.memory.allocate_value(alloc.clone(), Some(MemoryKind::Stack))?;
+                Ok(Value::ByRef(MemoryPointer::new(id, 0).into(), alloc.align))
+            },
+            ConstValue::ByValPair(a, b) => Ok(Value::ByValPair(a, b)),
+            ConstValue::ByVal(val) => Ok(Value::ByVal(val)),
+        }
+    }
+
+    pub(super) fn const_to_value(
+        &mut self,
+        const_val: &ConstVal<'tcx>,
+        ty: Ty<'tcx>
+    ) -> EvalResult<'tcx, Value> {
         match *const_val {
             ConstVal::Unevaluated(def_id, substs) => {
                 let instance = self.resolve(def_id, substs)?;
@@ -244,7 +266,7 @@ pub(super) fn const_to_value(&self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) ->
                     promoted: None,
                 }, ty)
             }
-            ConstVal::Value(val) => Ok(val),
+            ConstVal::Value(val) => self.const_value_to_value(val, ty)
         }
     }
 
@@ -568,7 +590,7 @@ pub(super) fn eval_rvalue_into_place(
 
             Repeat(ref operand, _) => {
                 let (elem_ty, length) = match dest_ty.sty {
-                    ty::TyArray(elem_ty, n) => (elem_ty, n.val.unwrap_u64()),
+                    ty::TyArray(elem_ty, n) => (elem_ty, n.unwrap_usize(self.tcx.tcx)),
                     _ => {
                         bug!(
                             "tried to assign array-repeat to non-array type {:?}",
@@ -592,7 +614,7 @@ pub(super) fn eval_rvalue_into_place(
                 // FIXME(CTFE): don't allow computing the length of arrays in const eval
                 let src = self.eval_place(place)?;
                 let ty = self.place_ty(place);
-                let (_, len) = src.elem_ty_and_len(ty);
+                let (_, len) = src.elem_ty_and_len(ty, self.tcx.tcx);
                 self.write_primval(
                     dest,
                     PrimVal::from_u128(len as u128),
@@ -822,8 +844,9 @@ pub fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, ValT
                     Literal::Value { ref value } => self.const_to_value(&value.val, ty)?,
 
                     Literal::Promoted { index } => {
+                        let instance = self.frame().instance;
                         self.read_global_as_value(GlobalId {
-                            instance: self.frame().instance,
+                            instance,
                             promoted: Some(index),
                         }, ty)?
                     }
@@ -997,7 +1020,7 @@ pub fn write_discriminant_value(
         Ok(())
     }
 
-    pub fn read_global_as_value(&self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
+    pub fn read_global_as_value(&mut self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
         if self.tcx.is_static(gid.instance.def_id()).is_some() {
             let alloc_id = self
                 .tcx
@@ -1341,92 +1364,84 @@ pub(crate) fn read_ptr(
         }
     }
 
-    pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
-        use syntax::ast::FloatTy;
-
-        let layout = self.layout_of(ty)?;
-        self.memory.check_align(ptr, ptr_align)?;
-
-        if layout.size.bytes() == 0 {
-            return Ok(Some(Value::ByVal(PrimVal::Undef)));
-        }
-
-        let ptr = ptr.to_ptr()?;
-        let val = match ty.sty {
+    pub fn validate_ptr_target(
+        &self,
+        ptr: MemoryPointer,
+        ptr_align: Align,
+        ty: Ty<'tcx>
+    ) -> EvalResult<'tcx> {
+        match ty.sty {
             ty::TyBool => {
                 let val = self.memory.read_primval(ptr, ptr_align, 1)?;
-                let val = match val {
-                    PrimVal::Bytes(0) => false,
-                    PrimVal::Bytes(1) => true,
+                match val {
+                    PrimVal::Bytes(0) | PrimVal::Bytes(1) => (),
                     // TODO: This seems a little overeager, should reading at bool type already be insta-UB?
                     _ => return err!(InvalidBool),
-                };
-                PrimVal::from_bool(val)
+                }
             }
             ty::TyChar => {
                 let c = self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()? as u32;
                 match ::std::char::from_u32(c) {
-                    Some(ch) => PrimVal::from_char(ch),
+                    Some(..) => (),
                     None => return err!(InvalidChar(c as u128)),
                 }
             }
 
-            ty::TyInt(int_ty) => {
-                use syntax::ast::IntTy::*;
-                let size = match int_ty {
-                    I8 => 1,
-                    I16 => 2,
-                    I32 => 4,
-                    I64 => 8,
-                    I128 => 16,
-                    Isize => self.memory.pointer_size(),
-                };
-                self.memory.read_primval(ptr, ptr_align, size)?
-            }
-
-            ty::TyUint(uint_ty) => {
-                use syntax::ast::UintTy::*;
-                let size = match uint_ty {
-                    U8 => 1,
-                    U16 => 2,
-                    U32 => 4,
-                    U64 => 8,
-                    U128 => 16,
-                    Usize => self.memory.pointer_size(),
-                };
-                self.memory.read_primval(ptr, ptr_align, size)?
-            }
-
-            ty::TyFloat(FloatTy::F32) => {
-                PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()?)
-            }
-            ty::TyFloat(FloatTy::F64) => {
-                PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 8)?.to_bytes()?)
-            }
-
-            ty::TyFnPtr(_) => self.memory.read_ptr_sized(ptr, ptr_align)?,
+            ty::TyFnPtr(_) => {
+                self.memory.read_ptr_sized(ptr, ptr_align)?;
+            },
             ty::TyRef(_, rty, _) |
             ty::TyRawPtr(ty::TypeAndMut { ty: rty, .. }) => {
-                return self.read_ptr(ptr, ptr_align, rty).map(Some)
+                self.read_ptr(ptr, ptr_align, rty)?;
             }
 
             ty::TyAdt(def, _) => {
                 if def.is_box() {
-                    return self.read_ptr(ptr, ptr_align, ty.boxed_ty()).map(Some);
+                    self.read_ptr(ptr, ptr_align, ty.boxed_ty())?;
+                    return Ok(());
                 }
 
                 if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi {
                     let size = scalar.value.size(self).bytes();
-                    self.memory.read_primval(ptr, ptr_align, size)?
-                } else {
-                    return Ok(None);
+                    self.memory.read_primval(ptr, ptr_align, size)?;
                 }
             }
 
-            _ => return Ok(None),
-        };
+            _ => (),
+        }
+        Ok(())
+    }
+
+    pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
+        let layout = self.layout_of(ty)?;
+        self.memory.check_align(ptr, ptr_align)?;
 
-        Ok(Some(Value::ByVal(val)))
+        if layout.size.bytes() == 0 {
+            return Ok(Some(Value::ByVal(PrimVal::Undef)));
+        }
+
+        let ptr = ptr.to_ptr()?;
+
+        // Not the right place to do this
+        //self.validate_ptr_target(ptr, ptr_align, ty)?;
+
+        match layout.abi {
+            layout::Abi::Scalar(..) => {
+                let primval = self.memory.read_primval(ptr, ptr_align, layout.size.bytes())?;
+                Ok(Some(Value::ByVal(primval)))
+            }
+            layout::Abi::ScalarPair(ref a, ref b) => {
+                let (a, b) = (&a.value, &b.value);
+                let (a_size, b_size) = (a.size(self), b.size(self));
+                let a_ptr = ptr;
+                let b_offset = a_size.abi_align(b.align(self));
+                let b_ptr = ptr.offset(b_offset.bytes(), self)?.into();
+                let a_val = self.memory.read_primval(a_ptr, ptr_align, a_size.bytes())?;
+                let b_val = self.memory.read_primval(b_ptr, ptr_align, b_size.bytes())?;
+                Ok(Some(Value::ByValPair(a_val, b_val)))
+            }
+            _ => Ok(None),
+        }
     }
 
     pub fn frame(&self) -> &Frame<'mir, 'tcx> {
@@ -1466,7 +1481,7 @@ fn unsize_into_ptr(
                 let ptr = self.into_ptr(src)?;
                 // u64 cast is from usize to u64, which is always good
                 let valty = ValTy {
-                    value: ptr.to_value_with_len(length.val.unwrap_u64() ),
+                    value: ptr.to_value_with_len(length.unwrap_usize(self.tcx.tcx)),
                     ty: dest_ty,
                 };
                 self.write_value(valty, dest)
index 7f8205b8327face1250c757888a8dbfaaf8039d7..ba1c05deef1b42e8a0264c5ef4d7dc34223d14ce 100644 (file)
@@ -1,15 +1,18 @@
-use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian};
-use std::collections::{btree_map, BTreeMap, VecDeque};
-use std::{ptr, io};
+use std::collections::{btree_map, VecDeque};
+use std::ptr;
 
+use rustc::hir::def_id::DefId;
 use rustc::ty::Instance;
+use rustc::ty::ParamEnv;
 use rustc::ty::maps::TyCtxtAt;
 use rustc::ty::layout::{self, Align, TargetDataLayout};
 use syntax::ast::Mutability;
+use rustc::middle::const_val::{ConstVal, ErrKind};
 
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
-use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, UndefMask, Value, Pointer,
-                            EvalResult, PrimVal, EvalErrorKind};
+use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, Value, Pointer,
+                            EvalResult, PrimVal, EvalErrorKind, GlobalId};
+pub use rustc::mir::interpret::{write_target_uint, write_target_int, read_target_uint};
 
 use super::{EvalContext, Machine};
 
@@ -79,20 +82,11 @@ pub fn allocate_cached(&mut self, bytes: &[u8]) -> MemoryPointer {
     }
 
     /// kind is `None` for statics
-    pub fn allocate(
+    pub fn allocate_value(
         &mut self,
-        size: u64,
-        align: Align,
+        alloc: Allocation,
         kind: Option<MemoryKind<M::MemoryKinds>>,
-    ) -> EvalResult<'tcx, MemoryPointer> {
-        assert_eq!(size as usize as u64, size);
-        let alloc = Allocation {
-            bytes: vec![0; size as usize],
-            relocations: BTreeMap::new(),
-            undef_mask: UndefMask::new(size),
-            align,
-            runtime_mutability: Mutability::Immutable,
-        };
+    ) -> EvalResult<'tcx, AllocId> {
         let id = self.tcx.interpret_interner.reserve();
         M::add_lock(self, id);
         match kind {
@@ -105,6 +99,17 @@ pub fn allocate(
                 self.uninitialized_statics.insert(id, alloc);
             },
         }
+        Ok(id)
+    }
+
+    /// kind is `None` for statics
+    pub fn allocate(
+        &mut self,
+        size: u64,
+        align: Align,
+        kind: Option<MemoryKind<M::MemoryKinds>>,
+    ) -> EvalResult<'tcx, MemoryPointer> {
+        let id = self.allocate_value(Allocation::undef(size, align), kind)?;
         Ok(MemoryPointer::new(id, 0))
     }
 
@@ -272,6 +277,31 @@ pub fn check_bounds(&self, ptr: MemoryPointer, access: bool) -> EvalResult<'tcx>
 
 /// Allocation accessors
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
+    fn const_eval_static(&self, def_id: DefId) -> EvalResult<'tcx, &'tcx Allocation> {
+        let instance = Instance::mono(self.tcx.tcx, def_id);
+        let gid = GlobalId {
+            instance,
+            promoted: None,
+        };
+        self.tcx.const_eval(ParamEnv::reveal_all().and(gid)).map_err(|err| {
+            match *err.kind {
+                ErrKind::Miri(ref err, _) => match err.kind {
+                    EvalErrorKind::TypeckError |
+                    EvalErrorKind::Layout(_) => EvalErrorKind::TypeckError.into(),
+                    _ => EvalErrorKind::ReferencedConstant.into(),
+                },
+                ErrKind::TypeckError => EvalErrorKind::TypeckError.into(),
+                ref other => bug!("const eval returned {:?}", other),
+            }
+        }).map(|val| {
+            let const_val = match val.val {
+                ConstVal::Value(val) => val,
+                ConstVal::Unevaluated(..) => bug!("should be evaluated"),
+            };
+            self.tcx.const_value_to_allocation((const_val, val.ty))
+        })
+    }
+
     pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
         // normal alloc?
         match self.alloc_map.get(&id) {
@@ -281,13 +311,19 @@ pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
                 Some(alloc) => Ok(alloc),
                 None => {
                     // static alloc?
-                    self.tcx.interpret_interner.get_alloc(id)
-                        // no alloc? produce an error
-                        .ok_or_else(|| if self.tcx.interpret_interner.get_fn(id).is_some() {
-                            EvalErrorKind::DerefFunctionPointer.into()
-                        } else {
-                            EvalErrorKind::DanglingPointerDeref.into()
-                        })
+                    if let Some(a) = self.tcx.interpret_interner.get_alloc(id) {
+                        return Ok(a);
+                    }
+                    // static variable?
+                    if let Some(did) = self.tcx.interpret_interner.get_static(id) {
+                        return self.const_eval_static(did);
+                    }
+                    // otherwise return an error
+                    Err(if self.tcx.interpret_interner.get_fn(id).is_some() {
+                        EvalErrorKind::DerefFunctionPointer.into()
+                    } else {
+                        EvalErrorKind::DanglingPointerDeref.into()
+                    })
                 },
             },
         }
@@ -873,41 +909,6 @@ pub fn mark_definedness(
     }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// Methods to access integers in the target endianness
-////////////////////////////////////////////////////////////////////////////////
-
-pub fn write_target_uint(
-    endianness: layout::Endian,
-    mut target: &mut [u8],
-    data: u128,
-) -> Result<(), io::Error> {
-    let len = target.len();
-    match endianness {
-        layout::Endian::Little => target.write_uint128::<LittleEndian>(data, len),
-        layout::Endian::Big => target.write_uint128::<BigEndian>(data, len),
-    }
-}
-
-pub fn write_target_int(
-    endianness: layout::Endian,
-    mut target: &mut [u8],
-    data: i128,
-) -> Result<(), io::Error> {
-    let len = target.len();
-    match endianness {
-        layout::Endian::Little => target.write_int128::<LittleEndian>(data, len),
-        layout::Endian::Big => target.write_int128::<BigEndian>(data, len),
-    }
-}
-
-pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
-    match endianness {
-        layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
-        layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()),
-    }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Unaligned accesses
 ////////////////////////////////////////////////////////////////////////////////
index 1eb131810bdf38d9404a60a6fa16f61c4c3a9c17..d39bae5e8dbbaa1ca4ecc17539f5b6039af025a3 100644 (file)
     mk_borrowck_eval_cx,
     eval_body,
     CompileTimeEvaluator,
+    const_value_to_allocation_provider,
     const_eval_provider,
     const_val_field,
     const_variant_index,
+    value_to_const_value,
 };
 
 pub use self::machine::Machine;
index b5a06286e4eed18430d12f9460043b0ecd27d4aa..883b17b8584fb010ff322449d6262a5e4cced110 100644 (file)
@@ -1,5 +1,5 @@
 use rustc::mir;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
 use rustc_data_structures::indexed_vec::Idx;
 
@@ -69,9 +69,13 @@ pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> {
         self.to_ptr_align().0.to_ptr()
     }
 
-    pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) {
+    pub(super) fn elem_ty_and_len(
+        self,
+        ty: Ty<'tcx>,
+        tcx: TyCtxt<'_, 'tcx, '_>
+    ) -> (Ty<'tcx>, u64) {
         match ty.sty {
-            ty::TyArray(elem, n) => (elem, n.val.unwrap_u64() as u64),
+            ty::TyArray(elem, n) => (elem, n.unwrap_usize(tcx)),
 
             ty::TySlice(elem) => {
                 match self {
@@ -320,7 +324,7 @@ pub fn place_index(
         let base = self.force_allocation(base)?;
         let (base_ptr, align) = base.to_ptr_align();
 
-        let (elem_ty, len) = base.elem_ty_and_len(outer_ty);
+        let (elem_ty, len) = base.elem_ty_and_len(outer_ty, self.tcx.tcx);
         let elem_size = self.layout_of(elem_ty)?.size.bytes();
         assert!(
             n < len,
@@ -396,7 +400,7 @@ pub fn eval_place_projection(
                 let base = self.force_allocation(base)?;
                 let (base_ptr, align) = base.to_ptr_align();
 
-                let (elem_ty, n) = base.elem_ty_and_len(base_ty);
+                let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx);
                 let elem_size = self.layout_of(elem_ty)?.size.bytes();
                 assert!(n >= min_length as u64);
 
@@ -415,7 +419,7 @@ pub fn eval_place_projection(
                 let base = self.force_allocation(base)?;
                 let (base_ptr, align) = base.to_ptr_align();
 
-                let (elem_ty, n) = base.elem_ty_and_len(base_ty);
+                let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx);
                 let elem_size = self.layout_of(elem_ty)?.size.bytes();
                 assert!(u64::from(from) <= n - u64::from(to));
                 let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?;
index 2545ba3a94af12215c6a4a15437304944a2ee358..fbc0facbc49670ca94fedbeef383d422780c83be 100644 (file)
@@ -85,6 +85,7 @@ pub fn provide(providers: &mut Providers) {
     shim::provide(providers);
     transform::provide(providers);
     providers.const_eval = interpret::const_eval_provider;
+    providers.const_value_to_allocation = interpret::const_value_to_allocation_provider;
     providers.check_match = hair::pattern::check_match;
 }
 
index e051b848c011fe21a193cfc193fbf88719413b34..e690e8ee88066cc9b9f99efaaea7d758529175b0 100644 (file)
 use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
 use rustc::middle::const_val::ConstVal;
-use rustc::mir::interpret::{Value, PrimVal, AllocId, Pointer};
+use rustc::mir::interpret::{AllocId, ConstValue};
 use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
 use rustc::ty::subst::{Substs, Kind};
 use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
 use rustc::mir::{self, Location, Promoted};
 use rustc::mir::visit::Visitor as MirVisitor;
 use rustc::mir::mono::MonoItem;
-use rustc::mir::interpret::GlobalId;
+use rustc::mir::interpret::{PrimVal, GlobalId};
 
 use monomorphize::{self, Instance};
 use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
@@ -1237,22 +1237,17 @@ fn collect_const<'a, 'tcx>(
     };
     match val {
         ConstVal::Unevaluated(..) => bug!("const eval yielded unevaluated const"),
-        ConstVal::Value(Value::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => {
+        ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => {
             collect_miri(tcx, a.alloc_id, output);
             collect_miri(tcx, b.alloc_id, output);
         }
-        ConstVal::Value(Value::ByValPair(_, PrimVal::Ptr(ptr))) |
-        ConstVal::Value(Value::ByValPair(PrimVal::Ptr(ptr), _)) |
-        ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) =>
+        ConstVal::Value(ConstValue::ByValPair(_, PrimVal::Ptr(ptr))) |
+        ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(ptr), _)) |
+        ConstVal::Value(ConstValue::ByVal(PrimVal::Ptr(ptr))) =>
             collect_miri(tcx, ptr.alloc_id, output),
-        ConstVal::Value(Value::ByRef(Pointer { primval: PrimVal::Ptr(ptr) }, _)) => {
-            // by ref should only collect the inner allocation, not the value itself
-            let alloc = tcx
-                .interpret_interner
-                .get_alloc(ptr.alloc_id)
-                .expect("ByRef to extern static is not allowed");
-            for &inner in alloc.relocations.values() {
-                collect_miri(tcx, inner, output);
+        ConstVal::Value(ConstValue::ByRef(alloc)) => {
+            for &id in alloc.relocations.values() {
+                collect_miri(tcx, id, output);
             }
         }
         _ => {},
index 176ed8c5bca745c53e4c8f0cf2c7f80f9ba86bd7..a569ad00d0c65a6a3dcb211ef677964cc2dbbb86 100644 (file)
@@ -313,8 +313,7 @@ pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String) {
             ty::TyArray(inner_type, len) => {
                 output.push('[');
                 self.push_type_name(inner_type, output);
-                write!(output, "; {}",
-                    len.val.unwrap_u64()).unwrap();
+                write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap();
                 output.push(']');
             },
             ty::TySlice(inner_type) => {
index 699a5b17435bd2c4161d8033eee349992cfc0d9f..5b2f3a8b8aac7ee01237d4ee84e572f28e090e74 100644 (file)
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::infer;
-use rustc::middle::const_val::ConstVal;
 use rustc::mir::*;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::ty::maps::Providers;
-use rustc::mir::interpret::{Value, PrimVal};
 
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
@@ -303,7 +301,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     match self_ty.sty {
         _ if is_copy => builder.copy_shim(),
         ty::TyArray(ty, len) => {
-            let len = len.val.unwrap_u64();
+            let len = len.unwrap_usize(tcx);
             builder.array_shim(dest, src, ty, len)
         }
         ty::TyClosure(def_id, substs) => {
@@ -442,11 +440,7 @@ fn make_clone_call(
             span: self.span,
             ty: func_ty,
             literal: Literal::Value {
-                value: tcx.mk_const(ty::Const {
-                    // ZST function type
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
-                    ty: func_ty
-                }),
+                value: ty::Const::zero_sized(self.tcx, func_ty)
             },
         });
 
@@ -506,10 +500,7 @@ fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> {
             span: self.span,
             ty: self.tcx.types.usize,
             literal: Literal::Value {
-                value: self.tcx.mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))),
-                    ty: self.tcx.types.usize,
-                })
+                value: ty::Const::from_usize(self.tcx, value),
             }
         }
     }
@@ -738,11 +729,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 span,
                 ty,
                 literal: Literal::Value {
-                    value: tcx.mk_const(ty::Const {
-                        // ZST function type
-                        val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
-                        ty
-                    }),
+                    value: ty::Const::zero_sized(tcx, ty)
                 },
              }),
              vec![rcvr])
index e1db216b6bbbcfad1b1d15a9a696d79cc3325674..6b0217c8f7cbc17b48687f4d94a1e83286df3d2c 100644 (file)
 use rustc::mir::visit::{Visitor, PlaceContext};
 use rustc::middle::const_val::ConstVal;
 use rustc::ty::{TyCtxt, self, Instance};
-use rustc::mir::interpret::{Value, PrimVal, GlobalId};
+use rustc::mir::interpret::{Value, PrimVal, GlobalId, EvalResult};
+use interpret::EvalContext;
+use interpret::CompileTimeEvaluator;
 use interpret::{eval_promoted, mk_borrowck_eval_cx, ValTy};
 use transform::{MirPass, MirSource};
-use syntax::codemap::Span;
+use syntax::codemap::{Span, DUMMY_SP};
 use rustc::ty::subst::Substs;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc::ty::ParamEnv;
 use rustc::ty::layout::{
-    LayoutOf, TyLayout, LayoutError,
+    LayoutOf, TyLayout, LayoutError, LayoutCx,
     HasTyCtxt, TargetDataLayout, HasDataLayout,
 };
 
@@ -64,6 +66,7 @@ fn run_pass<'a, 'tcx>(&self,
 
 /// Finds optimization opportunities on the MIR.
 struct ConstPropagator<'b, 'a, 'tcx:'a+'b> {
+    ecx: EvalContext<'a, 'b, 'tcx, CompileTimeEvaluator>,
     mir: &'b Mir<'tcx>,
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     source: MirSource,
@@ -102,7 +105,11 @@ fn new(
         source: MirSource,
     ) -> ConstPropagator<'b, 'a, 'tcx> {
         let param_env = tcx.param_env(source.def_id);
+        let substs = Substs::identity_for_item(tcx, source.def_id);
+        let instance = Instance::new(source.def_id, substs);
+        let ecx = mk_borrowck_eval_cx(tcx, instance, mir, DUMMY_SP).unwrap();
         ConstPropagator {
+            ecx,
             mir,
             tcx,
             source,
@@ -112,7 +119,27 @@ fn new(
         }
     }
 
-    fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
+    fn use_ecx<F, T>(
+        &mut self,
+        span: Span,
+        f: F
+    ) -> Option<T>
+    where
+        F: FnOnce(&mut Self) -> EvalResult<'tcx, T>,
+    {
+        self.ecx.tcx.span = span;
+        let r = match f(self) {
+            Ok(val) => Some(val),
+            Err(mut err) => {
+                self.ecx.report(&mut err, false, Some(span));
+                None
+            },
+        };
+        self.ecx.tcx.span = DUMMY_SP;
+        r
+    }
+
+    fn const_eval(&mut self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
         let value = match self.tcx.const_eval(self.param_env.and(cid)) {
             Ok(val) => val,
             Err(err) => {
@@ -121,7 +148,9 @@ fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
             },
         };
         let val = match value.val {
-            ConstVal::Value(v) => v,
+            ConstVal::Value(v) => {
+                self.use_ecx(span, |this| this.ecx.const_value_to_value(v, value.ty))?
+            },
             _ => bug!("eval produced: {:?}", value),
         };
         let val = (val, value.ty, span);
@@ -132,7 +161,12 @@ fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
     fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<Const<'tcx>> {
         match c.literal {
             Literal::Value { value } => match value.val {
-                ConstVal::Value(v) => Some((v, value.ty, c.span)),
+                ConstVal::Value(v) => {
+                    let v = self.use_ecx(c.span, |this| {
+                        this.ecx.const_value_to_value(v, value.ty)
+                    })?;
+                    Some((v, value.ty, c.span))
+                },
                 ConstVal::Unevaluated(did, substs) => {
                     let instance = Instance::resolve(
                         self.tcx,
@@ -162,7 +196,10 @@ fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<Const<'tcx>> {
                 };
                 // cannot use `const_eval` here, because that would require having the MIR
                 // for the current function available, but we're producing said MIR right now
-                let (value, _, ty) = eval_promoted(self.tcx, cid, self.mir, self.param_env)?;
+                let span = self.mir.span;
+                let (value, _, ty) = self.use_ecx(span, |this| {
+                    Ok(eval_promoted(&mut this.ecx, cid, this.mir, this.param_env))
+                })??;
                 let val = (value, ty, c.span);
                 trace!("evaluated {:?} to {:?}", c, val);
                 Some(val)
@@ -185,7 +222,11 @@ fn eval_place(&mut self, place: &Place<'tcx>) -> Option<Const<'tcx>> {
                             use rustc_data_structures::indexed_vec::Idx;
                             let field_index = field.index();
                             let val = [a, b][field_index];
-                            let field = base_layout.field(&*self, field_index).ok()?;
+                            let cx = LayoutCx {
+                                tcx: self.tcx,
+                                param_env: self.param_env,
+                            };
+                            let field = base_layout.field(cx, field_index).ok()?;
                             trace!("projection resulted in: {:?}", val);
                             Some((Value::ByVal(val), field.ty, span))
                         },
@@ -258,19 +299,13 @@ fn const_prop(
                     // FIXME: can't handle code with generics
                     return None;
                 }
-                let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
-                let instance = Instance::new(self.source.def_id, substs);
-                let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap();
 
                 let val = self.eval_operand(arg)?;
-                let prim = ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }).ok()?;
-                match ecx.unary_op(op, prim, val.1) {
-                    Ok(val) => Some((Value::ByVal(val), place_ty, span)),
-                    Err(mut err) => {
-                        ecx.report(&mut err, false, Some(span));
-                        None
-                    },
-                }
+                let prim = self.use_ecx(span, |this| {
+                    this.ecx.value_to_primval(ValTy { value: val.0, ty: val.1 })
+                })?;
+                let val = self.use_ecx(span, |this| this.ecx.unary_op(op, prim, val.1))?;
+                Some((Value::ByVal(val), place_ty, span))
             }
             Rvalue::CheckedBinaryOp(op, ref left, ref right) |
             Rvalue::BinaryOp(op, ref left, ref right) => {
@@ -287,11 +322,10 @@ fn const_prop(
                     // FIXME: can't handle code with generics
                     return None;
                 }
-                let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
-                let instance = Instance::new(self.source.def_id, substs);
-                let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap();
 
-                let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?;
+                let r = self.use_ecx(span, |this| {
+                    this.ecx.value_to_primval(ValTy { value: right.0, ty: right.1 })
+                })?;
                 if op == BinOp::Shr || op == BinOp::Shl {
                     let param_env = self.tcx.param_env(self.source.def_id);
                     let left_ty = left.ty(self.mir, self.tcx);
@@ -316,31 +350,31 @@ fn const_prop(
                     }
                 }
                 let left = self.eval_operand(left)?;
-                let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?;
+                let l = self.use_ecx(span, |this| {
+                    this.ecx.value_to_primval(ValTy { value: left.0, ty: left.1 })
+                })?;
                 trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
-                match ecx.binary_op(op, l, left.1, r, right.1) {
-                    Ok((val, overflow)) => {
-                        let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
-                            Value::ByValPair(
-                                val,
-                                PrimVal::from_bool(overflow),
-                            )
-                        } else {
-                            if overflow {
-                                use rustc::mir::interpret::EvalErrorKind;
-                                let mut err = EvalErrorKind::Overflow(op).into();
-                                ecx.report(&mut err, false, Some(span));
-                                return None;
-                            }
-                            Value::ByVal(val)
-                        };
-                        Some((val, place_ty, span))
-                    },
-                    Err(mut err) => {
-                        ecx.report(&mut err, false, Some(span));
-                        None
-                    },
-                }
+                let (val, overflow) = self.use_ecx(span, |this| {
+                    this.ecx.binary_op(op, l, left.1, r, right.1)
+                })?;
+                let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
+                    Value::ByValPair(
+                        val,
+                        PrimVal::from_bool(overflow),
+                    )
+                } else {
+                    if overflow {
+                        use rustc::mir::interpret::EvalErrorKind;
+                        let mut err = EvalErrorKind::Overflow(op).into();
+                        self.use_ecx(span, |this| {
+                            this.ecx.report(&mut err, false, Some(span));
+                            Ok(())
+                        });
+                        return None;
+                    }
+                    Value::ByVal(val)
+                };
+                Some((val, place_ty, span))
             },
         }
     }
index 5397d18cdd720be1b0d185fe4359e88d10bb07d3..56050318ca7faf808687a0dd313110f83d996ded 100644 (file)
@@ -17,8 +17,6 @@
 use dataflow::{self, do_dataflow, DebugFormatted};
 use rustc::ty::{self, TyCtxt};
 use rustc::mir::*;
-use rustc::middle::const_val::ConstVal;
-use rustc::mir::interpret::{Value, PrimVal};
 use rustc::util::nodemap::FxHashMap;
 use rustc_data_structures::indexed_set::IdxSetBuf;
 use rustc_data_structures::indexed_vec::Idx;
@@ -174,7 +172,7 @@ struct Elaborator<'a, 'b: 'a, 'tcx: 'b> {
 }
 
 impl<'a, 'b, 'tcx> fmt::Debug for Elaborator<'a, 'b, 'tcx> {
-    fn fmt(&self, _f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
         Ok(())
     }
 }
@@ -533,10 +531,7 @@ fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> {
             span,
             ty: self.tcx.types.bool,
             literal: Literal::Value {
-                value: self.tcx.mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val as u128))),
-                    ty: self.tcx.types.bool
-                })
+                value: ty::Const::from_bool(self.tcx, val)
             }
         })))
     }
index c4e700cdd1f41aa2d62c720dc0a2d0ef5b2f9a72..5da40d04b337399b6526b5bcf64b43c4267bd098 100644 (file)
@@ -61,7 +61,6 @@
 
 use rustc::hir;
 use rustc::hir::def_id::DefId;
-use rustc::middle::const_val::ConstVal;
 use rustc::mir::*;
 use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor};
 use rustc::ty::{self, TyCtxt, AdtDef, Ty};
@@ -79,7 +78,6 @@
 use transform::no_landing_pads::no_landing_pads;
 use dataflow::{do_dataflow, DebugFormatted, state_for_location};
 use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals};
-use rustc::mir::interpret::{Value, PrimVal};
 
 pub struct StateTransform;
 
@@ -180,10 +178,10 @@ fn set_state(&self, state_disc: u32, source_info: SourceInfo) -> Statement<'tcx>
             span: source_info.span,
             ty: self.tcx.types.u32,
             literal: Literal::Value {
-                value: self.tcx.mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into()))),
-                    ty: self.tcx.types.u32
-                }),
+                value: ty::Const::from_bits(
+                    self.tcx,
+                    state_disc.into(),
+                    self.tcx.types.u32),
             },
         });
         Statement {
@@ -698,10 +696,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             span: mir.span,
             ty: tcx.types.bool,
             literal: Literal::Value {
-                value: tcx.mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
-                    ty: tcx.types.bool
-                }),
+                value: ty::Const::from_bool(tcx, false),
             },
         }),
         expected: true,
index 4762c6aaa27cc8143e78f65ffe3058c493a67d62..28ab3d6a8574fb3543cf27bc40e15f42192cb97d 100644 (file)
@@ -595,7 +595,7 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
             }
             Operand::Constant(ref constant) => {
                 if let Literal::Value {
-                    value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty }
+                    value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty, .. }
                 } = constant.literal {
                     // Don't peek inside trait associated constants.
                     if self.tcx.trait_of_item(def_id).is_some() {
@@ -690,7 +690,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                             _ => false
                         }
                     } else if let ty::TyArray(_, len) = ty.sty {
-                        len.val.unwrap_u64() == 0 &&
+                        len.unwrap_usize(self.tcx) == 0 &&
                             self.mode == Mode::Fn
                     } else {
                         false
index 9dd48952208a9bed86565fb603ffdbaca8bf1927..72bee040c06a9a676f5b5b3c5fcad9fc00511acc 100644 (file)
 
 //! A pass that simplifies branches when their condition is known.
 
-use rustc::ty::{self, TyCtxt};
-use rustc::middle::const_val::ConstVal;
+use rustc::ty::TyCtxt;
 use rustc::mir::*;
-use rustc::mir::interpret::{Value, PrimVal};
 use transform::{MirPass, MirSource};
 
 use std::borrow::Cow;
@@ -32,7 +30,7 @@ fn name<'a>(&'a self) -> Cow<'a, str> {
     }
 
     fn run_pass<'a, 'tcx>(&self,
-                          _tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           _src: MirSource,
                           mir: &mut Mir<'tcx>) {
         for block in mir.basic_blocks_mut() {
@@ -40,8 +38,8 @@ fn run_pass<'a, 'tcx>(&self,
             terminator.kind = match terminator.kind {
                 TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
                     literal: Literal::Value { ref value }, ..
-                }), ref values, ref targets, .. } => {
-                    if let Some(constint) = value.val.to_raw_bits() {
+                }), switch_ty, ref values, ref targets, .. } => {
+                    if let Some(constint) = value.assert_bits(switch_ty) {
                         let (otherwise, targets) = targets.split_last().unwrap();
                         let mut ret = TerminatorKind::Goto { target: *otherwise };
                         for (&v, t) in values.iter().zip(targets.iter()) {
@@ -57,12 +55,9 @@ fn run_pass<'a, 'tcx>(&self,
                 },
                 TerminatorKind::Assert { target, cond: Operand::Constant(box Constant {
                     literal: Literal::Value {
-                        value: &ty::Const {
-                            val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(cond))),
-                        .. }
+                        value
                     }, ..
-                }), expected, .. } if (cond == 1) == expected => {
-                    assert!(cond <= 1);
+                }), expected, .. } if (value.assert_bool(tcx) == Some(true)) == expected => {
                     TerminatorKind::Goto { target: target }
                 },
                 TerminatorKind::FalseEdges { real_target, .. } => {
index 9cc3ffb30638fe78945d485a482235b0ee7e0f92..5019c74742a2b3ff31ddc087b85883ae5a1de196 100644 (file)
@@ -81,9 +81,9 @@ fn visit_assign(&mut self,
                 } else {
                     let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
                     if let ty::TyArray(item_ty, const_size) = place_ty.sty {
-                        if let Some(size) = const_size.val.to_raw_bits() {
-                            assert!(size <= (u32::max_value() as u128),
-                                    "unform array move out doesn't supported
+                        if let Some(size) = const_size.assert_usize(self.tcx) {
+                            assert!(size <= u32::max_value() as u64,
+                                    "uniform array move out doesn't supported
                                      for array bigger then u32");
                             self.uniform(location, dst_place, proj, item_ty, size as u32);
                         }
@@ -203,7 +203,7 @@ fn run_pass<'a, 'tcx>(&self,
                         let opt_size = opt_src_place.and_then(|src_place| {
                             let src_ty = src_place.ty(mir, tcx).to_ty(tcx);
                             if let ty::TyArray(_, ref size_o) = src_ty.sty {
-                                size_o.val.to_raw_bits().map(|n| n as u64)
+                                size_o.assert_usize(tcx)
                             } else {
                                 None
                             }
index a641cf3d93ecfeff5dab38d05389ee2c448a5761..9fc04dc7d24914a3c66fca69418aeaa2cf984799 100644 (file)
@@ -11,7 +11,6 @@
 use std::fmt;
 use rustc::hir;
 use rustc::mir::*;
-use rustc::middle::const_val::ConstVal;
 use rustc::middle::lang_items;
 use rustc::traits::Reveal;
 use rustc::ty::{self, Ty, TyCtxt};
@@ -19,7 +18,6 @@
 use rustc::ty::util::IntTypeExt;
 use rustc_data_structures::indexed_vec::Idx;
 use util::patch::MirPatch;
-use rustc::mir::interpret::{Value, PrimVal};
 
 use std::{iter, u32};
 
@@ -809,8 +807,10 @@ fn open_drop<'a>(&mut self) -> BasicBlock {
                 let succ = self.succ;
                 self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
             }
-            ty::TyArray(ety, size) => self.open_drop_for_array(
-                ety, size.val.to_raw_bits().map(|i| i as u64)),
+            ty::TyArray(ety, size) => {
+                let size = size.assert_usize(self.tcx());
+                self.open_drop_for_array(ety, size)
+            },
             ty::TySlice(ety) => self.open_drop_for_array(ety, None),
 
             _ => bug!("open drop from non-ADT `{:?}`", ty)
@@ -961,10 +961,7 @@ fn constant_usize(&self, val: u16) -> Operand<'tcx> {
             span: self.source_info.span,
             ty: self.tcx().types.usize,
             literal: Literal::Value {
-                value: self.tcx().mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.into()))),
-                    ty: self.tcx().types.usize
-                })
+                value: ty::Const::from_usize(self.tcx(), val.into())
             }
         })
     }
index 71012ca6d5f7992045124a4af6997ed39a65351d..9d74ad0830f0c236178cc1227b48e0a81ac1fa45 100644 (file)
@@ -402,7 +402,7 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
 
     fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) {
         self.super_const(constant);
-        let ty::Const { ty, val } = constant;
+        let ty::Const { ty, val, .. } = constant;
         self.push(&format!("ty::Const"));
         self.push(&format!("+ ty: {:?}", ty));
         self.push(&format!("+ val: {:?}", val));
index 293f23eab388317c4b5a5d0bdbd8f50ca3d2426a..4594d450c1507f7a05dbd9078d0f3c9d90dab2c4 100644 (file)
@@ -15,7 +15,8 @@ pub fn opts() -> TargetOptions {
 
     // Make sure that the linker/gcc really don't pull in anything, including
     // default objects, libs, etc.
-    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string());
+    base.pre_link_args_crt.insert(LinkerFlavor::Gcc, Vec::new());
+    base.pre_link_args_crt.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string());
 
     // At least when this was tested, the linker would not add the
     // `GNU_EH_FRAME` program header to executables generated, which is required
@@ -55,9 +56,11 @@ pub fn opts() -> TargetOptions {
     //
     // Each target directory for musl has these object files included in it so
     // they'll be included from there.
-    base.pre_link_objects_exe.push("crt1.o".to_string());
-    base.pre_link_objects_exe.push("crti.o".to_string());
-    base.post_link_objects.push("crtn.o".to_string());
+    base.pre_link_objects_exe_crt.push("crt1.o".to_string());
+    base.pre_link_objects_exe_crt.push("crti.o".to_string());
+    base.pre_link_objects_exe_crt_sys.push("crtbegin.o".to_string());
+    base.post_link_objects_crt_sys.push("crtend.o".to_string());
+    base.post_link_objects_crt.push("crtn.o".to_string());
 
     // These targets statically link libc by default
     base.crt_static_default = true;
index 48e771e0aafab3c942cf8922825cc28cc4276be9..708a3865b23b910fa88920f25044b18287686f69 100644 (file)
@@ -421,20 +421,26 @@ pub struct TargetOptions {
     /// Linker to invoke
     pub linker: Option<String>,
 
-    /// Linker arguments that are unconditionally passed *before* any
-    /// user-defined libraries.
-    pub pre_link_args: LinkArgs,
-    /// Objects to link before all others, always found within the
+    /// Linker arguments that are passed *before* any user-defined libraries.
+    pub pre_link_args: LinkArgs, // ... unconditionally
+    pub pre_link_args_crt: LinkArgs, // ... when linking with a bundled crt
+    /// Objects to link before all others, all except *_sys found within the
     /// sysroot folder.
-    pub pre_link_objects_exe: Vec<String>, // ... when linking an executable
+    pub pre_link_objects_exe: Vec<String>, // ... when linking an executable, unconditionally
+    pub pre_link_objects_exe_crt: Vec<String>, // ... when linking an executable with a bundled crt
+    pub pre_link_objects_exe_crt_sys: Vec<String>, // ... when linking an executable with a bundled
+                                                   //  crt, from the system library search path
     pub pre_link_objects_dll: Vec<String>, // ... when linking a dylib
     /// Linker arguments that are unconditionally passed after any
     /// user-defined but before post_link_objects.  Standard platform
     /// libraries that should be always be linked to, usually go here.
     pub late_link_args: LinkArgs,
-    /// Objects to link after all others, always found within the
+    /// Objects to link after all others, all except *_sys found within the
     /// sysroot folder.
-    pub post_link_objects: Vec<String>,
+    pub post_link_objects: Vec<String>, // ... unconditionally
+    pub post_link_objects_crt: Vec<String>, // ... when linking with a bundled crt
+    pub post_link_objects_crt_sys: Vec<String>, // ... when linking with a bundled crt, from the
+                                                //  system library search path
     /// Linker arguments that are unconditionally passed *after* any
     /// user-defined libraries.
     pub post_link_args: LinkArgs,
@@ -634,6 +640,7 @@ fn default() -> TargetOptions {
             is_builtin: false,
             linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()),
             pre_link_args: LinkArgs::new(),
+            pre_link_args_crt: LinkArgs::new(),
             post_link_args: LinkArgs::new(),
             asm_args: Vec::new(),
             cpu: "generic".to_string(),
@@ -667,8 +674,12 @@ fn default() -> TargetOptions {
             position_independent_executables: false,
             relro_level: RelroLevel::None,
             pre_link_objects_exe: Vec::new(),
+            pre_link_objects_exe_crt: Vec::new(),
+            pre_link_objects_exe_crt_sys: Vec::new(),
             pre_link_objects_dll: Vec::new(),
             post_link_objects: Vec::new(),
+            post_link_objects_crt: Vec::new(),
+            post_link_objects_crt_sys: Vec::new(),
             late_link_args: LinkArgs::new(),
             link_env: Vec::new(),
             archive_format: "gnu".to_string(),
@@ -887,10 +898,15 @@ macro_rules! key {
         key!(is_builtin, bool);
         key!(linker, optional);
         key!(pre_link_args, link_args);
+        key!(pre_link_args_crt, link_args);
         key!(pre_link_objects_exe, list);
+        key!(pre_link_objects_exe_crt, list);
+        key!(pre_link_objects_exe_crt_sys, list);
         key!(pre_link_objects_dll, list);
         key!(late_link_args, link_args);
         key!(post_link_objects, list);
+        key!(post_link_objects_crt, list);
+        key!(post_link_objects_crt_sys, list);
         key!(post_link_args, link_args);
         key!(link_env, env);
         key!(asm_args, list);
@@ -1092,10 +1108,15 @@ macro_rules! target_option_val {
         target_option_val!(is_builtin);
         target_option_val!(linker);
         target_option_val!(link_args - pre_link_args);
+        target_option_val!(link_args - pre_link_args_crt);
         target_option_val!(pre_link_objects_exe);
+        target_option_val!(pre_link_objects_exe_crt);
+        target_option_val!(pre_link_objects_exe_crt_sys);
         target_option_val!(pre_link_objects_dll);
         target_option_val!(link_args - late_link_args);
         target_option_val!(post_link_objects);
+        target_option_val!(post_link_objects_crt);
+        target_option_val!(post_link_objects_crt_sys);
         target_option_val!(link_args - post_link_args);
         target_option_val!(env - link_env);
         target_option_val!(asm_args);
index d39556e9bb197e6ff91aaef9fad166ee04bd3268..299075ed03ad9ec0cfbc922c89f624227f8048fb 100644 (file)
@@ -621,6 +621,11 @@ fn link_natively(sess: &Session,
     if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
         cmd.args(args);
     }
+    if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) {
+        if sess.crt_static() {
+            cmd.args(args);
+        }
+    }
     if let Some(ref args) = sess.opts.debugging_opts.pre_link_args {
         cmd.args(args);
     }
@@ -635,6 +640,18 @@ fn link_natively(sess: &Session,
         cmd.arg(root.join(obj));
     }
 
+    if crate_type == config::CrateTypeExecutable && sess.crt_static() {
+        for obj in &sess.target.target.options.pre_link_objects_exe_crt {
+            cmd.arg(root.join(obj));
+        }
+
+        for obj in &sess.target.target.options.pre_link_objects_exe_crt_sys {
+            if flavor == LinkerFlavor::Gcc {
+                cmd.arg(format!("-l:{}", obj));
+            }
+        }
+    }
+
     if sess.target.target.options.is_like_emscripten {
         cmd.arg("-s");
         cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
@@ -656,6 +673,16 @@ fn link_natively(sess: &Session,
     for obj in &sess.target.target.options.post_link_objects {
         cmd.arg(root.join(obj));
     }
+    if sess.crt_static() {
+        for obj in &sess.target.target.options.post_link_objects_crt_sys {
+            if flavor == LinkerFlavor::Gcc {
+                cmd.arg(format!("-l:{}", obj));
+            }
+        }
+        for obj in &sess.target.target.options.post_link_objects_crt {
+            cmd.arg(root.join(obj));
+        }
+    }
     if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) {
         cmd.args(args);
     }
index 2a473f1ecbcc5efcff393a10b751c22a0ae96998..bbb5f7eecc82c28223cd4e6edad47cca48769d17 100644 (file)
@@ -482,7 +482,7 @@ fn run_pass_manager(cgcx: &CodegenContext,
             llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less,
             level => level,
         };
-        with_llvm_pmb(llmod, config, opt_level, &mut |b| {
+        with_llvm_pmb(llmod, config, opt_level, false, &mut |b| {
             if thin {
                 if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) {
                     panic!("this version of LLVM does not support ThinLTO");
index 64876e82309f05182f6fba788b23b39b39047540..acfe7c33028274a1be426816e9dd3f19f2545693 100644 (file)
@@ -17,8 +17,8 @@
 use back::symbol_export::ExportedSymbols;
 use base;
 use consts;
-use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
-use rustc::dep_graph::{DepGraph, WorkProductFileKind};
+use rustc_incremental::{copy_cgu_workproducts_to_incr_comp_cache_dir, in_incr_comp_dir};
+use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind};
 use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
 use rustc::session::config::{self, OutputFilenames, OutputType, Passes, SomePasses,
                              AllPasses, Sanitizer, Lto};
@@ -547,7 +547,8 @@ unsafe fn optimize(cgcx: &CodegenContext,
             llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
             llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
             let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
-            with_llvm_pmb(llmod, &config, opt_level, &mut |b| {
+            let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal;
+            with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| {
                 llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
                 llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
             })
@@ -1021,11 +1022,14 @@ pub fn start_async_translation(tcx: TyCtxt,
     }
 }
 
-fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
-                                              dep_graph: &DepGraph,
-                                              compiled_modules: &CompiledModules) {
+fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
+    sess: &Session,
+    compiled_modules: &CompiledModules
+) -> FxHashMap<WorkProductId, WorkProduct> {
+    let mut work_products = FxHashMap::default();
+
     if sess.opts.incremental.is_none() {
-        return;
+        return work_products;
     }
 
     for module in compiled_modules.modules.iter() {
@@ -1041,8 +1045,13 @@ fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
             files.push((WorkProductFileKind::BytecodeCompressed, path.clone()));
         }
 
-        save_trans_partition(sess, dep_graph, &module.name, &files);
+        if let Some((id, product)) =
+                copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files) {
+            work_products.insert(id, product);
+        }
     }
+
+    work_products
 }
 
 fn produce_final_output_artifacts(sess: &Session,
@@ -2042,6 +2051,7 @@ pub fn run_assembler(cgcx: &CodegenContext, handler: &Handler, assembly: &Path,
 pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
                             config: &ModuleConfig,
                             opt_level: llvm::CodeGenOptLevel,
+                            prepare_for_thin_lto: bool,
                             f: &mut FnMut(llvm::PassManagerBuilderRef)) {
     use std::ptr;
 
@@ -2069,6 +2079,7 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
         config.merge_functions,
         config.vectorize_slp,
         config.vectorize_loop,
+        prepare_for_thin_lto,
         pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
         pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
     );
@@ -2236,7 +2247,10 @@ pub struct OngoingCrateTranslation {
 }
 
 impl OngoingCrateTranslation {
-    pub(crate) fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslation {
+    pub(crate) fn join(
+        self,
+        sess: &Session
+    ) -> (CrateTranslation, FxHashMap<WorkProductId, WorkProduct>) {
         self.shared_emitter_main.check(sess, true);
         let compiled_modules = match self.future.join() {
             Ok(Ok(compiled_modules)) => compiled_modules,
@@ -2255,9 +2269,9 @@ pub(crate) fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslati
             time_graph.dump(&format!("{}-timings", self.crate_name));
         }
 
-        copy_module_artifacts_into_incr_comp_cache(sess,
-                                                   dep_graph,
-                                                   &compiled_modules);
+        let work_products = copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess,
+                                                                             &compiled_modules);
+
         produce_final_output_artifacts(sess,
                                        &compiled_modules,
                                        &self.output_filenames);
@@ -2281,7 +2295,7 @@ pub(crate) fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslati
             metadata_module: compiled_modules.metadata_module,
         };
 
-        trans
+        (trans, work_products)
     }
 
     pub(crate) fn submit_pre_translated_module_to_llvm(&self,
index 33dc9b3b7ab90087caf3291f7c1ae6aabe53115d..0dd1adbff86e0daf7f616c646dcee11b3748c856 100644 (file)
@@ -199,7 +199,7 @@ pub fn unsized_info<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>,
     let (source, target) = cx.tcx.struct_lockstep_tails(source, target);
     match (&source.sty, &target.sty) {
         (&ty::TyArray(_, len), &ty::TySlice(_)) => {
-            C_usize(cx, len.val.unwrap_u64())
+            C_usize(cx, len.unwrap_usize(cx.tcx))
         }
         (&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
             // For now, upcasts are limited to changes in marker
@@ -1372,7 +1372,7 @@ fn hash_stable<W: StableHasherResult>(&self,
 }
 
 fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec<u8>) {
-    use rustc::mir::interpret::{GlobalId, Value, PrimVal};
+    use rustc::mir::interpret::GlobalId;
     use rustc::middle::const_val::ConstVal;
 
     info!("loading wasm section {:?}", id);
@@ -1392,22 +1392,11 @@ fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec<u8>) {
     let param_env = ty::ParamEnv::reveal_all();
     let val = tcx.const_eval(param_env.and(cid)).unwrap();
 
-    let val = match val.val {
+    let const_val = match val.val {
         ConstVal::Value(val) => val,
         ConstVal::Unevaluated(..) => bug!("should be evaluated"),
     };
-    let val = match val {
-        Value::ByRef(ptr, _align) => ptr.into_inner_primval(),
-        ref v => bug!("should be ByRef, was {:?}", v),
-    };
-    let mem = match val {
-        PrimVal::Ptr(mem) => mem,
-        ref v => bug!("should be Ptr, was {:?}", v),
-    };
-    assert_eq!(mem.offset, 0);
-    let alloc = tcx
-        .interpret_interner
-        .get_alloc(mem.alloc_id)
-        .expect("miri allocation never successfully created");
+
+    let alloc = tcx.const_value_to_allocation((const_val, val.ty));
     (section.to_string(), alloc.bytes.clone())
 }
index ae23b523cbfaebcb68fa9dc4e56e44a2a5d2a297..4e77c0df65ef4eeeb6569d2d67b0f237c1d4ca8d 100644 (file)
@@ -277,7 +277,7 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
 
     let upper_bound = match array_or_slice_type.sty {
         ty::TyArray(_, len) => {
-            len.val.unwrap_u64() as c_longlong
+            len.unwrap_usize(cx.tcx) as c_longlong
         }
         _ => -1
     };
index 565a9bedef0f51d724bf78e044bcb1e7c66891b0..05a74db3a6ca9842470d51991fc589dc5998c88a 100644 (file)
@@ -97,7 +97,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
         ty::TyArray(inner_type, len) => {
             output.push('[');
             push_debuginfo_type_name(cx, inner_type, true, output);
-            output.push_str(&format!("; {}", len.val.unwrap_u64()));
+            output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx)));
             output.push(']');
         },
         ty::TySlice(inner_type) => {
index 7a152d6ded4c56ecc957f4d6ce7c40d5a1a31c31..30780b8c965637704a683b5e16552ecd4e8bc0d6 100644 (file)
@@ -212,16 +212,16 @@ fn join_trans_and_link(
         outputs: &OutputFilenames,
     ) -> Result<(), CompileIncomplete>{
         use rustc::util::common::time;
-        let trans = trans.downcast::<::back::write::OngoingCrateTranslation>()
+        let (trans, work_products) = trans.downcast::<::back::write::OngoingCrateTranslation>()
             .expect("Expected LlvmTransCrate's OngoingCrateTranslation, found Box<Any>")
-            .join(sess, dep_graph);
+            .join(sess);
         if sess.opts.debugging_opts.incremental_info {
             back::write::dump_incremental_data(&trans);
         }
 
         time(sess,
              "serialize work products",
-             move || rustc_incremental::save_work_products(sess, &dep_graph));
+             move || rustc_incremental::save_work_product_index(sess, &dep_graph, work_products));
 
         sess.compile_status()?;
 
index 6e07b8e73ef22c329ea9c8749ede3d649ae14667..a10b7c9c9f10f23a818d98dd2b8ead0e96fd3fb5 100644 (file)
@@ -14,7 +14,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::mir;
 use rustc_data_structures::indexed_vec::Idx;
-use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue};
+use rustc::mir::interpret::{GlobalId, MemoryPointer, PrimVal, Allocation, ConstValue};
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar};
 use builder::Builder;
@@ -56,7 +56,7 @@ pub fn primval_to_llvm(cx: &CodegenCx,
                     consts::get_static(cx, def_id)
                 } else if let Some(alloc) = cx.tcx.interpret_interner
                                               .get_alloc(ptr.alloc_id) {
-                    let init = global_initializer(cx, alloc);
+                    let init = const_alloc_to_llvm(cx, alloc);
                     if alloc.runtime_mutability == Mutability::Mutable {
                         consts::addr_of_mut(cx, init, alloc.align, "byte_str")
                     } else {
@@ -81,7 +81,50 @@ pub fn primval_to_llvm(cx: &CodegenCx,
     }
 }
 
-pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
+fn const_value_to_llvm<'tcx>(cx: &CodegenCx<'_, 'tcx>, val: ConstValue, ty: Ty<'tcx>) -> ValueRef {
+    let layout = cx.layout_of(ty);
+
+    if layout.is_zst() {
+        return C_undef(layout.immediate_llvm_type(cx));
+    }
+
+    match val {
+        ConstValue::ByVal(x) => {
+            let scalar = match layout.abi {
+                layout::Abi::Scalar(ref x) => x,
+                _ => bug!("const_value_to_llvm: invalid ByVal layout: {:#?}", layout)
+            };
+            primval_to_llvm(
+                cx,
+                x,
+                scalar,
+                layout.immediate_llvm_type(cx),
+            )
+        },
+        ConstValue::ByValPair(a, b) => {
+            let (a_scalar, b_scalar) = match layout.abi {
+                layout::Abi::ScalarPair(ref a, ref b) => (a, b),
+                _ => bug!("const_value_to_llvm: invalid ByValPair layout: {:#?}", layout)
+            };
+            let a_llval = primval_to_llvm(
+                cx,
+                a,
+                a_scalar,
+                layout.scalar_pair_element_llvm_type(cx, 0),
+            );
+            let b_llval = primval_to_llvm(
+                cx,
+                b,
+                b_scalar,
+                layout.scalar_pair_element_llvm_type(cx, 1),
+            );
+            C_struct(cx, &[a_llval, b_llval], false)
+        },
+        ConstValue::ByRef(alloc) => const_alloc_to_llvm(cx, alloc),
+    }
+}
+
+pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
     let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1);
     let layout = cx.data_layout();
     let pointer_size = layout.pointer_size.bytes() as usize;
@@ -96,7 +139,7 @@ pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
         let ptr_offset = read_target_uint(
             layout.endian,
             &alloc.bytes[offset..(offset + pointer_size)],
-        ).expect("global_initializer: could not read relocation pointer") as u64;
+        ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64;
         llvals.push(primval_to_llvm(
             cx,
             PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }),
@@ -128,25 +171,19 @@ pub fn trans_static_initializer<'a, 'tcx>(
     let param_env = ty::ParamEnv::reveal_all();
     let static_ = cx.tcx.const_eval(param_env.and(cid))?;
 
-    let ptr = match static_.val {
-        ConstVal::Value(MiriValue::ByRef(ptr, _)) => ptr,
+    let val = match static_.val {
+        ConstVal::Value(val) => val,
         _ => bug!("static const eval returned {:#?}", static_),
     };
-
-    let alloc = cx
-        .tcx
-        .interpret_interner
-        .get_alloc(ptr.primval.to_ptr().expect("static has integer pointer").alloc_id)
-        .expect("miri allocation never successfully created");
-    Ok(global_initializer(cx, alloc))
+    Ok(const_value_to_llvm(cx, val, static_.ty))
 }
 
 impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
-    fn const_to_miri_value(
+    fn const_to_const_value(
         &mut self,
         bx: &Builder<'a, 'tcx>,
         constant: &'tcx ty::Const<'tcx>,
-    ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
+    ) -> Result<ConstValue<'tcx>, ConstEvalErr<'tcx>> {
         match constant.val {
             ConstVal::Unevaluated(def_id, ref substs) => {
                 let tcx = bx.tcx();
@@ -157,17 +194,17 @@ fn const_to_miri_value(
                     promoted: None,
                 };
                 let c = tcx.const_eval(param_env.and(cid))?;
-                self.const_to_miri_value(bx, c)
+                self.const_to_const_value(bx, c)
             },
-            ConstVal::Value(miri_val) => Ok(miri_val),
+            ConstVal::Value(val) => Ok(val),
         }
     }
 
-    pub fn mir_constant_to_miri_value(
+    pub fn mir_constant_to_const_value(
         &mut self,
         bx: &Builder<'a, 'tcx>,
         constant: &mir::Constant<'tcx>,
-    ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
+    ) -> Result<ConstValue<'tcx>, ConstEvalErr<'tcx>> {
         match constant.literal {
             mir::Literal::Promoted { index } => {
                 let param_env = ty::ParamEnv::reveal_all();
@@ -180,7 +217,7 @@ pub fn mir_constant_to_miri_value(
             mir::Literal::Value { value } => {
                 Ok(self.monomorphize(&value))
             }
-        }.and_then(|c| self.const_to_miri_value(bx, c))
+        }.and_then(|c| self.const_to_const_value(bx, c))
     }
 
     /// process constant containing SIMD shuffle indices
@@ -189,11 +226,11 @@ pub fn simd_shuffle_indices(
         bx: &Builder<'a, 'tcx>,
         constant: &mir::Constant<'tcx>,
     ) -> (ValueRef, Ty<'tcx>) {
-        self.mir_constant_to_miri_value(bx, constant)
+        self.mir_constant_to_const_value(bx, constant)
             .and_then(|c| {
                 let field_ty = constant.ty.builtin_index().unwrap();
                 let fields = match constant.ty.sty {
-                    ty::TyArray(_, n) => n.val.unwrap_u64(),
+                    ty::TyArray(_, n) => n.unwrap_usize(bx.tcx()),
                     ref other => bug!("invalid simd shuffle type: {}", other),
                 };
                 let values: Result<Vec<ValueRef>, _> = (0..fields).map(|field| {
@@ -206,19 +243,18 @@ pub fn simd_shuffle_indices(
                         c,
                         constant.ty,
                     )?;
-                    match field.val {
-                        ConstVal::Value(MiriValue::ByVal(prim)) => {
-                            let layout = bx.cx.layout_of(field_ty);
-                            let scalar = match layout.abi {
-                                layout::Abi::Scalar(ref x) => x,
-                                _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
-                            };
-                            Ok(primval_to_llvm(
-                                bx.cx, prim, scalar,
-                                layout.immediate_llvm_type(bx.cx),
-                            ))
-                        },
-                        other => bug!("simd shuffle field {:?}, {}", other, constant.ty),
+                    if let Some(prim) = field.to_primval() {
+                        let layout = bx.cx.layout_of(field_ty);
+                        let scalar = match layout.abi {
+                            layout::Abi::Scalar(ref x) => x,
+                            _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
+                        };
+                        Ok(primval_to_llvm(
+                            bx.cx, prim, scalar,
+                            layout.immediate_llvm_type(bx.cx),
+                        ))
+                    } else {
+                        bug!("simd shuffle field {:?}", field)
                     }
                 }).collect();
                 let llval = C_struct(bx.cx, &values?, false);
index 656ab95a28cf3e1730c78092260dc9ec40e9fb90..432ac44e0a5660e2f33f90042b7912a065f4d3e0 100644 (file)
@@ -11,7 +11,7 @@
 use llvm::ValueRef;
 use rustc::middle::const_val::ConstEvalErr;
 use rustc::mir;
-use rustc::mir::interpret::Value as MiriValue;
+use rustc::mir::interpret::ConstValue;
 use rustc::ty;
 use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
 use rustc_data_structures::indexed_vec::Idx;
 use value::Value;
 use type_of::LayoutLlvmExt;
 use type_::Type;
+use consts;
 
 use std::fmt;
 use std::ptr;
 
 use super::{FunctionCx, LocalRef};
-use super::constant::{primval_to_llvm};
+use super::constant::{primval_to_llvm, const_alloc_to_llvm};
 use super::place::PlaceRef;
 
 /// The representation of a Rust value. The enum variant is in fact
@@ -94,7 +95,7 @@ pub fn new_zst(cx: &CodegenCx<'a, 'tcx>,
     }
 
     pub fn from_const(bx: &Builder<'a, 'tcx>,
-                      miri_val: MiriValue,
+                      val: ConstValue<'tcx>,
                       ty: ty::Ty<'tcx>)
                       -> Result<OperandRef<'tcx>, ConstEvalErr<'tcx>> {
         let layout = bx.cx.layout_of(ty);
@@ -103,8 +104,8 @@ pub fn from_const(bx: &Builder<'a, 'tcx>,
             return Ok(OperandRef::new_zst(bx.cx, layout));
         }
 
-        let val = match miri_val {
-            MiriValue::ByVal(x) => {
+        let val = match val {
+            ConstValue::ByVal(x) => {
                 let scalar = match layout.abi {
                     layout::Abi::Scalar(ref x) => x,
                     _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
@@ -117,7 +118,7 @@ pub fn from_const(bx: &Builder<'a, 'tcx>,
                 );
                 OperandValue::Immediate(llval)
             },
-            MiriValue::ByValPair(a, b) => {
+            ConstValue::ByValPair(a, b) => {
                 let (a_scalar, b_scalar) = match layout.abi {
                     layout::Abi::ScalarPair(ref a, ref b) => (a, b),
                     _ => bug!("from_const: invalid ByValPair layout: {:#?}", layout)
@@ -136,18 +137,11 @@ pub fn from_const(bx: &Builder<'a, 'tcx>,
                 );
                 OperandValue::Pair(a_llval, b_llval)
             },
-            MiriValue::ByRef(ptr, align) => {
-                let scalar = layout::Scalar {
-                    value: layout::Primitive::Pointer,
-                    valid_range: 0..=!0
-                };
-                let ptr = primval_to_llvm(
-                    bx.cx,
-                    ptr.into_inner_primval(),
-                    &scalar,
-                    layout.llvm_type(bx.cx).ptr_to(),
-                );
-                return Ok(PlaceRef::new_sized(ptr, layout, align).load(bx));
+            ConstValue::ByRef(alloc) => {
+                let init = const_alloc_to_llvm(bx.cx, alloc);
+                let llval = consts::addr_of(bx.cx, init, layout.align, "byte_str");
+                let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to());
+                return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx));
             },
         };
 
@@ -396,7 +390,7 @@ pub fn trans_operand(&mut self,
 
             mir::Operand::Constant(ref constant) => {
                 let ty = self.monomorphize(&constant.ty);
-                self.mir_constant_to_miri_value(bx, constant)
+                self.mir_constant_to_const_value(bx, constant)
                     .and_then(|c| OperandRef::from_const(bx, c, ty))
                     .unwrap_or_else(|err| {
                         match constant.literal {
index 0cd823391b9b66ed4dd6872afb2f56d6ce51f0bc..3b4477564502c4f11f17e8b6a26af70e5585c7f9 100644 (file)
@@ -516,7 +516,7 @@ fn evaluate_array_len(&mut self,
         if let mir::Place::Local(index) = *place {
             if let LocalRef::Operand(Some(op)) = self.locals[index] {
                 if let ty::TyArray(_, n) = op.layout.ty.sty {
-                    let n = n.val.unwrap_u64();
+                    let n = n.unwrap_usize(bx.cx.tcx);
                     return common::C_usize(bx.cx, n);
                 }
             }
index 93dbba6e873a9d4f807e906dfd8008c2f1335a93..d307ef30044e12f13d9faa92fc3059fe4265765f 100644 (file)
@@ -12,7 +12,6 @@
 //! representation.  The main routine here is `ast_ty_to_ty()`: each use
 //! is parameterized by an instance of `AstConv`.
 
-use rustc::middle::const_val::ConstVal;
 use rustc_data_structures::accumulate_vec::AccumulateVec;
 use hir;
 use hir::def::Def;
@@ -1087,10 +1086,7 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
             hir::TyArray(ref ty, length) => {
                 let length_def_id = tcx.hir.body_owner_def_id(length);
                 let substs = Substs::identity_for_item(tcx, length_def_id);
-                let length = tcx.mk_const(ty::Const {
-                    val: ConstVal::Unevaluated(length_def_id, substs),
-                    ty: tcx.types.usize
-                });
+                let length = ty::Const::unevaluated(tcx, length_def_id, substs, tcx.types.usize);
                 let array_ty = tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length));
                 self.normalize_ty(ast_ty.span, array_ty)
             }
index c7585c827ce11eaf92b0f0cbf59cd5ec1b0ec7a3..2547952d1043cfc8805b3655a1d8b461c3c03ed0 100644 (file)
@@ -375,7 +375,7 @@ pub fn check_pat_walk(
                 let expected_ty = self.structurally_resolved_type(pat.span, expected);
                 let (inner_ty, slice_ty) = match expected_ty.sty {
                     ty::TyArray(inner_ty, size) => {
-                        let size = size.val.unwrap_u64();
+                        let size = size.unwrap_usize(tcx);
                         let min_len = before.len() as u64 + after.len() as u64;
                         if slice.is_none() {
                             if min_len != size {
index ef14fa9a12248eb5a49d189eda474601d617e778..7b859635f60df1f297a04df6c838db4b33106361 100644 (file)
@@ -4018,7 +4018,7 @@ fn check_expr_kind(&self,
             };
 
             if let Ok(count) = count {
-                let zero_or_one = count.val.to_raw_bits().map_or(false, |count| count <= 1);
+                let zero_or_one = count.assert_usize(tcx).map_or(false, |count| count <= 1);
                 if !zero_or_one {
                     // For [foo, ..n] where n > 1, `foo` must have
                     // Copy type:
index 9e8e00594e60afc9074322c7b080ac6c09294f7f..23081b87d2651e4f7ec1bfc1143d9b7d90f0aa7c 100644 (file)
@@ -12,8 +12,8 @@
 
 use super::{FnCtxt, Needs};
 use super::method::MethodCallee;
-use rustc::ty::{self, Ty, TypeFoldable, TypeVariants};
-use rustc::ty::TypeVariants::{TyStr, TyRef, TyAdt};
+use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::TypeVariants::{TyRef, TyAdt, TyStr, TyUint, TyNever, TyTuple, TyChar, TyArray};
 use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::infer::type_variable::TypeVariableOrigin;
 use errors;
@@ -246,76 +246,151 @@ fn check_overloaded_binop(&self,
             Err(()) => {
                 // error types are considered "builtin"
                 if !lhs_ty.references_error() {
-                    if let IsAssign::Yes = is_assign {
-                        struct_span_err!(self.tcx.sess, expr.span, E0368,
-                                         "binary assignment operation `{}=` \
-                                          cannot be applied to type `{}`",
-                                         op.node.as_str(),
-                                         lhs_ty)
-                            .span_label(lhs_expr.span,
-                                        format!("cannot use `{}=` on type `{}`",
-                                        op.node.as_str(), lhs_ty))
-                            .emit();
-                    } else {
-                        let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369,
-                            "binary operation `{}` cannot be applied to type `{}`",
-                            op.node.as_str(),
-                            lhs_ty);
-
-                        if let TypeVariants::TyRef(_, rty, _) = lhs_ty.sty {
-                            if {
-                                !self.infcx.type_moves_by_default(self.param_env,
-                                                                  rty,
-                                                                  lhs_expr.span) &&
-                                    self.lookup_op_method(rty,
-                                                          &[rhs_ty],
-                                                          Op::Binary(op, is_assign))
-                                        .is_ok()
-                            } {
-                                err.note(
-                                    &format!(
-                                        "this is a reference to a type that `{}` can be applied \
-                                        to; you need to dereference this variable once for this \
-                                        operation to work",
-                                    op.node.as_str()));
+                    let codemap = self.tcx.sess.codemap();
+                    match is_assign {
+                        IsAssign::Yes => {
+                            let mut err = struct_span_err!(self.tcx.sess, expr.span, E0368,
+                                                "binary assignment operation `{}=` \
+                                                cannot be applied to type `{}`",
+                                                op.node.as_str(),
+                                                lhs_ty);
+                            err.span_label(lhs_expr.span,
+                                    format!("cannot use `{}=` on type `{}`",
+                                    op.node.as_str(), lhs_ty));
+                            let mut suggested_deref = false;
+                            if let TyRef(_, mut rty, _) = lhs_ty.sty {
+                                if {
+                                    !self.infcx.type_moves_by_default(self.param_env,
+                                                                        rty,
+                                                                        lhs_expr.span) &&
+                                        self.lookup_op_method(rty,
+                                                              &[rhs_ty],
+                                                              Op::Binary(op, is_assign))
+                                            .is_ok()
+                                } {
+                                    if let Ok(lstring) = codemap.span_to_snippet(lhs_expr.span) {
+                                        while let TyRef(_, rty_inner, _) = rty.sty {
+                                            rty = rty_inner;
+                                        }
+                                        let msg = &format!(
+                                                "`{}=` can be used on '{}', you can \
+                                                dereference `{2}`: `*{2}`",
+                                                op.node.as_str(),
+                                                rty,
+                                                lstring
+                                        );
+                                        err.help(msg);
+                                        suggested_deref = true;
+                                    }
+                                }
                             }
+                            let missing_trait = match op.node {
+                                hir::BiAdd    => Some("std::ops::AddAssign"),
+                                hir::BiSub    => Some("std::ops::SubAssign"),
+                                hir::BiMul    => Some("std::ops::MulAssign"),
+                                hir::BiDiv    => Some("std::ops::DivAssign"),
+                                hir::BiRem    => Some("std::ops::RemAssign"),
+                                hir::BiBitAnd => Some("std::ops::BitAndAssign"),
+                                hir::BiBitXor => Some("std::ops::BitXorAssign"),
+                                hir::BiBitOr  => Some("std::ops::BitOrAssign"),
+                                hir::BiShl    => Some("std::ops::ShlAssign"),
+                                hir::BiShr    => Some("std::ops::ShrAssign"),
+                                _             => None
+                            };
+                            if let Some(missing_trait) = missing_trait {
+                                if op.node == hir::BiAdd &&
+                                    self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
+                                                            rhs_ty, &mut err) {
+                                    // This has nothing here because it means we did string
+                                    // concatenation (e.g. "Hello " + "World!"). This means
+                                    // we don't want the note in the else clause to be emitted
+                                } else if let ty::TyParam(_) = lhs_ty.sty {
+                                    // FIXME: point to span of param
+                                    err.note(&format!(
+                                        "`{}` might need a bound for `{}`",
+                                        lhs_ty, missing_trait
+                                    ));
+                                } else if !suggested_deref {
+                                    err.note(&format!(
+                                        "an implementation of `{}` might \
+                                         be missing for `{}`",
+                                        missing_trait, lhs_ty
+                                    ));
+                                }
+                            }
+                            err.emit();
                         }
-
-                        let missing_trait = match op.node {
-                            hir::BiAdd    => Some("std::ops::Add"),
-                            hir::BiSub    => Some("std::ops::Sub"),
-                            hir::BiMul    => Some("std::ops::Mul"),
-                            hir::BiDiv    => Some("std::ops::Div"),
-                            hir::BiRem    => Some("std::ops::Rem"),
-                            hir::BiBitAnd => Some("std::ops::BitAnd"),
-                            hir::BiBitOr  => Some("std::ops::BitOr"),
-                            hir::BiShl    => Some("std::ops::Shl"),
-                            hir::BiShr    => Some("std::ops::Shr"),
-                            hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"),
-                            hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe =>
-                                Some("std::cmp::PartialOrd"),
-                            _             => None
-                        };
-
-                        if let Some(missing_trait) = missing_trait {
-                            if missing_trait == "std::ops::Add" &&
-                                self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
-                                                        rhs_ty, &mut err) {
-                                // This has nothing here because it means we did string
-                                // concatenation (e.g. "Hello " + "World!"). This means
-                                // we don't want the note in the else clause to be emitted
-                            } else if let ty::TyParam(_) = lhs_ty.sty {
-                                // FIXME: point to span of param
-                                err.note(
-                                    &format!("`{}` might need a bound for `{}`",
-                                             lhs_ty, missing_trait));
-                            } else {
-                                err.note(
-                                    &format!("an implementation of `{}` might be missing for `{}`",
-                                             missing_trait, lhs_ty));
+                        IsAssign::No => {
+                            let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369,
+                                            "binary operation `{}` cannot be applied to type `{}`",
+                                            op.node.as_str(),
+                                            lhs_ty);
+                            let mut suggested_deref = false;
+                            if let TyRef(_, mut rty, _) = lhs_ty.sty {
+                                if {
+                                    !self.infcx.type_moves_by_default(self.param_env,
+                                                                        rty,
+                                                                        lhs_expr.span) &&
+                                        self.lookup_op_method(rty,
+                                                              &[rhs_ty],
+                                                              Op::Binary(op, is_assign))
+                                            .is_ok()
+                                } {
+                                    if let Ok(lstring) = codemap.span_to_snippet(lhs_expr.span) {
+                                        while let TyRef(_, rty_inner, _) = rty.sty {
+                                            rty = rty_inner;
+                                        }
+                                        let msg = &format!(
+                                                "`{}` can be used on '{}', you can \
+                                                dereference `{2}`: `*{2}`",
+                                                op.node.as_str(),
+                                                rty,
+                                                lstring
+                                        );
+                                        err.help(msg);
+                                        suggested_deref = true;
+                                    }
+                                }
                             }
+                            let missing_trait = match op.node {
+                                hir::BiAdd    => Some("std::ops::Add"),
+                                hir::BiSub    => Some("std::ops::Sub"),
+                                hir::BiMul    => Some("std::ops::Mul"),
+                                hir::BiDiv    => Some("std::ops::Div"),
+                                hir::BiRem    => Some("std::ops::Rem"),
+                                hir::BiBitAnd => Some("std::ops::BitAnd"),
+                                hir::BiBitXor => Some("std::ops::BitXor"),
+                                hir::BiBitOr  => Some("std::ops::BitOr"),
+                                hir::BiShl    => Some("std::ops::Shl"),
+                                hir::BiShr    => Some("std::ops::Shr"),
+                                hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"),
+                                hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe =>
+                                    Some("std::cmp::PartialOrd"),
+                                _             => None
+                            };
+                            if let Some(missing_trait) = missing_trait {
+                                if op.node == hir::BiAdd &&
+                                    self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
+                                                            rhs_ty, &mut err) {
+                                    // This has nothing here because it means we did string
+                                    // concatenation (e.g. "Hello " + "World!"). This means
+                                    // we don't want the note in the else clause to be emitted
+                                } else if let ty::TyParam(_) = lhs_ty.sty {
+                                    // FIXME: point to span of param
+                                    err.note(&format!(
+                                        "`{}` might need a bound for `{}`",
+                                        lhs_ty, missing_trait
+                                    ));
+                                } else if !suggested_deref {
+                                    err.note(&format!(
+                                        "an implementation of `{}` might \
+                                         be missing for `{}`",
+                                        missing_trait, lhs_ty
+                                    ));
+                                }
+                            }
+                            err.emit();
                         }
-                        err.emit();
                     }
                 }
                 self.tcx.types.err
@@ -393,9 +468,29 @@ pub fn check_user_unop(&self,
             Err(()) => {
                 let actual = self.resolve_type_vars_if_possible(&operand_ty);
                 if !actual.references_error() {
-                    struct_span_err!(self.tcx.sess, ex.span, E0600,
+                    let mut err = struct_span_err!(self.tcx.sess, ex.span, E0600,
                                      "cannot apply unary operator `{}` to type `{}`",
-                                     op.as_str(), actual).emit();
+                                     op.as_str(), actual);
+                    err.span_label(ex.span, format!("cannot apply unary \
+                                                    operator `{}`", op.as_str()));
+                    match actual.sty {
+                        TyUint(_) if op == hir::UnNeg => {
+                            err.note(&format!("unsigned values cannot be negated"));
+                        },
+                        TyStr | TyNever | TyChar | TyTuple(_) | TyArray(_,_) => {},
+                        TyRef(_, ref lty, _) if lty.sty == TyStr => {},
+                        _ => {
+                            let missing_trait = match op {
+                                hir::UnNeg => "std::ops::Neg",
+                                hir::UnNot => "std::ops::Not",
+                                hir::UnDeref => "std::ops::UnDerf"
+                            };
+                            err.note(&format!("an implementation of `{}` might \
+                                                be missing for `{}`",
+                                             missing_trait, operand_ty));
+                        }
+                    }
+                    err.emit();
                 }
                 self.tcx.types.err
             }
index 3424a31e09df09245058b1315be2b9c54450c6c2..2f08a54e10f08839b6cffbb4d58899f9d42af86f 100644 (file)
@@ -111,9 +111,9 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     debug!("visit_implementation_of_copy: self_type={:?} (free)",
            self_type);
 
-    match param_env.can_type_implement_copy(tcx, self_type, span) {
+    match param_env.can_type_implement_copy(tcx, self_type) {
         Ok(()) => {}
-        Err(CopyImplementationError::InfrigingField(field)) => {
+        Err(CopyImplementationError::InfrigingFields(fields)) => {
             let item = tcx.hir.expect_item(impl_node_id);
             let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node {
                 tr.path.span
@@ -121,14 +121,14 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 span
             };
 
-            struct_span_err!(tcx.sess,
-                             span,
-                             E0204,
-                             "the trait `Copy` may not be implemented for this type")
-                .span_label(
-                    tcx.def_span(field.did),
-                    "this field does not implement `Copy`")
-                .emit()
+            let mut err = struct_span_err!(tcx.sess,
+                                          span,
+                                          E0204,
+                                          "the trait `Copy` may not be implemented for this type");
+            for span in fields.iter().map(|f| tcx.def_span(f.did)) {
+                    err.span_label(span, "this field does not implement `Copy`");
+            }
+            err.emit()
         }
         Err(CopyImplementationError::NotAnAdt) => {
             let item = tcx.hir.expect_item(impl_node_id);
index 007938e86ed9d9f37addd9624cd71b897b7c8c1a..7d3ba792829382c75d6f613225f906aa1882dc9a 100644 (file)
@@ -697,7 +697,7 @@ fn from_iter<T>(iter: T) -> Self
 pub struct Attributes {
     pub doc_strings: Vec<DocFragment>,
     pub other_attrs: Vec<ast::Attribute>,
-    pub cfg: Option<Rc<Cfg>>,
+    pub cfg: Option<Arc<Cfg>>,
     pub span: Option<syntax_pos::Span>,
     /// map from Rust paths to resolved defs and potential URL fragments
     pub links: Vec<(String, Option<DefId>, Option<String>)>,
@@ -848,7 +848,7 @@ pub fn from_ast(diagnostic: &::errors::Handler,
         Attributes {
             doc_strings,
             other_attrs,
-            cfg: if cfg == Cfg::True { None } else { Some(Rc::new(cfg)) },
+            cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) },
             span: sp,
             links: vec![],
         }
@@ -2644,10 +2644,7 @@ fn clean(&self, cx: &DocContext) -> Type {
                     promoted: None
                 };
                 let n = cx.tcx.const_eval(param_env.and(cid)).unwrap_or_else(|_| {
-                    cx.tcx.mk_const(ty::Const {
-                        val: ConstVal::Unevaluated(def_id, substs),
-                        ty: cx.tcx.types.usize
-                    })
+                    ty::Const::unevaluated(cx.tcx, def_id, substs, cx.tcx.types.usize)
                 });
                 let n = print_const(cx, n);
                 Array(box ty.clean(cx), n)
@@ -3828,9 +3825,9 @@ fn print_const(cx: &DocContext, n: &ty::Const) -> String {
                 inline::print_inlined_const(cx, def_id)
             }
         },
-        ConstVal::Value(val) => {
+        ConstVal::Value(..) => {
             let mut s = String::new();
-            ::rustc::mir::print_miri_value(val, n.ty, &mut s).unwrap();
+            ::rustc::mir::fmt_const_val(&mut s, n).unwrap();
             // array lengths are obviously usize
             if s.ends_with("usize") {
                 let n = s.len() - "usize".len();
index 61fb0b40c231560b8005af5f1997b706a41f190e..6222edd5450f05cc1facd4fe4271816daab71d5a 100644 (file)
@@ -161,161 +161,162 @@ pub fn run_core(search_paths: SearchPaths,
         edition,
         ..config::basic_options().clone()
     };
-
-    let codemap = Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping()));
-    let emitter: Box<dyn Emitter + sync::Send> = match error_format {
-        ErrorOutputType::HumanReadable(color_config) => Box::new(
-            EmitterWriter::stderr(
-                color_config,
-                Some(codemap.clone()),
-                false,
-                sessopts.debugging_opts.teach,
-            ).ui_testing(sessopts.debugging_opts.ui_testing)
-        ),
-        ErrorOutputType::Json(pretty) => Box::new(
-            JsonEmitter::stderr(
-                None,
-                codemap.clone(),
-                pretty,
-                sessopts.debugging_opts.suggestion_applicability,
-            ).ui_testing(sessopts.debugging_opts.ui_testing)
-        ),
-        ErrorOutputType::Short(color_config) => Box::new(
-            EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false)
-        ),
-    };
-
-    let diagnostic_handler = errors::Handler::with_emitter_and_flags(
-        emitter,
-        errors::HandlerFlags {
-            can_emit_warnings: true,
-            treat_err_as_bug: false,
-            external_macro_backtrace: false,
-            ..Default::default()
-        },
-    );
-
-    let mut sess = session::build_session_(
-        sessopts, cpath, diagnostic_handler, codemap,
-    );
-    let trans = rustc_driver::get_trans(&sess);
-    let cstore = Rc::new(CStore::new(trans.metadata_loader()));
-    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-
-    let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs));
-    target_features::add_configuration(&mut cfg, &sess, &*trans);
-    sess.parse_sess.config = cfg;
-
-    let control = &driver::CompileController::basic();
-
-    let krate = panictry!(driver::phase_1_parse_input(control, &sess, &input));
-
-    let name = ::rustc_trans_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input);
-
-    let mut crate_loader = CrateLoader::new(&sess, &cstore, &name);
-
-    let resolver_arenas = resolve::Resolver::arenas();
-    let result = driver::phase_2_configure_and_expand_inner(&sess,
-                                                      &cstore,
-                                                      krate,
-                                                      None,
-                                                      &name,
-                                                      None,
-                                                      resolve::MakeGlobMap::No,
-                                                      &resolver_arenas,
-                                                      &mut crate_loader,
-                                                      |_| Ok(()));
-    let driver::InnerExpansionResult {
-        mut hir_forest,
-        resolver,
-        ..
-    } = abort_on_err(result, &sess);
-
-    // We need to hold on to the complete resolver, so we clone everything
-    // for the analysis passes to use. Suboptimal, but necessary in the
-    // current architecture.
-    let defs = resolver.definitions.clone();
-    let resolutions = ty::Resolutions {
-        freevars: resolver.freevars.clone(),
-        export_map: resolver.export_map.clone(),
-        trait_map: resolver.trait_map.clone(),
-        maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(),
-        maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(),
-    };
-    let analysis = ty::CrateAnalysis {
-        access_levels: Lrc::new(AccessLevels::default()),
-        name: name.to_string(),
-        glob_map: if resolver.make_glob_map { Some(resolver.glob_map.clone()) } else { None },
-    };
-
-    let arenas = AllArenas::new();
-    let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
-    let output_filenames = driver::build_output_filenames(&input,
-                                                          &None,
-                                                          &None,
-                                                          &[],
-                                                          &sess);
-
-    let resolver = RefCell::new(resolver);
-
-    abort_on_err(driver::phase_3_run_analysis_passes(&*trans,
-                                                     control,
-                                                     &sess,
-                                                     &*cstore,
-                                                     hir_map,
-                                                     analysis,
-                                                     resolutions,
-                                                     &arenas,
-                                                     &name,
-                                                     &output_filenames,
-                                                     |tcx, analysis, _, result| {
-        if let Err(_) = result {
-            sess.fatal("Compilation failed, aborting rustdoc");
-        }
-
-        let ty::CrateAnalysis { access_levels, .. } = analysis;
-
-        // Convert from a NodeId set to a DefId set since we don't always have easy access
-        // to the map from defid -> nodeid
-        let access_levels = AccessLevels {
-            map: access_levels.map.iter()
-                                  .map(|(&k, &v)| (tcx.hir.local_def_id(k), v))
-                                  .collect()
+    driver::spawn_thread_pool(sessopts, move |sessopts| {
+        let codemap = Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping()));
+        let emitter: Box<dyn Emitter + sync::Send> = match error_format {
+            ErrorOutputType::HumanReadable(color_config) => Box::new(
+                EmitterWriter::stderr(
+                    color_config,
+                    Some(codemap.clone()),
+                    false,
+                    sessopts.debugging_opts.teach,
+                ).ui_testing(sessopts.debugging_opts.ui_testing)
+            ),
+            ErrorOutputType::Json(pretty) => Box::new(
+                JsonEmitter::stderr(
+                    None,
+                    codemap.clone(),
+                    pretty,
+                    sessopts.debugging_opts.suggestion_applicability,
+                ).ui_testing(sessopts.debugging_opts.ui_testing)
+            ),
+            ErrorOutputType::Short(color_config) => Box::new(
+                EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false)
+            ),
         };
 
-        let send_trait = if crate_name == Some("core".to_string()) {
-            clean::get_trait_def_id(&tcx, &["marker", "Send"], true)
-        } else {
-            clean::get_trait_def_id(&tcx, &["core", "marker", "Send"], false)
+        let diagnostic_handler = errors::Handler::with_emitter_and_flags(
+            emitter,
+            errors::HandlerFlags {
+                can_emit_warnings: true,
+                treat_err_as_bug: false,
+                external_macro_backtrace: false,
+                ..Default::default()
+            },
+        );
+
+        let mut sess = session::build_session_(
+            sessopts, cpath, diagnostic_handler, codemap,
+        );
+        let trans = rustc_driver::get_trans(&sess);
+        let cstore = Rc::new(CStore::new(trans.metadata_loader()));
+        rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+
+        let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs));
+        target_features::add_configuration(&mut cfg, &sess, &*trans);
+        sess.parse_sess.config = cfg;
+
+        let control = &driver::CompileController::basic();
+
+        let krate = panictry!(driver::phase_1_parse_input(control, &sess, &input));
+
+        let name = ::rustc_trans_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input);
+
+        let mut crate_loader = CrateLoader::new(&sess, &cstore, &name);
+
+        let resolver_arenas = resolve::Resolver::arenas();
+        let result = driver::phase_2_configure_and_expand_inner(&sess,
+                                                        &cstore,
+                                                        krate,
+                                                        None,
+                                                        &name,
+                                                        None,
+                                                        resolve::MakeGlobMap::No,
+                                                        &resolver_arenas,
+                                                        &mut crate_loader,
+                                                        |_| Ok(()));
+        let driver::InnerExpansionResult {
+            mut hir_forest,
+            resolver,
+            ..
+        } = abort_on_err(result, &sess);
+
+        // We need to hold on to the complete resolver, so we clone everything
+        // for the analysis passes to use. Suboptimal, but necessary in the
+        // current architecture.
+        let defs = resolver.definitions.clone();
+        let resolutions = ty::Resolutions {
+            freevars: resolver.freevars.clone(),
+            export_map: resolver.export_map.clone(),
+            trait_map: resolver.trait_map.clone(),
+            maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(),
+            maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(),
         };
-
-        let ctxt = DocContext {
-            tcx,
-            resolver: &resolver,
-            crate_name,
-            cstore: cstore.clone(),
-            populated_all_crate_impls: Cell::new(false),
-            access_levels: RefCell::new(access_levels),
-            external_traits: Default::default(),
-            active_extern_traits: Default::default(),
-            renderinfo: Default::default(),
-            ty_substs: Default::default(),
-            lt_substs: Default::default(),
-            impl_trait_bounds: Default::default(),
-            mod_ids: Default::default(),
-            send_trait: send_trait,
-            fake_def_ids: RefCell::new(FxHashMap()),
-            all_fake_def_ids: RefCell::new(FxHashSet()),
-            generated_synthetics: RefCell::new(FxHashSet()),
-        };
-        debug!("crate: {:?}", tcx.hir.krate());
-
-        let krate = {
-            let mut v = RustdocVisitor::new(&*cstore, &ctxt);
-            v.visit(tcx.hir.krate());
-            v.clean(&ctxt)
+        let analysis = ty::CrateAnalysis {
+            access_levels: Lrc::new(AccessLevels::default()),
+            name: name.to_string(),
+            glob_map: if resolver.make_glob_map { Some(resolver.glob_map.clone()) } else { None },
         };
 
-        (krate, ctxt.renderinfo.into_inner())
-    }), &sess)
+        let arenas = AllArenas::new();
+        let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
+        let output_filenames = driver::build_output_filenames(&input,
+                                                            &None,
+                                                            &None,
+                                                            &[],
+                                                            &sess);
+
+        let resolver = RefCell::new(resolver);
+
+        abort_on_err(driver::phase_3_run_analysis_passes(&*trans,
+                                                        control,
+                                                        &sess,
+                                                        &*cstore,
+                                                        hir_map,
+                                                        analysis,
+                                                        resolutions,
+                                                        &arenas,
+                                                        &name,
+                                                        &output_filenames,
+                                                        |tcx, analysis, _, result| {
+            if let Err(_) = result {
+                sess.fatal("Compilation failed, aborting rustdoc");
+            }
+
+            let ty::CrateAnalysis { access_levels, .. } = analysis;
+
+            // Convert from a NodeId set to a DefId set since we don't always have easy access
+            // to the map from defid -> nodeid
+            let access_levels = AccessLevels {
+                map: access_levels.map.iter()
+                                    .map(|(&k, &v)| (tcx.hir.local_def_id(k), v))
+                                    .collect()
+            };
+
+            let send_trait = if crate_name == Some("core".to_string()) {
+                clean::get_trait_def_id(&tcx, &["marker", "Send"], true)
+            } else {
+                clean::get_trait_def_id(&tcx, &["core", "marker", "Send"], false)
+            };
+
+            let ctxt = DocContext {
+                tcx,
+                resolver: &resolver,
+                crate_name,
+                cstore: cstore.clone(),
+                populated_all_crate_impls: Cell::new(false),
+                access_levels: RefCell::new(access_levels),
+                external_traits: Default::default(),
+                active_extern_traits: Default::default(),
+                renderinfo: Default::default(),
+                ty_substs: Default::default(),
+                lt_substs: Default::default(),
+                impl_trait_bounds: Default::default(),
+                mod_ids: Default::default(),
+                send_trait: send_trait,
+                fake_def_ids: RefCell::new(FxHashMap()),
+                all_fake_def_ids: RefCell::new(FxHashSet()),
+                generated_synthetics: RefCell::new(FxHashSet()),
+            };
+            debug!("crate: {:?}", tcx.hir.krate());
+
+            let krate = {
+                let mut v = RustdocVisitor::new(&*cstore, &ctxt);
+                v.visit(tcx.hir.krate());
+                v.clean(&ctxt)
+            };
+
+            (krate, ctxt.renderinfo.into_inner())
+        }), &sess)
+    })
 }
index 21de2db1dfe74fd7bf1930e06b38b3e20589b31b..fe9fc3ddd680ee5626cc42d67ae4b53daaf18c35 100644 (file)
@@ -2579,7 +2579,7 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
 }
 
 fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter,
-                      implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> Result<(), fmt::Error> {
+                      implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> fmt::Result {
     write!(w, "<li><table class='table-display'><tbody><tr><td><code>")?;
     // If there's already another implementor that has the same abbridged name, use the
     // full path, for example in `std::iter::ExactSizeIterator`
@@ -2612,7 +2612,7 @@ fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter,
 
 fn render_impls(cx: &Context, w: &mut fmt::Formatter,
                 traits: &[&&Impl],
-                containing_item: &clean::Item) -> Result<(), fmt::Error> {
+                containing_item: &clean::Item) -> fmt::Result {
     for i in traits {
         let did = i.trait_did().unwrap();
         let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
index 059d41698953d2a4fcb85e36b1e45fd7e264ffa8..f2da09e16036ea05f9b56ca87c2645de6fd95bbe 100644 (file)
@@ -26,6 +26,8 @@
 #![feature(vec_remove_item)]
 #![feature(entry_and_modify)]
 
+#![recursion_limit="256"]
+
 extern crate arena;
 extern crate getopts;
 extern crate env_logger;
index 9e65fff5e2ac6f3f65c04f9a3af106a9e708c65a..fc8abafd4d89b549cb71e4b139f1a8532abec4d0 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::rc::Rc;
+use std::sync::Arc;
 
 use clean::{Crate, Item};
 use clean::cfg::Cfg;
@@ -20,7 +20,7 @@ pub fn propagate_doc_cfg(cr: Crate) -> PluginResult {
 }
 
 struct CfgPropagator {
-    parent_cfg: Option<Rc<Cfg>>,
+    parent_cfg: Option<Arc<Cfg>>,
 }
 
 impl DocFolder for CfgPropagator {
@@ -31,8 +31,8 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
             (None, None) => None,
             (Some(rc), None) | (None, Some(rc)) => Some(rc),
             (Some(mut a), Some(b)) => {
-                let b = Rc::try_unwrap(b).unwrap_or_else(|rc| Cfg::clone(&rc));
-                *Rc::make_mut(&mut a) &= b;
+                let b = Arc::try_unwrap(b).unwrap_or_else(|rc| Cfg::clone(&rc));
+                *Arc::make_mut(&mut a) &= b;
                 Some(a)
             }
         };
index c4eaa48e49db62e47c6bb0bb3c4fc64b32f2871d..7be7ce313fcffcbc738bde5667ed6c7a1b31efdf 100644 (file)
@@ -85,77 +85,80 @@ pub fn run(input_path: &Path,
         edition,
         ..config::basic_options().clone()
     };
-
-    let codemap = Lrc::new(CodeMap::new(sessopts.file_path_mapping()));
-    let handler =
-        errors::Handler::with_tty_emitter(ColorConfig::Auto,
-                                          true, false,
-                                          Some(codemap.clone()));
-
-    let mut sess = session::build_session_(
-        sessopts, Some(input_path.to_owned()), handler, codemap.clone(),
-    );
-    let trans = rustc_driver::get_trans(&sess);
-    let cstore = CStore::new(trans.metadata_loader());
-    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-
-    let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
-    target_features::add_configuration(&mut cfg, &sess, &*trans);
-    sess.parse_sess.config = cfg;
-
-    let krate = panictry!(driver::phase_1_parse_input(&driver::CompileController::basic(),
-                                                      &sess,
-                                                      &input));
-    let driver::ExpansionResult { defs, mut hir_forest, .. } = {
-        phase_2_configure_and_expand(
-            &sess,
-            &cstore,
-            krate,
-            None,
-            "rustdoc-test",
-            None,
-            MakeGlobMap::No,
-            |_| Ok(()),
-        ).expect("phase_2_configure_and_expand aborted in rustdoc!")
-    };
-
-    let crate_name = crate_name.unwrap_or_else(|| {
-        ::rustc_trans_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input)
-    });
-    let mut opts = scrape_test_config(hir_forest.krate());
-    opts.display_warnings |= display_warnings;
-    let mut collector = Collector::new(crate_name,
-                                       cfgs,
-                                       libs,
-                                       cg,
-                                       externs,
-                                       false,
-                                       opts,
-                                       maybe_sysroot,
-                                       Some(codemap),
-                                       None,
-                                       linker,
-                                       edition);
-
-    {
-        let map = hir::map::map_crate(&sess, &cstore, &mut hir_forest, &defs);
-        let krate = map.krate();
-        let mut hir_collector = HirCollector {
-            sess: &sess,
-            collector: &mut collector,
-            map: &map
+    driver::spawn_thread_pool(sessopts, |sessopts| {
+        let codemap = Lrc::new(CodeMap::new(sessopts.file_path_mapping()));
+        let handler =
+            errors::Handler::with_tty_emitter(ColorConfig::Auto,
+                                            true, false,
+                                            Some(codemap.clone()));
+
+        let mut sess = session::build_session_(
+            sessopts, Some(input_path.to_owned()), handler, codemap.clone(),
+        );
+        let trans = rustc_driver::get_trans(&sess);
+        let cstore = CStore::new(trans.metadata_loader());
+        rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+
+        let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
+        target_features::add_configuration(&mut cfg, &sess, &*trans);
+        sess.parse_sess.config = cfg;
+
+        let krate = panictry!(driver::phase_1_parse_input(&driver::CompileController::basic(),
+                                                        &sess,
+                                                        &input));
+        let driver::ExpansionResult { defs, mut hir_forest, .. } = {
+            phase_2_configure_and_expand(
+                &sess,
+                &cstore,
+                krate,
+                None,
+                "rustdoc-test",
+                None,
+                MakeGlobMap::No,
+                |_| Ok(()),
+            ).expect("phase_2_configure_and_expand aborted in rustdoc!")
         };
-        hir_collector.visit_testable("".to_string(), &krate.attrs, |this| {
-            intravisit::walk_crate(this, krate);
+
+        let crate_name = crate_name.unwrap_or_else(|| {
+            ::rustc_trans_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input)
         });
-    }
+        let mut opts = scrape_test_config(hir_forest.krate());
+        opts.display_warnings |= display_warnings;
+        let mut collector = Collector::new(
+            crate_name,
+            cfgs,
+            libs,
+            cg,
+            externs,
+            false,
+            opts,
+            maybe_sysroot,
+            Some(codemap),
+             None,
+            linker,
+            edition
+        );
+
+        {
+            let map = hir::map::map_crate(&sess, &cstore, &mut hir_forest, &defs);
+            let krate = map.krate();
+            let mut hir_collector = HirCollector {
+                sess: &sess,
+                collector: &mut collector,
+                map: &map
+            };
+            hir_collector.visit_testable("".to_string(), &krate.attrs, |this| {
+                intravisit::walk_crate(this, krate);
+            });
+        }
 
-    test_args.insert(0, "rustdoctest".to_string());
+        test_args.insert(0, "rustdoctest".to_string());
 
-    testing::test_main(&test_args,
-                       collector.tests.into_iter().collect(),
-                       testing::Options::new().display_output(display_warnings));
-    0
+        testing::test_main(&test_args,
+                        collector.tests.into_iter().collect(),
+                        testing::Options::new().display_output(display_warnings));
+        0
+    })
 }
 
 // Look for #![doc(test(no_crate_inject))], used by crates in the std facade
@@ -229,102 +232,106 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize,
         ..config::basic_options().clone()
     };
 
-    // Shuffle around a few input and output handles here. We're going to pass
-    // an explicit handle into rustc to collect output messages, but we also
-    // want to catch the error message that rustc prints when it fails.
-    //
-    // We take our thread-local stderr (likely set by the test runner) and replace
-    // it with a sink that is also passed to rustc itself. When this function
-    // returns the output of the sink is copied onto the output of our own thread.
-    //
-    // The basic idea is to not use a default Handler for rustc, and then also
-    // not print things by default to the actual stderr.
-    struct Sink(Arc<Mutex<Vec<u8>>>);
-    impl Write for Sink {
-        fn write(&mut self, data: &[u8]) -> io::Result<usize> {
-            Write::write(&mut *self.0.lock().unwrap(), data)
+    let (libdir, outdir) = driver::spawn_thread_pool(sessopts, |sessopts| {
+        // Shuffle around a few input and output handles here. We're going to pass
+        // an explicit handle into rustc to collect output messages, but we also
+        // want to catch the error message that rustc prints when it fails.
+        //
+        // We take our thread-local stderr (likely set by the test runner) and replace
+        // it with a sink that is also passed to rustc itself. When this function
+        // returns the output of the sink is copied onto the output of our own thread.
+        //
+        // The basic idea is to not use a default Handler for rustc, and then also
+        // not print things by default to the actual stderr.
+        struct Sink(Arc<Mutex<Vec<u8>>>);
+        impl Write for Sink {
+            fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+                Write::write(&mut *self.0.lock().unwrap(), data)
+            }
+            fn flush(&mut self) -> io::Result<()> { Ok(()) }
         }
-        fn flush(&mut self) -> io::Result<()> { Ok(()) }
-    }
-    struct Bomb(Arc<Mutex<Vec<u8>>>, Box<Write+Send>);
-    impl Drop for Bomb {
-        fn drop(&mut self) {
-            let _ = self.1.write_all(&self.0.lock().unwrap());
+        struct Bomb(Arc<Mutex<Vec<u8>>>, Box<Write+Send>);
+        impl Drop for Bomb {
+            fn drop(&mut self) {
+                let _ = self.1.write_all(&self.0.lock().unwrap());
+            }
         }
-    }
-    let data = Arc::new(Mutex::new(Vec::new()));
-    let codemap = Lrc::new(CodeMap::new_doctest(
-        sessopts.file_path_mapping(), filename.clone(), line as isize - line_offset as isize
-    ));
-    let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
-                                                      Some(codemap.clone()),
-                                                      false,
-                                                      false);
-    let old = io::set_panic(Some(box Sink(data.clone())));
-    let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
-
-    // Compile the code
-    let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
-
-    let mut sess = session::build_session_(
-        sessopts, None, diagnostic_handler, codemap,
-    );
-    let trans = rustc_driver::get_trans(&sess);
-    let cstore = CStore::new(trans.metadata_loader());
-    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-
-    let outdir = Mutex::new(TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir"));
-    let libdir = sess.target_filesearch(PathKind::All).get_lib_path();
-    let mut control = driver::CompileController::basic();
-
-    let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
-    target_features::add_configuration(&mut cfg, &sess, &*trans);
-    sess.parse_sess.config = cfg;
-
-    let out = Some(outdir.lock().unwrap().path().to_path_buf());
-
-    if no_run {
-        control.after_analysis.stop = Compilation::Stop;
-    }
-
-    let res = panic::catch_unwind(AssertUnwindSafe(|| {
-        driver::compile_input(
-            trans,
-            &sess,
-            &cstore,
-            &None,
-            &input,
-            &out,
-            &None,
-            None,
-            &control
-        )
-    }));
-
-    let compile_result = match res {
-        Ok(Ok(())) | Ok(Err(CompileIncomplete::Stopped)) => Ok(()),
-        Err(_) | Ok(Err(CompileIncomplete::Errored(_))) => Err(())
-    };
-
-    match (compile_result, compile_fail) {
-        (Ok(()), true) => {
-            panic!("test compiled while it wasn't supposed to")
+        let data = Arc::new(Mutex::new(Vec::new()));
+        let codemap = Lrc::new(CodeMap::new_doctest(
+            sessopts.file_path_mapping(), filename.clone(), line as isize - line_offset as isize
+        ));
+        let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
+                                                        Some(codemap.clone()),
+                                                        false,
+                                                        false);
+        let old = io::set_panic(Some(box Sink(data.clone())));
+        let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
+
+        // Compile the code
+        let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
+
+        let mut sess = session::build_session_(
+            sessopts, None, diagnostic_handler, codemap,
+        );
+        let trans = rustc_driver::get_trans(&sess);
+        let cstore = CStore::new(trans.metadata_loader());
+        rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+
+        let outdir = Mutex::new(TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir"));
+        let libdir = sess.target_filesearch(PathKind::All).get_lib_path();
+        let mut control = driver::CompileController::basic();
+
+        let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
+        target_features::add_configuration(&mut cfg, &sess, &*trans);
+        sess.parse_sess.config = cfg;
+
+        let out = Some(outdir.lock().unwrap().path().to_path_buf());
+
+        if no_run {
+            control.after_analysis.stop = Compilation::Stop;
         }
-        (Ok(()), false) => {}
-        (Err(()), true) => {
-            if error_codes.len() > 0 {
-                let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap();
-                error_codes.retain(|err| !out.contains(err));
+
+        let res = panic::catch_unwind(AssertUnwindSafe(|| {
+            driver::compile_input(
+                trans,
+                &sess,
+                &cstore,
+                &None,
+                &input,
+                &out,
+                &None,
+                None,
+                &control
+            )
+        }));
+
+        let compile_result = match res {
+            Ok(Ok(())) | Ok(Err(CompileIncomplete::Stopped)) => Ok(()),
+            Err(_) | Ok(Err(CompileIncomplete::Errored(_))) => Err(())
+        };
+
+        match (compile_result, compile_fail) {
+            (Ok(()), true) => {
+                panic!("test compiled while it wasn't supposed to")
+            }
+            (Ok(()), false) => {}
+            (Err(()), true) => {
+                if error_codes.len() > 0 {
+                    let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap();
+                    error_codes.retain(|err| !out.contains(err));
+                }
+            }
+            (Err(()), false) => {
+                panic!("couldn't compile the test")
             }
         }
-        (Err(()), false) => {
-            panic!("couldn't compile the test")
+
+        if error_codes.len() > 0 {
+            panic!("Some expected error codes were not found: {:?}", error_codes);
         }
-    }
 
-    if error_codes.len() > 0 {
-        panic!("Some expected error codes were not found: {:?}", error_codes);
-    }
+        (libdir, outdir)
+    });
 
     if no_run { return }
 
index 7bd1adc411ae4b1c0f19009c51f0faf1ff046643..442a0873ae075ad550e983747d6d91a06ecab75a 100644 (file)
@@ -331,6 +331,7 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
 ///
 /// fn main() -> std::io::Result<()> {
 ///     fs::write("foo.txt", b"Lorem ipsum")?;
+///     fs::write("bar.txt", "dolor sit")?;
 ///     Ok(())
 /// }
 /// ```
@@ -1699,8 +1700,8 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
     fs_imp::readlink(path.as_ref())
 }
 
-/// Returns the canonical form of a path with all intermediate components
-/// normalized and symbolic links resolved.
+/// Returns the canonical, absolute form of a path with all intermediate
+/// components normalized and symbolic links resolved.
 ///
 /// # Platform-specific behavior
 ///
@@ -1708,7 +1709,14 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
 /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows.
 /// Note that, this [may change in the future][changes].
 ///
+/// On Windows, this converts the path to use [extended length path][path]
+/// syntax, which allows your program to use longer path names, but means you
+/// can only join backslash-delimited paths to it, and it may be incompatible
+/// with other applications (if passed to the application on the command-line,
+/// or written to a file another application may read).
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
+/// [path]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
 ///
 /// # Errors
 ///
index 696711a70d4f6408cc773abf87d04ed932e64b02..86478f0a523190fc6abc64772241f2c555d7fd4a 100644 (file)
@@ -1460,7 +1460,7 @@ fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Debug for PathBuf {
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         fmt::Debug::fmt(&**self, formatter)
     }
 }
@@ -2284,8 +2284,8 @@ pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
         fs::symlink_metadata(self)
     }
 
-    /// Returns the canonical form of the path with all intermediate components
-    /// normalized and symbolic links resolved.
+    /// Returns the canonical, absolute form of the path with all intermediate
+    /// components normalized and symbolic links resolved.
     ///
     /// This is an alias to [`fs::canonicalize`].
     ///
index d8d78d550162ae3ef0f6750b8b82d39b3095bec1..1ef79547431f8ac0a23d9e3a85d92c288da346fa 100644 (file)
@@ -48,13 +48,13 @@ pub fn text(&self) -> &str {
 }
 
 impl fmt::Debug for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.write_str(self.text())
     }
 }
 
 impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.write_str(self.text())
     }
 }
index 5dafc3251e7551e10f6c68573b479a16cd2efbf6..67546d06b4e55055d98b767d0cd1b6a4fec43b5a 100644 (file)
@@ -75,8 +75,15 @@ pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
         unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
             -> io::Result<isize>
         {
+            use convert::TryInto;
             use libc::pread64;
-            cvt(pread64(fd, buf, count, offset as i32))
+            // pread64 on emscripten actually takes a 32 bit offset
+            if let Ok(o) = offset.try_into() {
+                cvt(pread64(fd, buf, count, o))
+            } else {
+                Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                   "cannot pread >2GB"))
+            }
         }
 
         #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
@@ -116,8 +123,15 @@ pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
         unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
             -> io::Result<isize>
         {
+            use convert::TryInto;
             use libc::pwrite64;
-            cvt(pwrite64(fd, buf, count, offset as i32))
+            // pwrite64 on emscripten actually takes a 32 bit offset
+            if let Ok(o) = offset.try_into() {
+                cvt(pwrite64(fd, buf, count, o))
+            } else {
+                Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                   "cannot pwrite >2GB"))
+            }
         }
 
         #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
index fe7e058091ed5fe1c6cf871817f879892f5ead2d..14a2555adf9baa109e7d7afe08bbea07e685826a 100644 (file)
@@ -56,7 +56,7 @@ pub struct CodePoint {
 /// Example: `U+1F4A9`
 impl fmt::Debug for CodePoint {
     #[inline]
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         write!(formatter, "U+{:04X}", self.value)
     }
 }
@@ -144,7 +144,7 @@ fn deref_mut(&mut self) -> &mut Wtf8 {
 /// Example: `"a\u{D800}"` for a string with code points [U+0061, U+D800]
 impl fmt::Debug for Wtf8Buf {
     #[inline]
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         fmt::Debug::fmt(&**self, formatter)
     }
 }
index 7341941c242a4a743092b4f125f6a4cf03fd87a9..c98b54581f35f4bde3d13bddad600106f419611c 100644 (file)
@@ -50,8 +50,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl Edition {
     pub fn lint_name(&self) -> &'static str {
         match *self {
-            Edition::Edition2015 => "rust_2015_breakage",
-            Edition::Edition2018 => "rust_2018_breakage",
+            Edition::Edition2015 => "rust_2015_compatibility",
+            Edition::Edition2018 => "rust_2018_compatibility",
         }
     }
 
index 5155408ba63f3143372f4a1db5ea19b312dca792..b27568a61f85cfb16390130cf07086787abd047a 100644 (file)
@@ -190,7 +190,7 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
     (active, rustc_attrs, "1.0.0", Some(29642), None),
 
     // Allows the use of non lexical lifetimes; RFC 2094
-    (active, nll, "1.0.0", Some(43234), Some(Edition::Edition2018)),
+    (active, nll, "1.0.0", Some(43234), None),
 
     // Allows the use of #[allow_internal_unstable]. This is an
     // attribute on macro_rules! and can't use the attribute handling
@@ -1861,56 +1861,61 @@ fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
             continue
         }
 
-        match attr.meta_item_list() {
+        let list = match attr.meta_item_list() {
+            Some(list) => list,
             None => {
                 span_err!(span_handler, attr.span, E0555,
                           "malformed feature attribute, expected #![feature(...)]");
+                continue
+            }
+        };
+
+        for mi in list {
+            let name = if let Some(word) = mi.word() {
+                word.name()
+            } else {
+                span_err!(span_handler, mi.span, E0556,
+                          "malformed feature, expected just one word");
+                continue
+            };
+
+            if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
+                set(&mut features, mi.span);
+                feature_checker.collect(&features, mi.span);
+                continue
             }
-            Some(list) => {
-                for mi in list {
 
-                    let name = if let Some(word) = mi.word() {
-                        word.name()
-                    } else {
-                        span_err!(span_handler, mi.span, E0556,
-                                  "malformed feature, expected just one word");
-                        continue
-                    };
-
-                    if let Some(&(_, _, _, _, set)) = ACTIVE_FEATURES.iter()
-                        .find(|& &(n, ..)| name == n) {
-                        set(&mut features, mi.span);
-                        feature_checker.collect(&features, mi.span);
-                    }
-                    else if let Some(&(.., reason)) = REMOVED_FEATURES.iter()
-                            .find(|& &(n, ..)| name == n)
-                        .or_else(|| STABLE_REMOVED_FEATURES.iter()
-                            .find(|& &(n, ..)| name == n)) {
-                        feature_removed(span_handler, mi.span, reason);
-                    }
-                    else if let Some(&(..)) = ACCEPTED_FEATURES.iter()
-                        .find(|& &(n, ..)| name == n) {
-                        features.declared_stable_lang_features.push((name, mi.span));
-                    } else if let Some(&edition) = ALL_EDITIONS.iter()
-                                                              .find(|e| name == e.feature_name()) {
-                        if edition <= crate_edition {
-                            feature_removed(span_handler, mi.span, None);
-                        } else {
-                            for &(.., f_edition, set) in ACTIVE_FEATURES.iter() {
-                                if let Some(f_edition) = f_edition {
-                                    if edition >= f_edition {
-                                        // FIXME(Manishearth) there is currently no way to set
-                                        // lib features by edition
-                                        set(&mut features, DUMMY_SP);
-                                    }
-                                }
-                            }
+            let removed = REMOVED_FEATURES.iter().find(|f| name == f.0);
+            let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0);
+            if let Some((.., reason)) = removed.or(stable_removed) {
+                feature_removed(span_handler, mi.span, *reason);
+                continue
+            }
+
+            if ACCEPTED_FEATURES.iter().any(|f| name == f.0) {
+                features.declared_stable_lang_features.push((name, mi.span));
+                continue
+            }
+
+            if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
+                if *edition <= crate_edition {
+                    continue
+                }
+
+                for &(.., f_edition, set) in ACTIVE_FEATURES.iter() {
+                    if let Some(f_edition) = f_edition {
+                        if *edition >= f_edition {
+                            // FIXME(Manishearth) there is currently no way to set
+                            // lib features by edition
+                            set(&mut features, DUMMY_SP);
                         }
-                    } else {
-                        features.declared_lib_features.push((name, mi.span));
                     }
                 }
+
+                continue
             }
+
+            features.declared_lib_features.push((name, mi.span));
         }
     }
 
index f148aaf7267eec9dc581fdfc025d8f2884df44b6..90af3ba51ecadcff1a3d7fdf58c90099df2c14b4 100644 (file)
@@ -73,7 +73,7 @@ macro_rules! unwrap_or {
     }
 }
 
-struct Globals {
+pub struct Globals {
     used_attrs: Lock<Vec<u64>>,
     known_attrs: Lock<Vec<u64>>,
     syntax_pos_globals: syntax_pos::Globals,
@@ -98,7 +98,7 @@ pub fn with_globals<F, R>(f: F) -> R
     })
 }
 
-scoped_thread_local!(static GLOBALS: Globals);
+scoped_thread_local!(pub static GLOBALS: Globals);
 
 #[macro_use]
 pub mod diagnostics {
index e95c6f2e1243fe7f5a2556d64d243eb3c30e12b4..2b8603c75a57b50733b0ac0ec611b8fd438b93d4 100644 (file)
@@ -989,7 +989,7 @@ fn clone(&self) -> StrCursor<'a> {
     }
 
     impl<'a> std::fmt::Debug for StrCursor<'a> {
-        fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+        fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
             write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after())
         }
     }
index b9637b1855ef08760a3ed96b6afdedd1aae4ecb5..a9147b394f7a498406baec5c22449ed2943c1c16 100644 (file)
@@ -11,5 +11,6 @@ crate-type = ["dylib"]
 [dependencies]
 serialize = { path = "../libserialize" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+arena = { path = "../libarena" }
 scoped-tls = { version = "0.1.1", features = ["nightly"] }
 unicode-width = "0.1.4"
index 8b4a3ea26a1ef7dca52f5a179e2f0110c7ea5f3f..d30d3d78ca5404dbea9f10b29f81f272b6c5af35 100644 (file)
@@ -35,6 +35,7 @@
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::{Lrc, Lock};
 
+extern crate arena;
 extern crate rustc_data_structures;
 
 #[macro_use]
index 4a8b1e8b1c1e46edb8569c04006a1258a9be7b0a..2258ed12779e4ce7792a195d9cfaa234db812bac 100644 (file)
 use {Span, DUMMY_SP, GLOBALS};
 
 use rustc_data_structures::fx::FxHashMap;
+use arena::DroplessArena;
 use serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::fmt;
+use std::str;
 use std::cmp::{PartialEq, Ordering, PartialOrd, Ord};
 use std::hash::{Hash, Hasher};
 
@@ -198,22 +200,35 @@ fn eq(&self, other: &T) -> bool {
     }
 }
 
-#[derive(Default)]
+// The &'static strs in this type actually point into the arena
 pub struct Interner {
-    names: FxHashMap<Box<str>, Symbol>,
-    strings: Vec<Box<str>>,
+    arena: DroplessArena,
+    names: FxHashMap<&'static str, Symbol>,
+    strings: Vec<&'static str>,
     gensyms: Vec<Symbol>,
 }
 
 impl Interner {
     pub fn new() -> Self {
-        Interner::default()
+        Interner {
+            arena: DroplessArena::new(),
+            names: Default::default(),
+            strings: Default::default(),
+            gensyms: Default::default(),
+        }
     }
 
     fn prefill(init: &[&str]) -> Self {
         let mut this = Interner::new();
         for &string in init {
-            this.intern(string);
+            if string == "" {
+                // We can't allocate empty strings in the arena, so handle this here
+                let name = Symbol(this.strings.len() as u32);
+                this.names.insert("", name);
+                this.strings.push("");
+            } else {
+                this.intern(string);
+            }
         }
         this
     }
@@ -224,8 +239,17 @@ pub fn intern(&mut self, string: &str) -> Symbol {
         }
 
         let name = Symbol(self.strings.len() as u32);
-        let string = string.to_string().into_boxed_str();
-        self.strings.push(string.clone());
+
+        // from_utf8_unchecked is safe since we just allocated a &str which is known to be utf8
+        let string: &str = unsafe {
+            str::from_utf8_unchecked(self.arena.alloc_slice(string.as_bytes()))
+        };
+        // It is safe to extend the arena allocation to 'static because we only access
+        // these while the arena is still alive
+        let string: &'static str =  unsafe {
+            &*(string as *const str)
+        };
+        self.strings.push(string);
         self.names.insert(string, name);
         name
     }
@@ -254,7 +278,7 @@ fn is_gensymed(&mut self, symbol: Symbol) -> bool {
 
     pub fn get(&self, symbol: Symbol) -> &str {
         match self.strings.get(symbol.0 as usize) {
-            Some(ref string) => string,
+            Some(string) => string,
             None => self.get(self.gensyms[(!0 - symbol.0) as usize]),
         }
     }
@@ -503,7 +527,7 @@ fn partial_cmp(&self, other: &InternedString) -> Option<Ordering> {
         if self.symbol == other.symbol {
             return Some(Ordering::Equal);
         }
-        self.with(|self_str| other.with(|other_str| self_str.partial_cmp(&other_str)))
+        self.with(|self_str| other.with(|other_str| self_str.partial_cmp(other_str)))
     }
 }
 
index 382ef2cc407dd93ba704457c5fee7a58073fde86..8593f543619a59ba5aa1b4e0db00bfaa9e20e3b2 100644 (file)
@@ -428,13 +428,16 @@ extern "C" void LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM,
 
 extern "C" void LLVMRustConfigurePassManagerBuilder(
     LLVMPassManagerBuilderRef PMBR, LLVMRustCodeGenOptLevel OptLevel,
-    bool MergeFunctions, bool SLPVectorize, bool LoopVectorize,
+    bool MergeFunctions, bool SLPVectorize, bool LoopVectorize, bool PrepareForThinLTO,
     const char* PGOGenPath, const char* PGOUsePath) {
   // Ignore mergefunc for now as enabling it causes crashes.
   // unwrap(PMBR)->MergeFunctions = MergeFunctions;
   unwrap(PMBR)->SLPVectorize = SLPVectorize;
   unwrap(PMBR)->OptLevel = fromRust(OptLevel);
   unwrap(PMBR)->LoopVectorize = LoopVectorize;
+#if LLVM_VERSION_GE(4, 0)
+  unwrap(PMBR)->PrepareForThinLTO = PrepareForThinLTO;
+#endif
 
 #ifdef PGO_AVAILABLE
   if (PGOGenPath) {
index 415ee6eb7eab8754834de460088b0ac260935313..1879002e7f3d7cb2750ca73b9aad7aedda4a8347 100644 (file)
 
 #![crate_type = "lib"]
 
-// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one"
+// CHECK: @VAR1 = constant i32 1, section ".test_one"
 #[no_mangle]
 #[link_section = ".test_one"]
-#[cfg(target_endian = "little")]
 pub static VAR1: u32 = 1;
 
-#[no_mangle]
-#[link_section = ".test_one"]
-#[cfg(target_endian = "big")]
-pub static VAR1: u32 = 0x01000000;
-
 pub enum E {
     A(u32),
     B(f32)
diff --git a/src/test/compile-fail/auxiliary/edition-extern-crate-allowed.rs b/src/test/compile-fail/auxiliary/edition-extern-crate-allowed.rs
new file mode 100644 (file)
index 0000000..d26ab6d
--- /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.
+
+// intentionally empty
diff --git a/src/test/compile-fail/edition-extern-crate-allowed.rs b/src/test/compile-fail/edition-extern-crate-allowed.rs
new file mode 100644 (file)
index 0000000..286ee89
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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:edition-extern-crate-allowed.rs
+// compile-flags: --edition 2015
+// compile-pass
+
+#![deny(rust_2018_idioms)]
+
+extern crate edition_extern_crate_allowed;
+
+fn main() {}
diff --git a/src/test/compile-fail/edition-feature-ok.rs b/src/test/compile-fail/edition-feature-ok.rs
new file mode 100644 (file)
index 0000000..3a3a6ff
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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:--edition 2018
+// compile-pass
+
+#![feature(rust_2018_preview)]
+
+fn main() {}
diff --git a/src/test/run-make-fulldeps/issue-36710/Makefile b/src/test/run-make-fulldeps/issue-36710/Makefile
new file mode 100644 (file)
index 0000000..2cb0b4c
--- /dev/null
@@ -0,0 +1,12 @@
+-include ../tools.mk
+
+all: foo
+       $(call RUN,foo)
+
+foo: foo.rs $(call NATIVE_STATICLIB,foo)
+       $(RUSTC) $< -lfoo $(EXTRACXXFLAGS)
+
+$(TMPDIR)/libfoo.o: foo.cpp
+       $(call COMPILE_OBJ_CXX,$@,$<)
+
+.PHONY: all
diff --git a/src/test/run-make-fulldeps/issue-36710/foo.cpp b/src/test/run-make-fulldeps/issue-36710/foo.cpp
new file mode 100644 (file)
index 0000000..fbd0ead
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#include <stdint.h>
+
+struct A {
+    A() { v = 1234; }
+    ~A() { v = 1; }
+    uint32_t v;
+};
+
+A a;
+
+extern "C" {
+    uint32_t get() {
+        return a.v;
+    }
+}
diff --git a/src/test/run-make-fulldeps/issue-36710/foo.rs b/src/test/run-make-fulldeps/issue-36710/foo.rs
new file mode 100644 (file)
index 0000000..6e50566
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Tests that linking to C++ code with global destructors works.
+
+extern { fn get() -> u32; }
+
+fn main() {
+    let i = unsafe { get() };
+    assert_eq!(i, 1234);
+}
index af1707de6c02f52432cfc241cca0df4f9e06ad70..3de358fa50007140e480d160ec4b66e01d70d08d 100644 (file)
@@ -59,12 +59,14 @@ endif
 
 ifdef IS_MSVC
 COMPILE_OBJ = $(CC) -c -Fo:`cygpath -w $(1)` $(2)
+COMPILE_OBJ_CXX = $(CXX) -c -Fo:`cygpath -w $(1)` $(2)
 NATIVE_STATICLIB_FILE = $(1).lib
 NATIVE_STATICLIB = $(TMPDIR)/$(call NATIVE_STATICLIB_FILE,$(1))
 OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
        -Fo:`cygpath -w $(TMPDIR)/$(1).obj`
 else
 COMPILE_OBJ = $(CC) -c -o $(1) $(2)
+COMPILE_OBJ_CXX = $(CXX) -c -o $(1) $(2)
 NATIVE_STATICLIB_FILE = lib$(1).a
 NATIVE_STATICLIB = $(call STATICLIB,$(1))
 OUT_EXE=-o $(TMPDIR)/$(1)
index 914b89dfb4dc030ae81190b79d525f51eaed8b7e..2d478e954e7cb7cb493e98b9da4e2ad124f80b33 100644 (file)
@@ -15,7 +15,7 @@
 
 struct SlowFmt(u32);
 impl fmt::Debug for SlowFmt {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         thread::sleep_ms(3);
         self.0.fmt(f)
     }
index 1cdaff2cab7c8c7e25efe55464f7744d03fdf8d3..c1e408cc02ac6764aa95fc848f28fe26ddcf4549 100644 (file)
@@ -15,7 +15,7 @@ union U {
 }
 
 impl fmt::Display for U {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         unsafe { write!(f, "Oh hai {}", self.a) }
     }
 }
index 9d678d91578bc1027db26cba228d1a80489178ae..0f532d3da6a7307ad1f25993bb5705ee3be751c4 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// compile-flags: --edition 2018
+
 #![deny(unnecessary_extern_crate)]
 #![feature(alloc, test, libc)]
 
index 7718808be58baea95df41a1088ea3bc83028fecd..b0b56f527e64f68c695c5a0141104de6ea91c75f 100644 (file)
@@ -1,65 +1,65 @@
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:14:1
+  --> $DIR/unnecessary-extern-crate.rs:16:1
    |
 LL | extern crate alloc;
    | ^^^^^^^^^^^^^^^^^^^ help: remove it
    |
 note: lint level defined here
-  --> $DIR/unnecessary-extern-crate.rs:11:9
+  --> $DIR/unnecessary-extern-crate.rs:13:9
    |
 LL | #![deny(unnecessary_extern_crate)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:17:1
+  --> $DIR/unnecessary-extern-crate.rs:19:1
    |
 LL | extern crate alloc as x;
    | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:23:1
+  --> $DIR/unnecessary-extern-crate.rs:25:1
    |
 LL | pub extern crate test as y;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:26:1
+  --> $DIR/unnecessary-extern-crate.rs:28:1
    |
 LL | pub extern crate libc;
    | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use libc`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:32:5
+  --> $DIR/unnecessary-extern-crate.rs:34:5
    |
 LL |     extern crate alloc;
    |     ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:35:5
+  --> $DIR/unnecessary-extern-crate.rs:37:5
    |
 LL |     extern crate alloc as x;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:38:5
+  --> $DIR/unnecessary-extern-crate.rs:40:5
    |
 LL |     pub extern crate test;
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:41:5
+  --> $DIR/unnecessary-extern-crate.rs:43:5
    |
 LL |     pub extern crate test as y;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:45:9
+  --> $DIR/unnecessary-extern-crate.rs:47:9
    |
 LL |         extern crate alloc;
    |         ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc`
 
 error: `extern crate` is unnecessary in the new edition
-  --> $DIR/unnecessary-extern-crate.rs:48:9
+  --> $DIR/unnecessary-extern-crate.rs:50:9
    |
 LL |         extern crate alloc as x;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
index 07aa3bfe40dea06e94f2da26f0a40d493b70ed81..c89defa3dd196d97a4a8822a33b37b1a933b527a 100644 (file)
@@ -4,8 +4,7 @@ error[E0369]: binary operation `%` cannot be applied to type `&&{integer}`
 LL |         x % 2 == 0
    |         ^^^^^
    |
-   = note: this is a reference to a type that `%` can be applied to; you need to dereference this variable once for this operation to work
-   = note: an implementation of `std::ops::Rem` might be missing for `&&{integer}`
+   = help: `%` can be used on '{integer}', you can dereference `x`: `*x`
 
 error: aborting due to previous error
 
index 2c8a33d95c03a23e57839323ea4f1d5feb7afb90..15c159a3b153cf8f8cfcdc586eac03a2dce496ae 100644 (file)
@@ -2,7 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str`
   --> $DIR/issue-28308.rs:12:5
    |
 LL |     assert!("foo");
-   |     ^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^ cannot apply unary operator `!`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-eval/duration_conversion.rs b/src/test/ui/const-eval/duration_conversion.rs
new file mode 100644 (file)
index 0000000..4481b75
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-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-pass
+
+#![feature(duration_getters)]
+
+use std::time::Duration;
+
+fn main() {
+    const _ONE_SECOND: Duration = Duration::from_nanos(1_000_000_000);
+    const _ONE_MILLISECOND: Duration = Duration::from_nanos(1_000_000);
+    const _ONE_MICROSECOND: Duration = Duration::from_nanos(1_000);
+    const _ONE_NANOSECOND: Duration = Duration::from_nanos(1);
+    const _ONE: usize = _ONE_SECOND.as_secs() as usize;
+    const _TWO: usize = _ONE_MILLISECOND.subsec_millis() as usize;
+    const _THREE: usize = _ONE_MICROSECOND.subsec_micros() as usize;
+    const _FOUR: usize = _ONE_NANOSECOND.subsec_nanos() as usize;
+    const _0: [[u8; _ONE]; _TWO] = [[1; _ONE]; _TWO];
+    const _1: [[u8; _THREE]; _FOUR] = [[3; _THREE]; _FOUR];
+}
index 76f06c7c46379476a0cc744d4e5f6d1b4c3d74b7..43e1ca4096cf69a37f9c90006a04ced496241fc9 100644 (file)
@@ -5,6 +5,8 @@ LL |     LinkedList::new() += 1; //~ ERROR E0368
    |     -----------------^^^^^
    |     |
    |     cannot use `+=` on type `std::collections::LinkedList<_>`
+   |
+   = note: an implementation of `std::ops::AddAssign` might be missing for `std::collections::LinkedList<_>`
 
 error[E0067]: invalid left-hand side expression
   --> $DIR/E0067.rs:14:5
index 500feb39f5e7421e9cafaa93fc2e3a717d65abc6..c29ec4fe6ae76e2f09e9ae53971e886b78deacc9 100644 (file)
@@ -2,7 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `&'static str`
   --> $DIR/E0600.rs:12:5
    |
 LL |     !"a"; //~ ERROR E0600
-   |     ^^^^
+   |     ^^^^ cannot apply unary operator `!`
 
 error: aborting due to previous error
 
index 345691352b407a7084cc0e38c890caad7712b1d6..69f11b4b7c08c33c74af00c7a73a05bd941ec0aa 100644 (file)
@@ -17,6 +17,8 @@ LL |     x += 2;
    |     -^^^^^
    |     |
    |     cannot use `+=` on type `&str`
+   |
+   = note: an implementation of `std::ops::AddAssign` might be missing for `&str`
 
 error[E0599]: no method named `z` found for type `&str` in the current scope
   --> $DIR/error-festival.rs:26:7
@@ -28,7 +30,9 @@ error[E0600]: cannot apply unary operator `!` to type `Question`
   --> $DIR/error-festival.rs:29:5
    |
 LL |     !Question::Yes;
-   |     ^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^ cannot apply unary operator `!`
+   |
+   = note: an implementation of `std::ops::Not` might be missing for `Question`
 
 error[E0604]: only `u8` can be cast as `char`, not `u32`
   --> $DIR/error-festival.rs:35:5
index 1025b56f55bc3cfc7dc505f6d845a09f452a3a2a..85e9b56e4af9db3f0caeee55d1621e7421599e08 100644 (file)
@@ -2,13 +2,17 @@ error[E0600]: cannot apply unary operator `-` to type `usize`
   --> $DIR/feature-gate-negate-unsigned.rs:20:23
    |
 LL |     let _max: usize = -1;
-   |                       ^^
+   |                       ^^ cannot apply unary operator `-`
+   |
+   = note: unsigned values cannot be negated
 
 error[E0600]: cannot apply unary operator `-` to type `u8`
   --> $DIR/feature-gate-negate-unsigned.rs:24:14
    |
 LL |     let _y = -x;
-   |              ^^
+   |              ^^ cannot apply unary operator `-`
+   |
+   = note: unsigned values cannot be negated
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.rs
deleted file mode 100644 (file)
index 005f1f0..0000000
+++ /dev/null
@@ -1,16 +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.
-#![deny(single_use_lifetime)]
-// FIXME(#44752) -- this scenario should not be warned
-fn deref<'x>() -> &'x u32 { //~ ERROR lifetime name `'x` only used once
-    22
-}
-
-fn main() { }
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-2.stderr
deleted file mode 100644 (file)
index 38d0536..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes-2.rs:12:10
-   |
-LL | fn deref<'x>() -> &'x u32 { //~ ERROR lifetime name `'x` only used once
-   |          ^^
-   |
-note: lint level defined here
-  --> $DIR/single_use_lifetimes-2.rs:10:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.rs
deleted file mode 100644 (file)
index 263548c..0000000
+++ /dev/null
@@ -1,20 +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.
-#![deny(single_use_lifetime)]
-struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
-    x: &'x u32 // no warning!
-}
-
-// Once #44524 is fixed, this should issue a warning.
-impl<'y> Foo<'y> { //~ ERROR lifetime name `'y` only used once
-    fn method() { }
-}
-
-fn main() { }
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-3.stderr
deleted file mode 100644 (file)
index 49c06aa..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes-3.rs:11:12
-   |
-LL | struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
-   |            ^^
-   |
-note: lint level defined here
-  --> $DIR/single_use_lifetimes-3.rs:10:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: lifetime name `'y` only used once
-  --> $DIR/single_use_lifetimes-3.rs:16:6
-   |
-LL | impl<'y> Foo<'y> { //~ ERROR lifetime name `'y` only used once
-   |      ^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.rs
deleted file mode 100644 (file)
index 4ac8f8c..0000000
+++ /dev/null
@@ -1,20 +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.
-#![deny(single_use_lifetime)]
- // Neither should issue a warning, as explicit lifetimes are mandatory in this case
-struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
-    x: &'x u32
-}
-
-enum Bar<'x> { //~ ERROR lifetime name `'x` only used once
-    Variant(&'x u32)
-}
-
-fn main() { }
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-4.stderr
deleted file mode 100644 (file)
index 2df370f..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes-4.rs:12:12
-   |
-LL | struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
-   |            ^^
-   |
-note: lint level defined here
-  --> $DIR/single_use_lifetimes-4.rs:10:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes-4.rs:16:10
-   |
-LL | enum Bar<'x> { //~ ERROR lifetime name `'x` only used once
-   |          ^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.rs
deleted file mode 100644 (file)
index cef904c..0000000
+++ /dev/null
@@ -1,16 +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.
-#![deny(single_use_lifetime)]
-// Should not issue a warning, as explicit lifetimes are mandatory in this case:
-trait Foo<'x> { //~ ERROR lifetime name `'x` only used once
-    fn foo(&self, arg: &'x u32);
-}
-
-fn main() { }
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes-5.stderr
deleted file mode 100644 (file)
index eec426e..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes-5.rs:12:11
-   |
-LL | trait Foo<'x> { //~ ERROR lifetime name `'x` only used once
-   |           ^^
-   |
-note: lint level defined here
-  --> $DIR/single_use_lifetimes-5.rs:10:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes.rs b/src/test/ui/in-band-lifetimes/single_use_lifetimes.rs
deleted file mode 100644 (file)
index a97056b..0000000
+++ /dev/null
@@ -1,16 +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.
-#![deny(single_use_lifetime)]
-
-fn deref<'x>(v: &'x u32) -> u32 { //~ ERROR lifetime name `'x` only used once
-    *v
-}
-
-fn main() {}
diff --git a/src/test/ui/in-band-lifetimes/single_use_lifetimes.stderr b/src/test/ui/in-band-lifetimes/single_use_lifetimes.stderr
deleted file mode 100644 (file)
index 15917d3..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: lifetime name `'x` only used once
-  --> $DIR/single_use_lifetimes.rs:12:10
-   |
-LL | fn deref<'x>(v: &'x u32) -> u32 { //~ ERROR lifetime name `'x` only used once
-   |          ^^
-   |
-note: lint level defined here
-  --> $DIR/single_use_lifetimes.rs:10:9
-   |
-LL | #![deny(single_use_lifetime)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/issue-50480.rs b/src/test/ui/issue-50480.rs
new file mode 100644 (file)
index 0000000..3427cf6
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[derive(Clone, Copy)]
+//~^ ERROR the trait `Copy` may not be implemented for this type
+struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+//~^ ERROR cannot find type `NotDefined` in this scope
+//~| ERROR the trait bound `i32: std::iter::Iterator` is not satisfied
+
+fn main() {}
diff --git a/src/test/ui/issue-50480.stderr b/src/test/ui/issue-50480.stderr
new file mode 100644 (file)
index 0000000..f5281fe
--- /dev/null
@@ -0,0 +1,29 @@
+error[E0412]: cannot find type `NotDefined` in this scope
+  --> $DIR/issue-50480.rs:13:12
+   |
+LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |            ^^^^^^^^^^ not found in this scope
+
+error[E0277]: the trait bound `i32: std::iter::Iterator` is not satisfied
+  --> $DIR/issue-50480.rs:13:24
+   |
+LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator; maybe try calling `.iter()` or a similar method
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `i32`
+
+error[E0204]: the trait `Copy` may not be implemented for this type
+  --> $DIR/issue-50480.rs:11:17
+   |
+LL | #[derive(Clone, Copy)]
+   |                 ^^^^
+LL | //~^ ERROR the trait `Copy` may not be implemented for this type
+LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |                                                 --------  ------ this field does not implement `Copy`
+   |                                                 |
+   |                                                 this field does not implement `Copy`
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0204, E0277, E0412.
+For more information about an error, try `rustc --explain E0204`.
index 2f9204e72d3fb0e73ac3e673ca3c945c3ef1f012..7ae01fb7d6012996c1e80ebb82038431117b6aaa 100644 (file)
@@ -5,6 +5,8 @@ LL |     let x = |ref x: isize| { x += 1; };
    |                              -^^^^^
    |                              |
    |                              cannot use `+=` on type `&isize`
+   |
+   = help: `+=` can be used on 'isize', you can dereference `x`: `*x`
 
 error: aborting due to previous error
 
index f5e6b4d3b48622d2a30b591490f41c3407a6ea07..0a1926f8ae56a11dd9ad7f91881d37c3827cbbde 100644 (file)
@@ -24,6 +24,7 @@
 mod private_mod {
     // non-leaked `pub` items in private module should be linted
     pub use std::fmt;
+    pub use std::env::{Args}; // braced-use has different item spans than unbraced
 
     pub struct Hydrogen {
         // `pub` struct fields, too
index d1711be456bcc1667babc691e12d6ea7e376a4ed..2948deb23009c64b62b33b56fa7a380974aae3b3 100644 (file)
@@ -14,7 +14,15 @@ LL | #![warn(unreachable_pub)]
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:28:5
+  --> $DIR/unreachable_pub-pub_crate.rs:27:24
+   |
+LL |     pub use std::env::{Args}; // braced-use has different item spans than unbraced
+   |                        ^^^^ help: consider restricting its visibility: `pub(crate)`
+   |
+   = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+  --> $DIR/unreachable_pub-pub_crate.rs:29:5
    |
 LL |     pub struct Hydrogen {
    |     ---^^^^^^^^^^^^^^^^
@@ -24,7 +32,7 @@ LL |     pub struct Hydrogen {
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` field
-  --> $DIR/unreachable_pub-pub_crate.rs:30:9
+  --> $DIR/unreachable_pub-pub_crate.rs:31:9
    |
 LL |         pub neutrons: usize,
    |         ---^^^^^^^^^^^^^^^^
@@ -32,7 +40,7 @@ LL |         pub neutrons: usize,
    |         help: consider restricting its visibility: `pub(crate)`
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:36:9
+  --> $DIR/unreachable_pub-pub_crate.rs:37:9
    |
 LL |         pub fn count_neutrons(&self) -> usize { self.neutrons }
    |         ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +48,7 @@ LL |         pub fn count_neutrons(&self) -> usize { self.neutrons }
    |         help: consider restricting its visibility: `pub(crate)`
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:40:5
+  --> $DIR/unreachable_pub-pub_crate.rs:41:5
    |
 LL |     pub enum Helium {}
    |     ---^^^^^^^^^^^^
@@ -50,7 +58,7 @@ LL |     pub enum Helium {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:41:5
+  --> $DIR/unreachable_pub-pub_crate.rs:42:5
    |
 LL |     pub union Lithium { c1: usize, c2: u8 }
    |     ---^^^^^^^^^^^^^^
@@ -60,7 +68,7 @@ LL |     pub union Lithium { c1: usize, c2: u8 }
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:42:5
+  --> $DIR/unreachable_pub-pub_crate.rs:43:5
    |
 LL |     pub fn beryllium() {}
    |     ---^^^^^^^^^^^^^^^
@@ -70,7 +78,7 @@ LL |     pub fn beryllium() {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:43:5
+  --> $DIR/unreachable_pub-pub_crate.rs:44:5
    |
 LL |     pub trait Boron {}
    |     ---^^^^^^^^^^^^
@@ -80,7 +88,7 @@ LL |     pub trait Boron {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:44:5
+  --> $DIR/unreachable_pub-pub_crate.rs:45:5
    |
 LL |     pub const CARBON: usize = 1;
    |     ---^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -90,7 +98,7 @@ LL |     pub const CARBON: usize = 1;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:45:5
+  --> $DIR/unreachable_pub-pub_crate.rs:46:5
    |
 LL |     pub static NITROGEN: usize = 2;
    |     ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +108,7 @@ LL |     pub static NITROGEN: usize = 2;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:46:5
+  --> $DIR/unreachable_pub-pub_crate.rs:47:5
    |
 LL |     pub type Oxygen = bool;
    |     ---^^^^^^^^^^^^^^^^^^^^
@@ -110,7 +118,7 @@ LL |     pub type Oxygen = bool;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:49:47
+  --> $DIR/unreachable_pub-pub_crate.rs:50:47
    |
 LL |         ($visibility: vis, $name: ident) => { $visibility struct $name {} }
    |                                               -----------^^^^^^^^^^^^^
@@ -123,7 +131,7 @@ LL |     define_empty_struct_with_visibility!(pub, Fluorine);
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub-pub_crate.rs:54:9
+  --> $DIR/unreachable_pub-pub_crate.rs:55:9
    |
 LL |         pub fn catalyze() -> bool;
    |         ---^^^^^^^^^^^^^^^^^^^^^^^
index 347579c3e7bb93df13e9d262e7d6561241d1e9a1..5bb67670d85c2ae6f9bcfa708e28c944ed82f2c4 100644 (file)
@@ -19,6 +19,7 @@
 mod private_mod {
     // non-leaked `pub` items in private module should be linted
     pub use std::fmt;
+    pub use std::env::{Args}; // braced-use has different item spans than unbraced
 
     pub struct Hydrogen {
         // `pub` struct fields, too
index 1d693161108db03fe6d319e84de76c90d3c94d6e..ad88c55d54013a92c97697454bdfcfcac7ef4fb4 100644 (file)
@@ -14,7 +14,15 @@ LL | #![warn(unreachable_pub)]
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:23:5
+  --> $DIR/unreachable_pub.rs:22:24
+   |
+LL |     pub use std::env::{Args}; // braced-use has different item spans than unbraced
+   |                        ^^^^ help: consider restricting its visibility: `crate`
+   |
+   = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+  --> $DIR/unreachable_pub.rs:24:5
    |
 LL |     pub struct Hydrogen {
    |     ---^^^^^^^^^^^^^^^^
@@ -24,7 +32,7 @@ LL |     pub struct Hydrogen {
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` field
-  --> $DIR/unreachable_pub.rs:25:9
+  --> $DIR/unreachable_pub.rs:26:9
    |
 LL |         pub neutrons: usize,
    |         ---^^^^^^^^^^^^^^^^
@@ -32,7 +40,7 @@ LL |         pub neutrons: usize,
    |         help: consider restricting its visibility: `crate`
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:31:9
+  --> $DIR/unreachable_pub.rs:32:9
    |
 LL |         pub fn count_neutrons(&self) -> usize { self.neutrons }
    |         ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +48,7 @@ LL |         pub fn count_neutrons(&self) -> usize { self.neutrons }
    |         help: consider restricting its visibility: `crate`
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:35:5
+  --> $DIR/unreachable_pub.rs:36:5
    |
 LL |     pub enum Helium {}
    |     ---^^^^^^^^^^^^
@@ -50,7 +58,7 @@ LL |     pub enum Helium {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:36:5
+  --> $DIR/unreachable_pub.rs:37:5
    |
 LL |     pub union Lithium { c1: usize, c2: u8 }
    |     ---^^^^^^^^^^^^^^
@@ -60,7 +68,7 @@ LL |     pub union Lithium { c1: usize, c2: u8 }
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:37:5
+  --> $DIR/unreachable_pub.rs:38:5
    |
 LL |     pub fn beryllium() {}
    |     ---^^^^^^^^^^^^^^^
@@ -70,7 +78,7 @@ LL |     pub fn beryllium() {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:38:5
+  --> $DIR/unreachable_pub.rs:39:5
    |
 LL |     pub trait Boron {}
    |     ---^^^^^^^^^^^^
@@ -80,7 +88,7 @@ LL |     pub trait Boron {}
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:39:5
+  --> $DIR/unreachable_pub.rs:40:5
    |
 LL |     pub const CARBON: usize = 1;
    |     ---^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -90,7 +98,7 @@ LL |     pub const CARBON: usize = 1;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:40:5
+  --> $DIR/unreachable_pub.rs:41:5
    |
 LL |     pub static NITROGEN: usize = 2;
    |     ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +108,7 @@ LL |     pub static NITROGEN: usize = 2;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:41:5
+  --> $DIR/unreachable_pub.rs:42:5
    |
 LL |     pub type Oxygen = bool;
    |     ---^^^^^^^^^^^^^^^^^^^^
@@ -110,7 +118,7 @@ LL |     pub type Oxygen = bool;
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:44:47
+  --> $DIR/unreachable_pub.rs:45:47
    |
 LL |         ($visibility: vis, $name: ident) => { $visibility struct $name {} }
    |                                               -----------^^^^^^^^^^^^^
@@ -123,7 +131,7 @@ LL |     define_empty_struct_with_visibility!(pub, Fluorine);
    = help: or consider exporting it for use by other crates
 
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:49:9
+  --> $DIR/unreachable_pub.rs:50:9
    |
 LL |         pub fn catalyze() -> bool;
    |         ---^^^^^^^^^^^^^^^^^^^^^^^
index 165eccd42396b2e8310ffcc4b6d6a734d44363ec..b889c884fcbb223f66e2eb574dc482cf6c06f908 100644 (file)
@@ -2,7 +2,7 @@ error[E0600]: cannot apply unary operator `!` to type `!`
   --> $DIR/expr_unary.rs:17:16
    |
 LL |     let x: ! = ! { return; }; //~ ERROR unreachable
-   |                ^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^ cannot apply unary operator `!`
 
 error: unreachable expression
   --> $DIR/expr_unary.rs:17:16
diff --git a/src/test/ui/single-use-lifetime/fn-types.rs b/src/test/ui/single-use-lifetime/fn-types.rs
new file mode 100644 (file)
index 0000000..c5d98d2
--- /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.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument.
+
+struct Foo {
+  a: for<'a> fn(&'a u32), //~ ERROR `'a` only used once
+  b: for<'a> fn(&'a u32, &'a u32), // OK, used twice.
+  c: for<'a> fn(&'a u32) -> &'a u32, // OK, used twice.
+  d: for<'a> fn() -> &'a u32, // OK, used only in return type.
+    //~^ ERROR return type references lifetime `'a`, which is not constrained by the fn input types
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/fn-types.stderr b/src/test/ui/single-use-lifetime/fn-types.stderr
new file mode 100644 (file)
index 0000000..bec712b
--- /dev/null
@@ -0,0 +1,21 @@
+error: lifetime parameter `'a` only used once
+  --> $DIR/fn-types.rs:19:10
+   |
+LL |   a: for<'a> fn(&'a u32), //~ ERROR `'a` only used once
+   |          ^^
+   |
+note: lint level defined here
+  --> $DIR/fn-types.rs:11:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
+  --> $DIR/fn-types.rs:22:22
+   |
+LL |   d: for<'a> fn() -> &'a u32, // OK, used only in return type.
+   |                      ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0581`.
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.rs b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.rs
new file mode 100644 (file)
index 0000000..9001a8d
--- /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.
+
+#![feature(in_band_lifetimes)]
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument, even with in band lifetimes.
+
+fn a(x: &'a u32, y: &'b u32) {
+    //~^ ERROR `'a` only used once
+    //~| ERROR `'b` only used once
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr
new file mode 100644 (file)
index 0000000..2011359
--- /dev/null
@@ -0,0 +1,20 @@
+error: lifetime parameter `'b` only used once
+  --> $DIR/one-use-in-fn-argument-in-band.rs:19:22
+   |
+LL | fn a(x: &'a u32, y: &'b u32) {
+   |                      ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-fn-argument-in-band.rs:12:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: lifetime parameter `'a` only used once
+  --> $DIR/one-use-in-fn-argument-in-band.rs:19:10
+   |
+LL | fn a(x: &'a u32, y: &'b u32) {
+   |          ^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument.rs b/src/test/ui/single-use-lifetime/one-use-in-fn-argument.rs
new file mode 100644 (file)
index 0000000..2a9e80d
--- /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.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument.
+
+fn a<'a>(x: &'a u32) { //~ ERROR `'a` only used once
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr b/src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr
new file mode 100644 (file)
index 0000000..e9a3570
--- /dev/null
@@ -0,0 +1,14 @@
+error: lifetime parameter `'a` only used once
+  --> $DIR/one-use-in-fn-argument.rs:18:6
+   |
+LL | fn a<'a>(x: &'a u32) { //~ ERROR `'a` only used once
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-fn-argument.rs:11:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-return.rs b/src/test/ui/single-use-lifetime/one-use-in-fn-return.rs
new file mode 100644 (file)
index 0000000..d024094
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO NOT warn when lifetime name is used only
+// once in a fn return type -- using `'_` is not legal there,
+// as it must refer back to an argument.
+//
+// (Normally, using `'static` would be preferred, but there are
+// times when that is not what you want.)
+//
+// run-pass
+
+fn b<'a>() -> &'a u32 { // OK: used only in return type
+    &22
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.rs b/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.rs
new file mode 100644 (file)
index 0000000..9cdad09
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn for a lifetime used only once in an impl.
+//
+// (Actually, until #15872 is fixed, you can't use `'_` here, but
+// hopefully that will come soon.)
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+    fn inherent_a(&self) {
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.stderr b/src/test/ui/single-use-lifetime/one-use-in-inherent-impl-header.stderr
new file mode 100644 (file)
index 0000000..1718f19
--- /dev/null
@@ -0,0 +1,14 @@
+error: lifetime parameter `'f` only used once
+  --> $DIR/one-use-in-inherent-impl-header.rs:24:6
+   |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-inherent-impl-header.rs:11:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.rs b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.rs
new file mode 100644 (file)
index 0000000..1ca078c
--- /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.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn for a lifetime used only once in an inherent method.
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+    fn inherent_a<'a>(&self, data: &'a u32) { //~ ERROR `'a` only used once
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.stderr b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-argument.stderr
new file mode 100644 (file)
index 0000000..38e90e7
--- /dev/null
@@ -0,0 +1,20 @@
+error: lifetime parameter `'a` only used once
+  --> $DIR/one-use-in-inherent-method-argument.rs:22:19
+   |
+LL |     fn inherent_a<'a>(&self, data: &'a u32) { //~ ERROR `'a` only used once
+   |                   ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-inherent-method-argument.rs:11:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: lifetime parameter `'f` only used once
+  --> $DIR/one-use-in-inherent-method-argument.rs:21:6
+   |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+   |      ^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.rs b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.rs
new file mode 100644 (file)
index 0000000..7d2ffa3
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO NOT warn for a lifetime used just once in a return type,
+// where that return type is in an inherent method.
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+    fn inherent_a<'a>(&self) -> &'a u32 { // OK for 'a
+        &22
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.stderr b/src/test/ui/single-use-lifetime/one-use-in-inherent-method-return.stderr
new file mode 100644 (file)
index 0000000..32fd284
--- /dev/null
@@ -0,0 +1,14 @@
+error: lifetime parameter `'f` only used once
+  --> $DIR/one-use-in-inherent-method-return.rs:22:6
+   |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-inherent-method-return.rs:11:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/one-use-in-struct.rs b/src/test/ui/single-use-lifetime/one-use-in-struct.rs
new file mode 100644 (file)
index 0000000..5c758d9
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we do not warn for named lifetimes in structs,
+// even when they are only used once (since to not use a named
+// lifetime is illegal!)
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+enum Bar<'f> {
+    Data(&'f u32)
+}
+
+trait Baz<'f> { }
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.rs b/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.rs
new file mode 100644 (file)
index 0000000..99e9eaf
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO warn for a lifetime on an impl used only in `&self`
+// in a trait method.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Iterator for Foo<'f> {
+    type Item = &'f u32;
+
+    fn next<'g>(&'g mut self) -> Option<Self::Item> { //~ ERROR `'g` only used once
+        None
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.stderr b/src/test/ui/single-use-lifetime/one-use-in-trait-method-argument.stderr
new file mode 100644 (file)
index 0000000..e527867
--- /dev/null
@@ -0,0 +1,14 @@
+error: lifetime parameter `'g` only used once
+  --> $DIR/one-use-in-trait-method-argument.rs:25:13
+   |
+LL |     fn next<'g>(&'g mut self) -> Option<Self::Item> { //~ ERROR `'g` only used once
+   |             ^^
+   |
+note: lint level defined here
+  --> $DIR/one-use-in-trait-method-argument.rs:14:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/two-uses-in-fn-argument-and-return.rs b/src/test/ui/single-use-lifetime/two-uses-in-fn-argument-and-return.rs
new file mode 100644 (file)
index 0000000..d210be4
--- /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.
+
+// Test that we DO NOT warn when lifetime name is used in
+// both the argument and return.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+fn c<'a>(x: &'a u32) -> &'a u32 { // OK: used twice
+    &22
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/two-uses-in-fn-arguments.rs b/src/test/ui/single-use-lifetime/two-uses-in-fn-arguments.rs
new file mode 100644 (file)
index 0000000..f43a3e1
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO NOT warn when lifetime name is used multiple
+// argments, or more than once in a single argument.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+fn c<'a>(x: &'a u32, y: &'a u32) { // OK: used twice
+}
+
+fn d<'a>(x: (&'a u32, &'a u32)) { // OK: used twice
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/two-uses-in-inherent-impl-header.rs b/src/test/ui/single-use-lifetime/two-uses-in-inherent-impl-header.rs
new file mode 100644 (file)
index 0000000..d224d9f
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO NOT warn for a lifetime used twice in an impl.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Foo<'f> {
+    fn inherent_a(&self, data: &'f u32) {
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.rs b/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.rs
new file mode 100644 (file)
index 0000000..7b69a6f
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO NOT warn for a lifetime used twice in an impl method and
+// header.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+    fn inherent_a<'a>(&self, data: &'a u32) -> &'a u32{
+      data
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.stderr b/src/test/ui/single-use-lifetime/two-uses-in-inherent-method-argument-and-return.stderr
new file mode 100644 (file)
index 0000000..6fc6661
--- /dev/null
@@ -0,0 +1,14 @@
+error: lifetime parameter `'f` only used once
+  --> $DIR/two-uses-in-inherent-method-argument-and-return.rs:22:6
+   |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/two-uses-in-inherent-method-argument-and-return.rs:14:9
+   |
+LL | #![deny(single_use_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/two-uses-in-trait-impl.rs b/src/test/ui/single-use-lifetime/two-uses-in-trait-impl.rs
new file mode 100644 (file)
index 0000000..ffba3d8
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO NOT warn for a lifetime on an impl used in both
+// header and in an associated type.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+    data: &'f u32
+}
+
+impl<'f> Iterator for Foo<'f> {
+    type Item = &'f u32;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        None
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/zero-uses-in-fn.rs b/src/test/ui/single-use-lifetime/zero-uses-in-fn.rs
new file mode 100644 (file)
index 0000000..b71b189
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO warn when lifetime name is not used at all.
+
+#![deny(unused_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+fn d<'a>() { } //~ ERROR `'a` never used
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/zero-uses-in-fn.stderr b/src/test/ui/single-use-lifetime/zero-uses-in-fn.stderr
new file mode 100644 (file)
index 0000000..f1cdc6e
--- /dev/null
@@ -0,0 +1,14 @@
+error: lifetime parameter `'a` never used
+  --> $DIR/zero-uses-in-fn.rs:17:6
+   |
+LL | fn d<'a>() { } //~ ERROR `'a` never used
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/zero-uses-in-fn.rs:13:9
+   |
+LL | #![deny(unused_lifetime)]
+   |         ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/single-use-lifetime/zero-uses-in-impl.rs b/src/test/ui/single-use-lifetime/zero-uses-in-impl.rs
new file mode 100644 (file)
index 0000000..6a09727
--- /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.
+
+// Test that we DO warn when lifetime name is not used at all.
+
+#![deny(unused_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo { }
+
+impl<'a> Foo { } //~ ERROR `'a` never used
+
+fn main() { }
diff --git a/src/test/ui/single-use-lifetime/zero-uses-in-impl.stderr b/src/test/ui/single-use-lifetime/zero-uses-in-impl.stderr
new file mode 100644 (file)
index 0000000..d2dd26e
--- /dev/null
@@ -0,0 +1,14 @@
+error: lifetime parameter `'a` never used
+  --> $DIR/zero-uses-in-impl.rs:19:6
+   |
+LL | impl<'a> Foo { } //~ ERROR `'a` never used
+   |      ^^
+   |
+note: lint level defined here
+  --> $DIR/zero-uses-in-impl.rs:13:9
+   |
+LL | #![deny(unused_lifetime)]
+   |         ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index adf6b85b6429c57e02a8cdef8d49ef7ac03e9231..b3e79ce2447fb564838d82ea413716b8c7ec8e03 100644 (file)
@@ -14,3 +14,7 @@ fn main() {
 fn foo<T>(x: T, y: T) {
     let z = x + y; //~ ERROR binary operation `+` cannot be applied to type `T`
 }
+
+fn bar<T>(x: T) {
+    x += x; //~ ERROR binary assignment operation `+=` cannot be applied to type `T`
+}
index 777f16b12ce683a4466b607fb344a3035453ec7d..4b01a626814e555a5427e4a316b65d970ef12c8a 100644 (file)
@@ -6,6 +6,17 @@ LL |     let z = x + y; //~ ERROR binary operation `+` cannot be applied to type
    |
    = note: `T` might need a bound for `std::ops::Add`
 
-error: aborting due to previous error
+error[E0368]: binary assignment operation `+=` cannot be applied to type `T`
+  --> $DIR/missing_trait_impl.rs:19:5
+   |
+LL |     x += x; //~ ERROR binary assignment operation `+=` cannot be applied to type `T`
+   |     -^^^^^
+   |     |
+   |     cannot use `+=` on type `T`
+   |
+   = note: `T` might need a bound for `std::ops::AddAssign`
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0369`.
+Some errors occurred: E0368, E0369.
+For more information about an error, try `rustc --explain E0368`.
index e456241f18227c7eb8d78a45daa66c756a9b65e7..7a4c00c669b3bf0ffb24c7aa89a776cd48f1e2d0 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e456241f18227c7eb8d78a45daa66c756a9b65e7
+Subproject commit 7a4c00c669b3bf0ffb24c7aa89a776cd48f1e2d0
index 1bac9ef66bb81354e9b25f6e66ae05d916877ad1..4f18f238cab903af72e49191325c5c28ba385e1c 100644 (file)
@@ -2524,7 +2524,7 @@ fn run_rmake_test(&self) {
                 .env("IS_WINDOWS", "1")
                 .env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
                 .env("CC", format!("'{}' {}", self.config.cc, cflags))
-                .env("CXX", &self.config.cxx);
+                .env("CXX", format!("'{}'", &self.config.cxx));
         } else {
             cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags))
                 .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags))
index e0e1bd7ff778e5913b566c9e03224faecc0eb486..6a4c62c1673c3dabcc9a0c99018bd08fec46fda7 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e0e1bd7ff778e5913b566c9e03224faecc0eb486
+Subproject commit 6a4c62c1673c3dabcc9a0c99018bd08fec46fda7
index 9a87fcb00d526f4cc683cfbbf98b2bbc9446d0b7..c34cf1bd5ec09691c5993f0ae2facee2205c2eb0 100644 (file)
@@ -59,6 +59,7 @@
 static WHITELIST: &'static [Crate] = &[
     Crate("aho-corasick"),
     Crate("ar"),
+    Crate("arrayvec"),
     Crate("atty"),
     Crate("backtrace"),
     Crate("backtrace-sys"),
     Crate("cc"),
     Crate("cfg-if"),
     Crate("cmake"),
+    Crate("crossbeam-deque"),
+    Crate("crossbeam-epoch"),
+    Crate("crossbeam-utils"),
+    Crate("either"),
     Crate("ena"),
     Crate("env_logger"),
     Crate("filetime"),
@@ -82,7 +87,9 @@
     Crate("log"),
     Crate("log_settings"),
     Crate("memchr"),
+    Crate("memoffset"),
     Crate("miniz-sys"),
+    Crate("nodrop"),
     Crate("num_cpus"),
     Crate("owning_ref"),
     Crate("parking_lot"),
     Crate("regex-syntax"),
     Crate("remove_dir_all"),
     Crate("rustc-demangle"),
+    Crate("rustc-rayon"),
+    Crate("rustc-rayon-core"),
     Crate("scoped-tls"),
+    Crate("scopeguard"),
     Crate("smallvec"),
     Crate("stable_deref_trait"),
     Crate("tempdir"),
index ef8b55186b104e8c0ad67012bbc2cad53d455e91..363d01d964eb5da89624680234f263d03cfddf43 100644 (file)
@@ -22,12 +22,22 @@ pub fn check(path: &Path, bad: &mut bool) {
         &libcore_path,
         &mut |subpath| t!(subpath.strip_prefix(&libcore_path)).starts_with("tests"),
         &mut |subpath| {
-            if t!(read_to_string(subpath)).contains("#[test]") {
-                tidy_error!(
-                    bad,
-                    "{} contains #[test]; libcore tests must be placed inside `src/libcore/tests/`",
-                    subpath.display()
-                );
+            if let Some("rs") = subpath.extension().and_then(|e| e.to_str()) {
+                match read_to_string(subpath) {
+                    Ok(contents) => {
+                        if contents.contains("#[test]") {
+                            tidy_error!(
+                                bad,
+                                "{} contains #[test]; libcore tests must be placed inside \
+                                `src/libcore/tests/`",
+                                subpath.display()
+                            );
+                        }
+                    }
+                    Err(err) => {
+                        panic!("failed to read file {:?}: {}", subpath, err);
+                    }
+                }
             }
         },
     );