]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #53364 - varkor:gat-warn-broken, r=pnkfelix
authorkennytm <kennytm@gmail.com>
Thu, 16 Aug 2018 16:13:23 +0000 (00:13 +0800)
committerGitHub <noreply@github.com>
Thu, 16 Aug 2018 16:13:23 +0000 (00:13 +0800)
Warn if the user tries to use GATs

GATs are currently broken, but still accessible behind a feature gate. This leads to people attempting to use them and then immediately encountering ICEs (or other broken behaviour). Here, we emit a warning if the user tries to use any feature associated with GATs, hopefully making it obvious that ICEs and the like are expected. For the meantime, this seems better than continually getting reported errors (for example: [here](https://github.com/rust-lang/rust/issues?q=is%3Aissue+gat+is%3Aclosed) and [here](https://github.com/rust-lang/rust/issues?utf8=%E2%9C%93&q=is%3Aissue+generic_associated_types+is%3Aclosed)).

156 files changed:
.gitmodules
.travis.yml
config.toml.example
src/Cargo.lock
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/config.rs
src/bootstrap/configure.py
src/bootstrap/dist.rs
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/doc/unstable-book/src/language-features/on-unimplemented.md
src/liballoc/alloc.rs
src/libcore/iter/iterator.rs
src/libcore/iter/mod.rs
src/libcore/macros.rs
src/libpanic_unwind/dummy.rs [new file with mode: 0644]
src/libpanic_unwind/lib.rs
src/libpanic_unwind/macros.rs [new file with mode: 0644]
src/libpanic_unwind/wasm32.rs [deleted file]
src/librustc/lib.rs
src/librustc/middle/dataflow.rs [deleted file]
src/librustc/mir/mod.rs
src/librustc/mir/tcx.rs
src/librustc/traits/error_reporting.rs
src/librustc/traits/mod.rs
src/librustc/traits/on_unimplemented.rs
src/librustc/traits/select.rs
src/librustc/traits/structural_impls.rs
src/librustc_apfloat/ieee.rs
src/librustc_borrowck/borrowck/check_loans.rs
src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
src/librustc_borrowck/borrowck/gather_loans/mod.rs
src/librustc_borrowck/borrowck/mod.rs
src/librustc_borrowck/borrowck/move_data.rs
src/librustc_borrowck/dataflow.rs [new file with mode: 0644]
src/librustc_borrowck/graphviz.rs
src/librustc_borrowck/lib.rs
src/librustc_codegen_llvm/back/linker.rs
src/librustc_data_structures/transitive_relation.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/move_errors.rs
src/librustc_mir/borrow_check/mutability_errors.rs
src/librustc_mir/build/matches/mod.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/dataflow/move_paths/builder.rs
src/librustc_mir/dataflow/move_paths/mod.rs
src/librustc_mir/lib.rs
src/librustc_mir/util/mod.rs
src/librustc_target/spec/aarch64_pc_windows_msvc.rs [new file with mode: 0644]
src/librustc_target/spec/mod.rs
src/librustc_typeck/check/generator_interior.rs
src/librustc_typeck/check/wfcheck.rs
src/librustdoc/Cargo.toml
src/librustdoc/html/static/themes/dark.css
src/librustdoc/html/static/themes/light.css
src/libserialize/json.rs
src/libstd/sync/mpsc/mod.rs
src/libstd/sys/windows/backtrace/mod.rs
src/libstd/sys/windows/c.rs
src/libstd/sys/windows/mod.rs
src/libsyntax/attr/mod.rs
src/libsyntax/config.rs
src/libsyntax/feature_gate.rs
src/libsyntax/parse/attr.rs
src/libsyntax/parse/lexer/comments.rs
src/libsyntax/parse/lexer/mod.rs
src/libsyntax/parse/lexer/tokentrees.rs
src/libsyntax/parse/lexer/unicode_chars.rs
src/libsyntax/parse/parser.rs
src/libtest/lib.rs
src/test/compile-fail-fulldeps/issue-48941.rs
src/test/compile-fail-fulldeps/proc-macro/proc-macro-attributes.rs
src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs
src/test/parse-fail/attr-bad-meta-2.rs [new file with mode: 0644]
src/test/parse-fail/attr-bad-meta-3.rs [new file with mode: 0644]
src/test/parse-fail/attr-bad-meta.rs
src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-b.rs
src/test/run-pass-fulldeps/proc-macro/derive-b.rs
src/test/run-pass/generator/issue-52398.rs [new file with mode: 0644]
src/test/run-pass/nll/issue-53123-raw-pointer-cast.rs [new file with mode: 0644]
src/test/ui-fulldeps/proc-macro/attribute-spans-preserved.rs
src/test/ui-fulldeps/proc-macro/attribute-spans-preserved.stderr
src/test/ui-fulldeps/proc-macro/attribute-spans-preserved.stdout
src/test/ui/E0508-fail.ast.nll.stderr [new file with mode: 0644]
src/test/ui/E0508-fail.mir.stderr
src/test/ui/E0508.nll.stderr [new file with mode: 0644]
src/test/ui/access-mode-in-closures.nll.stderr
src/test/ui/attr-eq-token-tree.rs [new file with mode: 0644]
src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.nll.stderr
src/test/ui/borrowck/borrowck-in-static.nll.stderr
src/test/ui/borrowck/borrowck-issue-2657-2.nll.stderr
src/test/ui/borrowck/borrowck-move-by-capture.nll.stderr
src/test/ui/borrowck/borrowck-move-error-with-note.nll.stderr
src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.nll.stderr
src/test/ui/borrowck/borrowck-move-in-irrefut-pat.ast.nll.stderr
src/test/ui/borrowck/borrowck-move-in-irrefut-pat.mir.stderr
src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.nll.stderr [new file with mode: 0644]
src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.ast.nll.stderr
src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.mir.stderr
src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.nll.stderr
src/test/ui/borrowck/borrowck-move-out-of-vec-tail.nll.stderr
src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.nll.stderr
src/test/ui/borrowck/borrowck-vec-pattern-nesting.nll.stderr
src/test/ui/borrowck/issue-51415.nll.stderr
src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.nll.stderr
src/test/ui/by-move-pattern-binding.nll.stderr
src/test/ui/check-static-values-constraints.nll.stderr
src/test/ui/codemap_tests/overlapping_spans.nll.stderr
src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.nll.stderr
src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.nll.stderr
src/test/ui/error-codes/E0232.stderr
src/test/ui/error-codes/E0509.nll.stderr [new file with mode: 0644]
src/test/ui/issue-51602.rs [new file with mode: 0644]
src/test/ui/issue-51602.stderr [new file with mode: 0644]
src/test/ui/issues/issue-12567.nll.stderr
src/test/ui/issues/issue-17718-static-move.nll.stderr [new file with mode: 0644]
src/test/ui/issues/issue-20801.nll.stderr
src/test/ui/issues/issue-27060-2.stderr
src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.nll.stderr
src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.nll.stderr
src/test/ui/issues/issue-4335.nll.stderr
src/test/ui/macros/issue-30143.rs [new file with mode: 0644]
src/test/ui/macros/issue-30143.stderr [new file with mode: 0644]
src/test/ui/macros/macro-attribute.rs
src/test/ui/macros/macro-attribute.stderr
src/test/ui/macros/macros-nonfatal-errors.rs
src/test/ui/macros/macros-nonfatal-errors.stderr
src/test/ui/moves/move-out-of-slice-1.nll.stderr
src/test/ui/moves/moves-based-on-type-block-bad.nll.stderr
src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.nll.stderr
src/test/ui/nll/cannot-move-block-spans.nll.stderr
src/test/ui/nll/issue-52663-span-decl-captured-variable.rs [new file with mode: 0644]
src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr [new file with mode: 0644]
src/test/ui/nll/move-errors.stderr
src/test/ui/on-unimplemented/bad-annotation.rs
src/test/ui/on-unimplemented/bad-annotation.stderr
src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr
src/test/ui/std-uncopyable-atomics.nll.stderr [new file with mode: 0644]
src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.rs [new file with mode: 0644]
src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr [new file with mode: 0644]
src/test/ui/suggestions/dont-suggest-ref/move-into-closure.rs [new file with mode: 0644]
src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr [new file with mode: 0644]
src/test/ui/suggestions/dont-suggest-ref/simple.rs [new file with mode: 0644]
src/test/ui/suggestions/dont-suggest-ref/simple.stderr [new file with mode: 0644]
src/test/ui/unboxed-closures/unboxed-closure-illegal-move.nll.stderr
src/test/ui/unrestricted-attribute-tokens.rs [new file with mode: 0644]
src/tools/build-manifest/src/main.rs
src/tools/cargo
src/tools/clang [new submodule]
src/tools/clippy
src/tools/compiletest/src/json.rs
src/tools/lldb [new submodule]
src/tools/rust-installer
src/tools/tidy/src/lib.rs

index f3eb902709ca7167699e2c46eb6092a506774e10..1631daac76c2ce07b0cc807666e4f2287a9bcfa8 100644 (file)
 [submodule "src/libbacktrace"]
        path = src/libbacktrace
        url = https://github.com/rust-lang-nursery/libbacktrace
+[submodule "src/tools/lldb"]
+       path = src/tools/lldb
+       url = https://github.com/rust-lang-nursery/lldb/
+       branch = rust-release-70
+[submodule "src/tools/clang"]
+       path = src/tools/clang
+       url = https://github.com/rust-lang-nursery/clang/
+       branch = release_70
index d010a8370b502b2159ac4ecfe6750d6cda9a9303..7251a46cc5878156caa21f5881d8b1f9314ce4e0 100644 (file)
@@ -30,7 +30,7 @@ matrix:
 
     - env: >
         RUST_CHECK_TARGET=dist
-        RUST_CONFIGURE_ARGS="--enable-extended --enable-profiler"
+        RUST_CONFIGURE_ARGS="--enable-extended --enable-profiler --enable-lldb"
         SRC=.
         DEPLOY_ALT=1
         RUSTC_RETRY_LINKER_ON_SEGFAULT=1
@@ -85,7 +85,7 @@ matrix:
     # OSX 10.7 and `xcode7` is the latest Xcode able to compile LLVM for 10.7.
     - env: >
         RUST_CHECK_TARGET=dist
-        RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-full-tools --enable-profiler"
+        RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-full-tools --enable-profiler --enable-lldb"
         SRC=.
         DEPLOY=1
         RUSTC_RETRY_LINKER_ON_SEGFAULT=1
@@ -99,7 +99,7 @@ matrix:
 
     - env: >
         RUST_CHECK_TARGET=dist
-        RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler"
+        RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --enable-lldb"
         SRC=.
         DEPLOY=1
         RUSTC_RETRY_LINKER_ON_SEGFAULT=1
@@ -233,7 +233,8 @@ install:
         osx)
           if [[ "$RUST_CHECK_TARGET" == dist ]]; then
             travis_retry brew update &&
-            travis_retry brew install xz;
+            travis_retry brew install xz &&
+            travis_retry brew install swig;
           fi &&
           travis_retry curl -fo /usr/local/bin/sccache https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2018-04-02-sccache-x86_64-apple-darwin &&
             chmod +x /usr/local/bin/sccache &&
index eb7cd61a1b07e7a936e126db5f9e622421d291a5..107375ac5cc3a3fa0ce254f11adde571d29d6e60 100644 (file)
 # sysroot.
 #llvm-tools = false
 
+# Indicates whether LLDB will be made available in the sysroot.
+# This is only built if LLVM is also being built.
+#lldb = false
+
 # Whether to deny warnings in crates
 #deny-warnings = true
 
index 9465f45dc19a47edbf2b8dc582d7b96b3571e1f2..a8308eb403896a277e766c80bef7545d9ea54521 100644 (file)
@@ -187,7 +187,7 @@ dependencies = [
  "filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "git2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "git2-curl 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -197,7 +197,7 @@ dependencies = [
  "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "libgit2-sys 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libgit2-sys 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -234,7 +234,8 @@ dependencies = [
  "filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "git2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "git2-curl 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -244,10 +245,11 @@ dependencies = [
  "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazycell 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "libgit2-sys 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libgit2-sys 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl 0.10.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-workspace-hack 1.0.0",
  "rustfix 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -616,7 +618,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl 0.10.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -629,7 +631,7 @@ dependencies = [
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "schannel 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
  "socket2 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -643,7 +645,7 @@ dependencies = [
  "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -876,6 +878,15 @@ name = "futures"
 version = "0.1.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "fwdansi"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "termcolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "getopts"
 version = "0.2.17"
@@ -883,15 +894,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "git2"
-version = "0.7.3"
+version = "0.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "libgit2-sys 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libgit2-sys 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -901,7 +912,7 @@ version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "curl 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "git2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1015,7 +1026,7 @@ name = "installer"
 version = "0.0.0"
 dependencies = [
  "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1134,7 +1145,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "libgit2-sys"
-version = "0.7.6"
+version = "0.7.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1143,7 +1154,7 @@ dependencies = [
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "libssh2-sys 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -1155,7 +1166,7 @@ dependencies = [
  "cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1215,6 +1226,11 @@ name = "mac"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "macro-utils"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "maplit"
 version = "1.0.1"
@@ -1292,10 +1308,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "minifier"
-version = "0.0.14"
+version = "0.0.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1382,7 +1398,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "openssl"
-version = "0.10.10"
+version = "0.10.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1390,7 +1406,7 @@ dependencies = [
  "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.35 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1398,13 +1414,22 @@ name = "openssl-probe"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "openssl-src"
+version = "110.0.6+1.1.0h"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "openssl-sys"
-version = "0.9.33"
+version = "0.9.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-src 110.0.6+1.1.0h (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -2431,7 +2456,7 @@ dependencies = [
 name = "rustdoc"
 version = "0.0.0"
 dependencies = [
- "minifier 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "minifier 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -3163,8 +3188,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
 "checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b"
 "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c"
+"checksum fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34dd4c507af68d37ffef962063dfa1944ce0dd4d5b82043dbab1dabe088610c3"
 "checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05"
-"checksum git2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b87cffac882c99f9654ca5eb4c6c61527b47bc1e113304f8c57333567cd31f2"
+"checksum git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "591f8be1674b421644b6c030969520bc3fa12114d2eb467471982ed3e9584e71"
 "checksum git2-curl 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b502f6b1b467957403d168f0039e0c46fa6a1220efa2adaef25d5b267b5fe024"
 "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
 "checksum globset 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "142754da2c9b3722affd909f9e27f2a6700a7a303f362971e0a74c652005a43d"
@@ -3189,7 +3215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"
 "checksum lazycell 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d33a48d0365c96081958cc663eef834975cb1e8d8bea3378513fc72bdbf11e50"
 "checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
-"checksum libgit2-sys 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c9051a4b288ba6f8728e9e52bb2510816946b8bcb2e20259e4d4cdc93b9ecafd"
+"checksum libgit2-sys 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6ab62b46003ba97701554631fa570d9f7e7947e2480ae3d941e555a54a2c0f05"
 "checksum libssh2-sys 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c628b499e8d1a4f4bd09a95d6cb1f8aeb231b46a9d40959bbd0408f14dd63adf"
 "checksum libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "87f737ad6cc6fd6eefe3d9dc5412f1573865bded441300904d2f42269e140f16"
 "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
@@ -3197,6 +3223,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum log_settings 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19af41f0565d7c19b2058153ad0b42d4d5ce89ec4dbf06ed6741114a8b63e7cd"
 "checksum lzma-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d1eaa027402541975218bb0eec67d6b0412f6233af96e0d096d31dbdfd22e614"
 "checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
+"checksum macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2c4deaccc2ead6a28c16c0ba82f07d52b6475397415ce40876e559b0b0ea510"
 "checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43"
 "checksum markup5ever 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfedc97d5a503e96816d10fedcd5b42f760b2e525ce2f7ec71f6a41780548475"
 "checksum matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "835511bab37c34c47da5cb44844bea2cfde0236db0b506f90ea4224482c9774a"
@@ -3204,7 +3231,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
 "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
 "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
-"checksum minifier 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "78cb57f9a385530d60f2d67f6e108050b478b7a0ffd0bb9c350803e1356535dd"
+"checksum minifier 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9908ed7c62f990c21ab41fdca53a864a3ada0da69d8729c4de727b397e27bc11"
 "checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
 "checksum miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9224c91f82b3c47cf53dcf78dfaa20d6888fbcc5d272d5f2fcdf8a697f3c987d"
 "checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4"
@@ -3214,9 +3241,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe"
 "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
 "checksum open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c281318d992e4432cfa799969467003d05921582a7489a8325e37f8a450d5113"
-"checksum openssl 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ed18a0f40ec4e9a8a81f8865033d823b7195d16a0a5721e10963ee1b0c2980ca"
+"checksum openssl 0.10.11 (registry+https://github.com/rust-lang/crates.io-index)" = "6c24d3508b4fb6da175c10baac54c578b33f09c89ae90c6fe9788b3b4768efdc"
 "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
-"checksum openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)" = "d8abc04833dcedef24221a91852931df2f63e3369ae003134e70aff3645775cc"
+"checksum openssl-src 110.0.6+1.1.0h (registry+https://github.com/rust-lang/crates.io-index)" = "2011250f011d9c0f2e982f36721c9cbf451a9b04f425ea43a6a3f1bfa889a3b4"
+"checksum openssl-sys 0.9.35 (registry+https://github.com/rust-lang/crates.io-index)" = "912f301a749394e1025d9dcddef6106ddee9252620e6d0a0e5f8d0681de9b129"
 "checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
 "checksum ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd20eec3dbe4376829cb7d80ae6ac45e0a766831dca50202ff2d40db46a8a024"
 "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
index 829487163a945ec21f9850c997901520105ec9b4..d9c66ce2d77905614b5f242c68bfafc123bc7d48 100644 (file)
@@ -721,6 +721,10 @@ class RustBuild(object):
                 config = self.get_toml('lld')
                 if config is None or config == 'false':
                     continue
+            if module.endswith("lldb") or module.endswith("clang"):
+                config = self.get_toml('lldb')
+                if config is None or config == 'false':
+                    continue
             check = self.check_submodule(module, slow_submodules)
             filtered_submodules.append((module, check))
             submodules_names.append(module)
index dc0b0aaf0bb3c894802f18be4d2e21e94b11a57c..12c1972c22039aa4b4b8a498b326bfc70823269a 100644 (file)
@@ -461,6 +461,7 @@ macro_rules! describe {
                 dist::Rustfmt,
                 dist::Clippy,
                 dist::LlvmTools,
+                dist::Lldb,
                 dist::Extended,
                 dist::HashSign
             ),
index 1a94d597ef895d6e5ba8b0cdc0ceab073ca1ffec..43650332d3b67c901df7c8783b09953cd175401d 100644 (file)
@@ -87,6 +87,7 @@ pub struct Config {
     pub llvm_link_jobs: Option<u32>,
 
     pub lld_enabled: bool,
+    pub lldb_enabled: bool,
     pub llvm_tools_enabled: bool,
 
     // rust codegen options
@@ -310,6 +311,7 @@ struct Rust {
     codegen_backends_dir: Option<String>,
     wasm_syscall: Option<bool>,
     lld: Option<bool>,
+    lldb: Option<bool>,
     llvm_tools: Option<bool>,
     deny_warnings: Option<bool>,
     backtrace_on_ice: Option<bool>,
@@ -538,6 +540,7 @@ pub fn parse(args: &[String]) -> Config {
             }
             set(&mut config.wasm_syscall, rust.wasm_syscall);
             set(&mut config.lld_enabled, rust.lld);
+            set(&mut config.lldb_enabled, rust.lldb);
             set(&mut config.llvm_tools_enabled, rust.llvm_tools);
             config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false);
             config.rustc_default_linker = rust.default_linker.clone();
index 9fdba044f4be3da82b035e5bc110c4a477f9085d..cf7f78eeba04b13b16e3d64de41efd7609c1f8ca 100755 (executable)
@@ -68,6 +68,7 @@ o("cargo-openssl-static", "build.openssl-static", "static openssl in cargo")
 o("profiler", "build.profiler", "build the profiler runtime")
 o("emscripten", None, "compile the emscripten backend as well as LLVM")
 o("full-tools", None, "enable all tools")
+o("lldb", "rust.lldb", "build lldb")
 
 # Optimization and debugging options. These may be overridden by the release
 # channel, etc.
@@ -350,7 +351,7 @@ set('build.configure-args', sys.argv[1:])
 # all the various comments and whatnot.
 #
 # Note that the `target` section is handled separately as we'll duplicate it
-# per configure dtarget, so there's a bit of special handling for that here.
+# per configuretarget, so there's a bit of special handling for that here.
 sections = {}
 cur_section = None
 sections[None] = []
index 188e64cd668ddc6bb2bdc68c34051254656d1a7a..6e473fae3be5c0208279c662f12e0ead34e9bca1 100644 (file)
@@ -47,6 +47,8 @@ pub fn pkgname(builder: &Builder, component: &str) -> String {
         format!("{}-{}", component, builder.rustfmt_package_vers())
     } else if component == "llvm-tools" {
         format!("{}-{}", component, builder.llvm_tools_package_vers())
+    } else if component == "lldb" {
+        format!("{}-{}", component, builder.lldb_package_vers())
     } else {
         assert!(component.starts_with("rust"));
         format!("{}-{}", component, builder.rust_package_vers())
@@ -1396,6 +1398,7 @@ fn run(self, builder: &Builder) {
         let rls_installer = builder.ensure(Rls { stage, target });
         let llvm_tools_installer = builder.ensure(LlvmTools { stage, target });
         let clippy_installer = builder.ensure(Clippy { stage, target });
+        let lldb_installer = builder.ensure(Lldb { target });
         let mingw_installer = builder.ensure(Mingw { host: target });
         let analysis_installer = builder.ensure(Analysis {
             compiler: builder.compiler(stage, self.host),
@@ -1435,6 +1438,7 @@ fn run(self, builder: &Builder) {
         tarballs.extend(clippy_installer.clone());
         tarballs.extend(rustfmt_installer.clone());
         tarballs.extend(llvm_tools_installer.clone());
+        tarballs.extend(lldb_installer.clone());
         tarballs.push(analysis_installer);
         tarballs.push(std_installer);
         if builder.config.docs {
@@ -1869,6 +1873,7 @@ fn run(self, builder: &Builder) {
         cmd.arg(builder.package_vers(&builder.release_num("clippy")));
         cmd.arg(builder.package_vers(&builder.release_num("rustfmt")));
         cmd.arg(builder.llvm_tools_package_vers());
+        cmd.arg(builder.lldb_package_vers());
         cmd.arg(addr);
 
         builder.create_dir(&distdir(builder));
@@ -1963,3 +1968,121 @@ fn run(self, builder: &Builder) -> Option<PathBuf> {
         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
     }
 }
+
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+pub struct Lldb {
+    pub target: Interned<String>,
+}
+
+impl Step for Lldb {
+    type Output = Option<PathBuf>;
+    const ONLY_HOSTS: bool = true;
+    const DEFAULT: bool = true;
+
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/tools/lldb")
+    }
+
+    fn make_run(run: RunConfig) {
+        run.builder.ensure(Lldb {
+            target: run.target,
+        });
+    }
+
+    fn run(self, builder: &Builder) -> Option<PathBuf> {
+        let target = self.target;
+
+        if builder.config.dry_run {
+            return None;
+        }
+
+        let bindir = builder
+            .llvm_out(target)
+            .join("bin");
+        let lldb_exe = bindir.join(exe("lldb", &target));
+        if !lldb_exe.exists() {
+            return None;
+        }
+
+        builder.info(&format!("Dist Lldb ({})", target));
+        let src = builder.src.join("src/tools/lldb");
+        let name = pkgname(builder, "lldb");
+
+        let tmp = tmpdir(builder);
+        let image = tmp.join("lldb-image");
+        drop(fs::remove_dir_all(&image));
+
+        // Prepare the image directory
+        let dst = image.join("bin");
+        t!(fs::create_dir_all(&dst));
+        for program in &["lldb", "lldb-argdumper", "lldb-mi", "lldb-server"] {
+            let exe = bindir.join(exe(program, &target));
+            builder.install(&exe, &dst, 0o755);
+        }
+
+        // The libraries.
+        let libdir = builder.llvm_out(target).join("lib");
+        let dst = image.join("lib");
+        t!(fs::create_dir_all(&dst));
+        for entry in t!(fs::read_dir(&libdir)) {
+            // let entry = t!(entry);
+            let entry = entry.unwrap();
+            if let Ok(name) = entry.file_name().into_string() {
+                if name.starts_with("liblldb.") && !name.ends_with(".a") {
+                    if t!(entry.file_type()).is_symlink() {
+                        builder.copy_to_folder(&entry.path(), &dst);
+                    } else {
+                       builder.install(&entry.path(), &dst, 0o755);
+                    }
+                }
+            }
+        }
+
+        // The lldb scripts might be installed in lib/python$version
+        // or in lib64/python$version.  If lib64 exists, use it;
+        // otherwise lib.
+        let libdir = builder.llvm_out(target).join("lib64");
+        let (libdir, libdir_name) = if libdir.exists() {
+            (libdir, "lib64")
+        } else {
+            (builder.llvm_out(target).join("lib"), "lib")
+        };
+        for entry in t!(fs::read_dir(&libdir)) {
+            let entry = t!(entry);
+            if let Ok(name) = entry.file_name().into_string() {
+                if name.starts_with("python") {
+                    let dst = image.join(libdir_name)
+                        .join(entry.file_name());
+                    t!(fs::create_dir_all(&dst));
+                    builder.cp_r(&entry.path(), &dst);
+                    break;
+                }
+            }
+        }
+
+        // Prepare the overlay
+        let overlay = tmp.join("lldb-overlay");
+        drop(fs::remove_dir_all(&overlay));
+        builder.create_dir(&overlay);
+        builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644);
+        builder.create(&overlay.join("version"), &builder.lldb_vers());
+
+        // Generate the installer tarball
+        let mut cmd = rust_installer(builder);
+        cmd.arg("generate")
+            .arg("--product-name=Rust")
+            .arg("--rel-manifest-dir=rustlib")
+            .arg("--success-message=lldb-installed.")
+            .arg("--image-dir").arg(&image)
+            .arg("--work-dir").arg(&tmpdir(builder))
+            .arg("--output-dir").arg(&distdir(builder))
+            .arg("--non-installed-overlay").arg(&overlay)
+            .arg(format!("--package-name={}-{}", name, target))
+            .arg("--legacy-manifest-dirs=rustlib,cargo")
+            .arg("--component-name=lldb-preview");
+
+
+        builder.run(&mut cmd);
+        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
+    }
+}
index 38965949bf22f6ce594090aa6c25812c4549f32f..5bb475e07ba8db1fb4ae46b6180b96f1a267b12d 100644 (file)
 use std::slice;
 use std::str;
 
+#[cfg(unix)]
+use std::os::unix::fs::symlink as symlink_file;
+#[cfg(windows)]
+use std::os::windows::fs::symlink_file;
+
 use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime};
 use filetime::FileTime;
 
@@ -1005,6 +1010,14 @@ fn llvm_tools_vers(&self) -> String {
         self.rust_version()
     }
 
+    fn lldb_package_vers(&self) -> String {
+        self.package_vers(&self.rust_version())
+    }
+
+    fn lldb_vers(&self) -> String {
+        self.rust_version()
+    }
+
     /// Returns the `version` string associated with this compiler for Rust
     /// itself.
     ///
@@ -1123,20 +1136,24 @@ fn read_stamp_file(&self, stamp: &Path) -> Vec<PathBuf> {
     pub fn copy(&self, src: &Path, dst: &Path) {
         if self.config.dry_run { return; }
         let _ = fs::remove_file(&dst);
-        // Attempt to "easy copy" by creating a hard link (symlinks don't work on
-        // windows), but if that fails just fall back to a slow `copy` operation.
-        if let Ok(()) = fs::hard_link(src, dst) {
-            return
-        }
-        if let Err(e) = fs::copy(src, dst) {
-            panic!("failed to copy `{}` to `{}`: {}", src.display(),
-                dst.display(), e)
+        let metadata = t!(src.symlink_metadata());
+        if metadata.file_type().is_symlink() {
+            let link = t!(fs::read_link(src));
+            t!(symlink_file(link, dst));
+        } else if let Ok(()) = fs::hard_link(src, dst) {
+            // Attempt to "easy copy" by creating a hard link
+            // (symlinks don't work on windows), but if that fails
+            // just fall back to a slow `copy` operation.
+        } else {
+            if let Err(e) = fs::copy(src, dst) {
+                panic!("failed to copy `{}` to `{}`: {}", src.display(),
+                       dst.display(), e)
+            }
+            t!(fs::set_permissions(dst, metadata.permissions()));
+            let atime = FileTime::from_last_access_time(&metadata);
+            let mtime = FileTime::from_last_modification_time(&metadata);
+            t!(filetime::set_file_times(dst, atime, mtime));
         }
-        let metadata = t!(src.metadata());
-        t!(fs::set_permissions(dst, metadata.permissions()));
-        let atime = FileTime::from_last_access_time(&metadata);
-        let mtime = FileTime::from_last_modification_time(&metadata);
-        t!(filetime::set_file_times(dst, atime, mtime));
     }
 
     /// Search-and-replaces within a file. (Not maximally efficiently: allocates a
index d5e1ed02b44c173d5e4159b35e92f70a7de0b4b0..c99347aa94e6637548a86f2e49cf15262ad33775 100644 (file)
@@ -149,7 +149,6 @@ fn run(self, builder: &Builder) -> PathBuf {
            .define("WITH_POLLY", "OFF")
            .define("LLVM_ENABLE_TERMINFO", "OFF")
            .define("LLVM_ENABLE_LIBEDIT", "OFF")
-           .define("LLVM_ENABLE_LIBXML2", "OFF")
            .define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string())
            .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
            .define("LLVM_DEFAULT_TARGET_TRIPLE", target);
@@ -163,6 +162,8 @@ fn run(self, builder: &Builder) -> PathBuf {
         cfg.define("LLVM_OCAML_INSTALL_PATH",
             env::var_os("LLVM_OCAML_INSTALL_PATH").unwrap_or_else(|| "usr/lib/ocaml".into()));
 
+        let want_lldb = builder.config.lldb_enabled && !self.emscripten;
+
         // This setting makes the LLVM tools link to the dynamic LLVM library,
         // which saves both memory during parallel links and overall disk space
         // for the tools.  We don't distribute any of those tools, so this is
@@ -170,12 +171,13 @@ fn run(self, builder: &Builder) -> PathBuf {
         //
         // If we are shipping llvm tools then we statically link them LLVM
         if (target.contains("linux-gnu") || target.contains("apple-darwin")) &&
-            !builder.config.llvm_tools_enabled {
+            !builder.config.llvm_tools_enabled &&
+            !want_lldb {
                 cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
         }
 
         // For distribution we want the LLVM tools to be *statically* linked to libstdc++
-        if builder.config.llvm_tools_enabled {
+        if builder.config.llvm_tools_enabled || want_lldb {
             if !target.contains("windows") {
                 if target.contains("apple") {
                     cfg.define("CMAKE_EXE_LINKER_FLAGS", "-static-libstdc++");
@@ -196,6 +198,17 @@ fn run(self, builder: &Builder) -> PathBuf {
             cfg.define("LLVM_BUILD_32_BITS", "ON");
         }
 
+        if want_lldb {
+            cfg.define("LLVM_EXTERNAL_CLANG_SOURCE_DIR", builder.src.join("src/tools/clang"));
+            cfg.define("LLVM_EXTERNAL_LLDB_SOURCE_DIR", builder.src.join("src/tools/lldb"));
+            // For the time being, disable code signing.
+            cfg.define("LLDB_CODESIGN_IDENTITY", "");
+        } else {
+            // LLDB requires libxml2; but otherwise we want it to be disabled.
+            // See https://github.com/rust-lang/rust/pull/50104
+            cfg.define("LLVM_ENABLE_LIBXML2", "OFF");
+        }
+
         if let Some(num_linkers) = builder.config.llvm_link_jobs {
             if num_linkers > 0 {
                 cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string());
index 70c7c110b786a9569effe2e359764357b228e527..f787f629756f32b38fc41418eed8540fe5ce9a76 100644 (file)
@@ -8,7 +8,9 @@ The tracking issue for this feature is: [#29628]
 
 The `on_unimplemented` feature provides the `#[rustc_on_unimplemented]`
 attribute, which allows trait definitions to add specialized notes to error
-messages when an implementation was expected but not found.
+messages when an implementation was expected but not found. You can refer
+to the trait's generic arguments by name and to the resolved type using
+`Self`.
 
 For example:
 
@@ -41,7 +43,98 @@ error[E0277]: the trait bound `&[{integer}]: MyIterator<char>` is not satisfied
    |
    = help: the trait `MyIterator<char>` is not implemented for `&[{integer}]`
    = note: required by `iterate_chars`
+```
+
+`on_unimplemented` also supports advanced filtering for better targeting
+of messages, as well as modifying specific parts of the error message. You
+target the text of:
+
+ - the main error message (`message`)
+ - the label (`label`)
+ - an extra note (`note`)
+
+For example, the following attribute
+
+```rust,compile_fail
+#[rustc_on_unimplemented(
+    message="message",
+    label="label",
+    note="note"
+)]
+trait MyIterator<A> {
+    fn next(&mut self) -> A;
+}
+```
+
+Would generate the following output:
+
+```text
+error[E0277]: message
+  --> <anon>:14:5
+   |
+14 |     iterate_chars(&[1, 2, 3][..]);
+   |     ^^^^^^^^^^^^^ label
+   |
+   = note: note
+   = help: the trait `MyIterator<char>` is not implemented for `&[{integer}]`
+   = note: required by `iterate_chars`
+```
+
+To allow more targeted error messages, it is possible to filter the
+application of these fields based on a variety of attributes when using
+`on`:
 
-error: aborting due to previous error
+ - `crate_local`: whether the code causing the trait bound to not be
+   fulfilled is part of the user's crate. This is used to avoid suggesting
+   code changes that would require modifying a dependency.
+ - Any of the generic arguments that can be substituted in the text can be
+   referred by name as well for filtering, like `Rhs="i32"`, except for
+   `Self`.
+ - `_Self`: to filter only on a particular calculated trait resolution, like
+   `Self="std::iter::Iterator<char>"`. This is needed because `Self` is a
+   keyword which cannot appear in attributes.
+ - `direct`: user-specified rather than derived obligation.
+ - `from_method`: usable both as boolean (whether the flag is present, like
+   `crate_local`) or matching against a particular method. Currently used
+   for `try`.
+ - `from_desugaring`: usable both as boolean (whether the flag is present)
+   or matching against a particular desugaring.
+
+For example, the `Iterator` trait can be annotated in the following way:
+
+```rust,compile_fail
+#[rustc_on_unimplemented(
+    on(
+        _Self="&str",
+        note="call `.chars()` or `.as_bytes()` on `{Self}"
+    ),
+    message="`{Self}` is not an iterator",
+    label="`{Self}` is not an iterator",
+    note="maybe try calling `.iter()` or a similar method"
+)]
+pub trait Iterator {}
 ```
 
+Which would produce the following outputs:
+
+```text
+error[E0277]: `Foo` is not an iterator
+ --> src/main.rs:4:16
+  |
+4 |     for foo in Foo {}
+  |                ^^^ `Foo` is not an iterator
+  |
+  = note: maybe try calling `.iter()` or a similar method
+  = help: the trait `std::iter::Iterator` is not implemented for `Foo`
+  = note: required by `std::iter::IntoIterator::into_iter`
+
+error[E0277]: `&str` is not an iterator
+ --> src/main.rs:5:16
+  |
+5 |     for foo in "" {}
+  |                ^^ `&str` is not an iterator
+  |
+  = note: call `.chars()` or `.bytes() on `&str`
+  = help: the trait `std::iter::Iterator` is not implemented for `&str`
+  = note: required by `std::iter::IntoIterator::into_iter`
+```
index 84bd275df347c9c73b376c37e900ff3212be6900..c69b2fb5e1c2a3e27619f5994f767d8f49d036db 100644 (file)
@@ -56,6 +56,22 @@ fn __rust_realloc(ptr: *mut u8,
 /// # Safety
 ///
 /// See [`GlobalAlloc::alloc`].
+///
+/// # Examples
+///
+/// ```
+/// use std::alloc::{alloc, dealloc, Layout};
+///
+/// unsafe {
+///     let layout = Layout::new::<u16>();
+///     let ptr = alloc(layout);
+///
+///     *(ptr as *mut u16) = 42;
+///     assert_eq!(*(ptr as *mut u16), 42);
+///
+///     dealloc(ptr, layout);
+/// }
+/// ```
 #[stable(feature = "global_alloc", since = "1.28.0")]
 #[inline]
 pub unsafe fn alloc(layout: Layout) -> *mut u8 {
@@ -110,6 +126,21 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8
 /// # Safety
 ///
 /// See [`GlobalAlloc::alloc_zeroed`].
+///
+/// # Examples
+///
+/// ```
+/// use std::alloc::{alloc_zeroed, dealloc, Layout};
+///
+/// unsafe {
+///     let layout = Layout::new::<u16>();
+///     let ptr = alloc_zeroed(layout);
+///
+///     assert_eq!(*(ptr as *mut u16), 0);
+///
+///     dealloc(ptr, layout);
+/// }
+/// ```
 #[stable(feature = "global_alloc", since = "1.28.0")]
 #[inline]
 pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
index 5681cfb04f2088c1fece1a7ede7c9d835b3eb0b5..3918529105334b23ff2aa614beb704f37b2106df 100644 (file)
@@ -1110,7 +1110,7 @@ fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
     ///
     /// [`flat_map()`]: #method.flat_map
     #[inline]
-    #[stable(feature = "iterator_flatten", since = "1.29")]
+    #[stable(feature = "iterator_flatten", since = "1.29.0")]
     fn flatten(self) -> Flatten<Self>
     where Self: Sized, Self::Item: IntoIterator {
         Flatten { inner: flatten_compat(self) }
index 35ae77411069cdf5c9a63fda2fedc313dad341b3..ef3f4ced4f9b2306fbaea947ab63acf690a3c584 100644 (file)
@@ -2577,13 +2577,13 @@ impl<I, U, F> FusedIterator for FlatMap<I, U, F>
 /// [`flatten`]: trait.Iterator.html#method.flatten
 /// [`Iterator`]: trait.Iterator.html
 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
-#[stable(feature = "iterator_flatten", since = "1.29")]
+#[stable(feature = "iterator_flatten", since = "1.29.0")]
 pub struct Flatten<I: Iterator>
 where I::Item: IntoIterator {
     inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>,
 }
 
-#[stable(feature = "iterator_flatten", since = "1.29")]
+#[stable(feature = "iterator_flatten", since = "1.29.0")]
 impl<I, U> fmt::Debug for Flatten<I>
     where I: Iterator + fmt::Debug, U: Iterator + fmt::Debug,
           I::Item: IntoIterator<IntoIter = U, Item = U::Item>,
@@ -2593,7 +2593,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-#[stable(feature = "iterator_flatten", since = "1.29")]
+#[stable(feature = "iterator_flatten", since = "1.29.0")]
 impl<I, U> Clone for Flatten<I>
     where I: Iterator + Clone, U: Iterator + Clone,
           I::Item: IntoIterator<IntoIter = U, Item = U::Item>,
@@ -2601,7 +2601,7 @@ impl<I, U> Clone for Flatten<I>
     fn clone(&self) -> Self { Flatten { inner: self.inner.clone() } }
 }
 
-#[stable(feature = "iterator_flatten", since = "1.29")]
+#[stable(feature = "iterator_flatten", since = "1.29.0")]
 impl<I, U> Iterator for Flatten<I>
     where I: Iterator, U: Iterator,
           I::Item: IntoIterator<IntoIter = U, Item = U::Item>
@@ -2629,7 +2629,7 @@ fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
     }
 }
 
-#[stable(feature = "iterator_flatten", since = "1.29")]
+#[stable(feature = "iterator_flatten", since = "1.29.0")]
 impl<I, U> DoubleEndedIterator for Flatten<I>
     where I: DoubleEndedIterator, U: DoubleEndedIterator,
           I::Item: IntoIterator<IntoIter = U, Item = U::Item>
@@ -2652,7 +2652,7 @@ fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
     }
 }
 
-#[stable(feature = "iterator_flatten", since = "1.29")]
+#[stable(feature = "iterator_flatten", since = "1.29.0")]
 impl<I, U> FusedIterator for Flatten<I>
     where I: FusedIterator, U: Iterator,
           I::Item: IntoIterator<IntoIter = U, Item = U::Item> {}
index 83f9dfea8f2676059c9dc6cf4c0617534ddd6201..5b3b2d1635688e8c04d5d9ee93e97321e2825a50 100644 (file)
@@ -396,6 +396,7 @@ macro_rules! write {
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[allow_internal_unstable]
 macro_rules! writeln {
     ($dst:expr) => (
         write!($dst, "\n")
@@ -403,11 +404,8 @@ macro_rules! writeln {
     ($dst:expr,) => (
         writeln!($dst)
     );
-    ($dst:expr, $fmt:expr) => (
-        write!($dst, concat!($fmt, "\n"))
-    );
-    ($dst:expr, $fmt:expr, $($arg:tt)*) => (
-        write!($dst, concat!($fmt, "\n"), $($arg)*)
+    ($dst:expr, $($arg:tt)*) => (
+        $dst.write_fmt(format_args_nl!($($arg)*))
     );
 }
 
diff --git a/src/libpanic_unwind/dummy.rs b/src/libpanic_unwind/dummy.rs
new file mode 100644 (file)
index 0000000..7150560
--- /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.
+
+//! Unwinding for wasm32
+//!
+//! Right now we don't support this, so this is just stubs
+
+use alloc::boxed::Box;
+use core::any::Any;
+use core::intrinsics;
+
+pub fn payload() -> *mut u8 {
+    0 as *mut u8
+}
+
+pub unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> {
+    intrinsics::abort()
+}
+
+pub unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 {
+    intrinsics::abort()
+}
index a61b2c1f06394aaabfb1775b09abe902f99c6d21..9c3fc76c307a6f7696ba4ce2f163c1dea7812602 100644 (file)
 use core::raw;
 use core::panic::BoxMeUp;
 
-// Rust runtime's startup objects depend on these symbols, so make them public.
-#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
-pub use imp::eh_frame_registry::*;
+#[macro_use]
+mod macros;
 
-// *-pc-windows-msvc
-#[cfg(target_env = "msvc")]
-#[path = "seh.rs"]
-mod imp;
-
-// x86_64-pc-windows-gnu
-#[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))]
-#[path = "seh64_gnu.rs"]
-mod imp;
-
-// i686-pc-windows-gnu and all others
-#[cfg(any(all(unix, not(target_os = "emscripten")),
-          target_os = "cloudabi",
-          target_os = "redox",
-          all(windows, target_arch = "x86", target_env = "gnu")))]
-#[path = "gcc.rs"]
-mod imp;
-
-// emscripten
-#[cfg(target_os = "emscripten")]
-#[path = "emcc.rs"]
-mod imp;
-
-#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
-#[path = "wasm32.rs"]
-mod imp;
+cfg_if! {
+    if #[cfg(target_os = "emscripten")] {
+        #[path = "emcc.rs"]
+        mod imp;
+    } else if #[cfg(target_arch = "wasm32")] {
+        #[path = "dummy.rs"]
+        mod imp;
+    } else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] {
+        #[path = "dummy.rs"]
+        mod imp;
+    } else if #[cfg(target_env = "msvc")] {
+        #[path = "seh.rs"]
+        mod imp;
+    } else if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
+        #[path = "seh64_gnu.rs"]
+        mod imp;
+    } else {
+        // Rust runtime's startup objects depend on these symbols, so make them public.
+        #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
+        pub use imp::eh_frame_registry::*;
+        #[path = "gcc.rs"]
+        mod imp;
+    }
+}
 
 mod dwarf;
 mod windows;
diff --git a/src/libpanic_unwind/macros.rs b/src/libpanic_unwind/macros.rs
new file mode 100644 (file)
index 0000000..6ea79dc
--- /dev/null
@@ -0,0 +1,45 @@
+// 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.
+
+/// A macro for defining `#[cfg]` if-else statements.
+///
+/// This is similar to the `if/elif` C preprocessor macro by allowing definition
+/// of a cascade of `#[cfg]` cases, emitting the implementation which matches
+/// first.
+///
+/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
+/// without having to rewrite each clause multiple times.
+macro_rules! cfg_if {
+    ($(
+        if #[cfg($($meta:meta),*)] { $($it:item)* }
+    ) else * else {
+        $($it2:item)*
+    }) => {
+        __cfg_if_items! {
+            () ;
+            $( ( ($($meta),*) ($($it)*) ), )*
+            ( () ($($it2)*) ),
+        }
+    }
+}
+
+macro_rules! __cfg_if_items {
+    (($($not:meta,)*) ; ) => {};
+    (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
+        __cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* }
+        __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
+    }
+}
+
+macro_rules! __cfg_if_apply {
+    ($m:meta, $($it:item)*) => {
+        $(#[$m] $it)*
+    }
+}
diff --git a/src/libpanic_unwind/wasm32.rs b/src/libpanic_unwind/wasm32.rs
deleted file mode 100644 (file)
index 7150560..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Unwinding for wasm32
-//!
-//! Right now we don't support this, so this is just stubs
-
-use alloc::boxed::Box;
-use core::any::Any;
-use core::intrinsics;
-
-pub fn payload() -> *mut u8 {
-    0 as *mut u8
-}
-
-pub unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> {
-    intrinsics::abort()
-}
-
-pub unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 {
-    intrinsics::abort()
-}
index e250b7549a0520484e6ee7e02da32d4ec1f36c5c..b6f4bd6dc408c9ffb4dfa10b2b7a935ad741434c 100644 (file)
@@ -135,7 +135,6 @@ pub mod middle {
     pub mod borrowck;
     pub mod expr_use_visitor;
     pub mod cstore;
-    pub mod dataflow;
     pub mod dead;
     pub mod dependency_format;
     pub mod entry;
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
deleted file mode 100644 (file)
index b949fd0..0000000
+++ /dev/null
@@ -1,686 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-//! A module for propagating forward dataflow information. The analysis
-//! assumes that the items to be propagated can be represented as bits
-//! and thus uses bitvectors. Your job is simply to specify the so-called
-//! GEN and KILL bits for each expression.
-
-use cfg;
-use cfg::CFGIndex;
-use ty::TyCtxt;
-use std::io;
-use std::mem;
-use std::usize;
-use syntax::print::pprust::PrintState;
-
-use rustc_data_structures::graph::implementation::OUTGOING;
-
-use util::nodemap::FxHashMap;
-use hir;
-use hir::intravisit::{self, IdRange};
-use hir::print as pprust;
-
-
-#[derive(Copy, Clone, Debug)]
-pub enum EntryOrExit {
-    Entry,
-    Exit,
-}
-
-#[derive(Clone)]
-pub struct DataFlowContext<'a, 'tcx: 'a, O> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-
-    /// a name for the analysis using this dataflow instance
-    analysis_name: &'static str,
-
-    /// the data flow operator
-    oper: O,
-
-    /// number of bits to propagate per id
-    bits_per_id: usize,
-
-    /// number of words we will use to store bits_per_id.
-    /// equal to bits_per_id/usize::BITS rounded up.
-    words_per_id: usize,
-
-    // mapping from node to cfg node index
-    // FIXME (#6298): Shouldn't this go with CFG?
-    local_id_to_index: FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>,
-
-    // Bit sets per cfg node.  The following three fields (`gens`, `kills`,
-    // and `on_entry`) all have the same structure. For each id in
-    // `id_range`, there is a range of words equal to `words_per_id`.
-    // So, to access the bits for any given id, you take a slice of
-    // the full vector (see the method `compute_id_range()`).
-
-    /// bits generated as we exit the cfg node. Updated by `add_gen()`.
-    gens: Vec<usize>,
-
-    /// bits killed as we exit the cfg node, or non-locally jump over
-    /// it. Updated by `add_kill(KillFrom::ScopeEnd)`.
-    scope_kills: Vec<usize>,
-
-    /// bits killed as we exit the cfg node directly; if it is jumped
-    /// over, e.g. via `break`, the kills are not reflected in the
-    /// jump's effects. Updated by `add_kill(KillFrom::Execution)`.
-    action_kills: Vec<usize>,
-
-    /// bits that are valid on entry to the cfg node. Updated by
-    /// `propagate()`.
-    on_entry: Vec<usize>,
-}
-
-pub trait BitwiseOperator {
-    /// Joins two predecessor bits together, typically either `|` or `&`
-    fn join(&self, succ: usize, pred: usize) -> usize;
-}
-
-/// Parameterization for the precise form of data flow that is used.
-pub trait DataFlowOperator : BitwiseOperator {
-    /// Specifies the initial value for each bit in the `on_entry` set
-    fn initial_value(&self) -> bool;
-}
-
-struct PropagationContext<'a, 'b: 'a, 'tcx: 'b, O: 'a> {
-    dfcx: &'a mut DataFlowContext<'b, 'tcx, O>,
-    changed: bool
-}
-
-fn get_cfg_indices<'a>(id: hir::ItemLocalId,
-                       index: &'a FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>)
-                       -> &'a [CFGIndex] {
-    index.get(&id).map_or(&[], |v| &v[..])
-}
-
-impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
-    fn has_bitset_for_local_id(&self, n: hir::ItemLocalId) -> bool {
-        assert!(n != hir::DUMMY_ITEM_LOCAL_ID);
-        self.local_id_to_index.contains_key(&n)
-    }
-}
-
-impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O> {
-    fn nested(&self, state: &mut pprust::State, nested: pprust::Nested) -> io::Result<()> {
-        pprust::PpAnn::nested(&self.tcx.hir, state, nested)
-    }
-    fn pre(&self,
-           ps: &mut pprust::State,
-           node: pprust::AnnNode) -> io::Result<()> {
-        let id = match node {
-            pprust::NodeName(_) => return Ok(()),
-            pprust::NodeExpr(expr) => expr.hir_id.local_id,
-            pprust::NodeBlock(blk) => blk.hir_id.local_id,
-            pprust::NodeItem(_) |
-            pprust::NodeSubItem(_) => return Ok(()),
-            pprust::NodePat(pat) => pat.hir_id.local_id
-        };
-
-        if !self.has_bitset_for_local_id(id) {
-            return Ok(());
-        }
-
-        assert!(self.bits_per_id > 0);
-        let indices = get_cfg_indices(id, &self.local_id_to_index);
-        for &cfgidx in indices {
-            let (start, end) = self.compute_id_range(cfgidx);
-            let on_entry = &self.on_entry[start.. end];
-            let entry_str = bits_to_string(on_entry);
-
-            let gens = &self.gens[start.. end];
-            let gens_str = if gens.iter().any(|&u| u != 0) {
-                format!(" gen: {}", bits_to_string(gens))
-            } else {
-                "".to_string()
-            };
-
-            let action_kills = &self.action_kills[start .. end];
-            let action_kills_str = if action_kills.iter().any(|&u| u != 0) {
-                format!(" action_kill: {}", bits_to_string(action_kills))
-            } else {
-                "".to_string()
-            };
-
-            let scope_kills = &self.scope_kills[start .. end];
-            let scope_kills_str = if scope_kills.iter().any(|&u| u != 0) {
-                format!(" scope_kill: {}", bits_to_string(scope_kills))
-            } else {
-                "".to_string()
-            };
-
-            ps.synth_comment(
-                format!("id {}: {}{}{}{}", id.as_usize(), entry_str,
-                        gens_str, action_kills_str, scope_kills_str))?;
-            ps.s.space()?;
-        }
-        Ok(())
-    }
-}
-
-fn build_local_id_to_index(body: Option<&hir::Body>,
-                           cfg: &cfg::CFG)
-                           -> FxHashMap<hir::ItemLocalId, Vec<CFGIndex>> {
-    let mut index = FxHashMap();
-
-    // FIXME(#15020) Would it be better to fold formals from decl
-    // into cfg itself?  i.e. introduce a fn-based flow-graph in
-    // addition to the current block-based flow-graph, rather than
-    // have to put traversals like this here?
-    if let Some(body) = body {
-        add_entries_from_fn_body(&mut index, body, cfg.entry);
-    }
-
-    cfg.graph.each_node(|node_idx, node| {
-        if let cfg::CFGNodeData::AST(id) = node.data {
-            index.entry(id).or_insert(vec![]).push(node_idx);
-        }
-        true
-    });
-
-    return index;
-
-    /// Add mappings from the ast nodes for the formal bindings to
-    /// the entry-node in the graph.
-    fn add_entries_from_fn_body(index: &mut FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>,
-                                body: &hir::Body,
-                                entry: CFGIndex) {
-        use hir::intravisit::Visitor;
-
-        struct Formals<'a> {
-            entry: CFGIndex,
-            index: &'a mut FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>,
-        }
-        let mut formals = Formals { entry: entry, index: index };
-        for arg in &body.arguments {
-            formals.visit_pat(&arg.pat);
-        }
-        impl<'a, 'v> Visitor<'v> for Formals<'a> {
-            fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v> {
-                intravisit::NestedVisitorMap::None
-            }
-
-            fn visit_pat(&mut self, p: &hir::Pat) {
-                self.index.entry(p.hir_id.local_id).or_insert(vec![]).push(self.entry);
-                intravisit::walk_pat(self, p)
-            }
-        }
-    }
-}
-
-/// Flag used by `add_kill` to indicate whether the provided kill
-/// takes effect only when control flows directly through the node in
-/// question, or if the kill's effect is associated with any
-/// control-flow directly through or indirectly over the node.
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum KillFrom {
-    /// A `ScopeEnd` kill is one that takes effect when any control
-    /// flow goes over the node. A kill associated with the end of the
-    /// scope of a variable declaration `let x;` is an example of a
-    /// `ScopeEnd` kill.
-    ScopeEnd,
-
-    /// An `Execution` kill is one that takes effect only when control
-    /// flow goes through the node to completion. A kill associated
-    /// with an assignment statement `x = expr;` is an example of an
-    /// `Execution` kill.
-    Execution,
-}
-
-impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
-    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-               analysis_name: &'static str,
-               body: Option<&hir::Body>,
-               cfg: &cfg::CFG,
-               oper: O,
-               id_range: IdRange,
-               bits_per_id: usize) -> DataFlowContext<'a, 'tcx, O> {
-        let usize_bits = mem::size_of::<usize>() * 8;
-        let words_per_id = (bits_per_id + usize_bits - 1) / usize_bits;
-        let num_nodes = cfg.graph.all_nodes().len();
-
-        debug!("DataFlowContext::new(analysis_name: {}, id_range={:?}, \
-                                     bits_per_id={}, words_per_id={}) \
-                                     num_nodes: {}",
-               analysis_name, id_range, bits_per_id, words_per_id,
-               num_nodes);
-
-        let entry = if oper.initial_value() { usize::MAX } else {0};
-
-        let zeroes = vec![0; num_nodes * words_per_id];
-        let gens = zeroes.clone();
-        let kills1 = zeroes.clone();
-        let kills2 = zeroes;
-        let on_entry = vec![entry; num_nodes * words_per_id];
-
-        let local_id_to_index = build_local_id_to_index(body, cfg);
-
-        DataFlowContext {
-            tcx,
-            analysis_name,
-            words_per_id,
-            local_id_to_index,
-            bits_per_id,
-            oper,
-            gens,
-            action_kills: kills1,
-            scope_kills: kills2,
-            on_entry,
-        }
-    }
-
-    pub fn add_gen(&mut self, id: hir::ItemLocalId, bit: usize) {
-        //! Indicates that `id` generates `bit`
-        debug!("{} add_gen(id={:?}, bit={})",
-               self.analysis_name, id, bit);
-        assert!(self.local_id_to_index.contains_key(&id));
-        assert!(self.bits_per_id > 0);
-
-        let indices = get_cfg_indices(id, &self.local_id_to_index);
-        for &cfgidx in indices {
-            let (start, end) = self.compute_id_range(cfgidx);
-            let gens = &mut self.gens[start.. end];
-            set_bit(gens, bit);
-        }
-    }
-
-    pub fn add_kill(&mut self, kind: KillFrom, id: hir::ItemLocalId, bit: usize) {
-        //! Indicates that `id` kills `bit`
-        debug!("{} add_kill(id={:?}, bit={})",
-               self.analysis_name, id, bit);
-        assert!(self.local_id_to_index.contains_key(&id));
-        assert!(self.bits_per_id > 0);
-
-        let indices = get_cfg_indices(id, &self.local_id_to_index);
-        for &cfgidx in indices {
-            let (start, end) = self.compute_id_range(cfgidx);
-            let kills = match kind {
-                KillFrom::Execution => &mut self.action_kills[start.. end],
-                KillFrom::ScopeEnd =>  &mut self.scope_kills[start.. end],
-            };
-            set_bit(kills, bit);
-        }
-    }
-
-    fn apply_gen_kill(&self, cfgidx: CFGIndex, bits: &mut [usize]) {
-        //! Applies the gen and kill sets for `cfgidx` to `bits`
-        debug!("{} apply_gen_kill(cfgidx={:?}, bits={}) [before]",
-               self.analysis_name, cfgidx, mut_bits_to_string(bits));
-        assert!(self.bits_per_id > 0);
-
-        let (start, end) = self.compute_id_range(cfgidx);
-        let gens = &self.gens[start.. end];
-        bitwise(bits, gens, &Union);
-        let kills = &self.action_kills[start.. end];
-        bitwise(bits, kills, &Subtract);
-        let kills = &self.scope_kills[start.. end];
-        bitwise(bits, kills, &Subtract);
-
-        debug!("{} apply_gen_kill(cfgidx={:?}, bits={}) [after]",
-               self.analysis_name, cfgidx, mut_bits_to_string(bits));
-    }
-
-    fn compute_id_range(&self, cfgidx: CFGIndex) -> (usize, usize) {
-        let n = cfgidx.node_id();
-        let start = n * self.words_per_id;
-        let end = start + self.words_per_id;
-
-        assert!(start < self.gens.len());
-        assert!(end <= self.gens.len());
-        assert!(self.gens.len() == self.action_kills.len());
-        assert!(self.gens.len() == self.scope_kills.len());
-        assert!(self.gens.len() == self.on_entry.len());
-
-        (start, end)
-    }
-
-
-    pub fn each_bit_on_entry<F>(&self, id: hir::ItemLocalId, mut f: F) -> bool where
-        F: FnMut(usize) -> bool,
-    {
-        //! Iterates through each bit that is set on entry to `id`.
-        //! Only useful after `propagate()` has been called.
-        if !self.has_bitset_for_local_id(id) {
-            return true;
-        }
-        let indices = get_cfg_indices(id, &self.local_id_to_index);
-        for &cfgidx in indices {
-            if !self.each_bit_for_node(EntryOrExit::Entry, cfgidx, |i| f(i)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    pub fn each_bit_for_node<F>(&self, e: EntryOrExit, cfgidx: CFGIndex, f: F) -> bool where
-        F: FnMut(usize) -> bool,
-    {
-        //! Iterates through each bit that is set on entry/exit to `cfgidx`.
-        //! Only useful after `propagate()` has been called.
-
-        if self.bits_per_id == 0 {
-            // Skip the surprisingly common degenerate case.  (Note
-            // compute_id_range requires self.words_per_id > 0.)
-            return true;
-        }
-
-        let (start, end) = self.compute_id_range(cfgidx);
-        let on_entry = &self.on_entry[start.. end];
-        let temp_bits;
-        let slice = match e {
-            EntryOrExit::Entry => on_entry,
-            EntryOrExit::Exit => {
-                let mut t = on_entry.to_vec();
-                self.apply_gen_kill(cfgidx, &mut t);
-                temp_bits = t;
-                &temp_bits[..]
-            }
-        };
-        debug!("{} each_bit_for_node({:?}, cfgidx={:?}) bits={}",
-               self.analysis_name, e, cfgidx, bits_to_string(slice));
-        self.each_bit(slice, f)
-    }
-
-    pub fn each_gen_bit<F>(&self, id: hir::ItemLocalId, mut f: F) -> bool where
-        F: FnMut(usize) -> bool,
-    {
-        //! Iterates through each bit in the gen set for `id`.
-        if !self.has_bitset_for_local_id(id) {
-            return true;
-        }
-
-        if self.bits_per_id == 0 {
-            // Skip the surprisingly common degenerate case.  (Note
-            // compute_id_range requires self.words_per_id > 0.)
-            return true;
-        }
-
-        let indices = get_cfg_indices(id, &self.local_id_to_index);
-        for &cfgidx in indices {
-            let (start, end) = self.compute_id_range(cfgidx);
-            let gens = &self.gens[start.. end];
-            debug!("{} each_gen_bit(id={:?}, gens={})",
-                   self.analysis_name, id, bits_to_string(gens));
-            if !self.each_bit(gens, |i| f(i)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    fn each_bit<F>(&self, words: &[usize], mut f: F) -> bool where
-        F: FnMut(usize) -> bool,
-    {
-        //! Helper for iterating over the bits in a bit set.
-        //! Returns false on the first call to `f` that returns false;
-        //! if all calls to `f` return true, then returns true.
-
-        let usize_bits = mem::size_of::<usize>() * 8;
-        for (word_index, &word) in words.iter().enumerate() {
-            if word != 0 {
-                let base_index = word_index * usize_bits;
-                for offset in 0..usize_bits {
-                    let bit = 1 << offset;
-                    if (word & bit) != 0 {
-                        // NB: we round up the total number of bits
-                        // that we store in any given bit set so that
-                        // it is an even multiple of usize::BITS.  This
-                        // means that there may be some stray bits at
-                        // the end that do not correspond to any
-                        // actual value.  So before we callback, check
-                        // whether the bit_index is greater than the
-                        // actual value the user specified and stop
-                        // iterating if so.
-                        let bit_index = base_index + offset as usize;
-                        if bit_index >= self.bits_per_id {
-                            return true;
-                        } else if !f(bit_index) {
-                            return false;
-                        }
-                    }
-                }
-            }
-        }
-        return true;
-    }
-
-    pub fn add_kills_from_flow_exits(&mut self, cfg: &cfg::CFG) {
-        //! Whenever you have a `break` or `continue` statement, flow
-        //! exits through any number of enclosing scopes on its way to
-        //! the new destination. This function infers the kill bits of
-        //! those control operators based on the kill bits associated
-        //! with those scopes.
-        //!
-        //! This is usually called (if it is called at all), after
-        //! all add_gen and add_kill calls, but before propagate.
-
-        debug!("{} add_kills_from_flow_exits", self.analysis_name);
-        if self.bits_per_id == 0 {
-            // Skip the surprisingly common degenerate case.  (Note
-            // compute_id_range requires self.words_per_id > 0.)
-            return;
-        }
-        cfg.graph.each_edge(|_edge_index, edge| {
-            let flow_exit = edge.source();
-            let (start, end) = self.compute_id_range(flow_exit);
-            let mut orig_kills = self.scope_kills[start.. end].to_vec();
-
-            let mut changed = false;
-            for &id in &edge.data.exiting_scopes {
-                let opt_cfg_idx = self.local_id_to_index.get(&id);
-                match opt_cfg_idx {
-                    Some(indices) => {
-                        for &cfg_idx in indices {
-                            let (start, end) = self.compute_id_range(cfg_idx);
-                            let kills = &self.scope_kills[start.. end];
-                            if bitwise(&mut orig_kills, kills, &Union) {
-                                debug!("scope exits: scope id={:?} \
-                                        (node={:?} of {:?}) added killset: {}",
-                                       id, cfg_idx, indices,
-                                       bits_to_string(kills));
-                                changed = true;
-                            }
-                        }
-                    }
-                    None => {
-                        debug!("{} add_kills_from_flow_exits flow_exit={:?} \
-                                no cfg_idx for exiting_scope={:?}",
-                               self.analysis_name, flow_exit, id);
-                    }
-                }
-            }
-
-            if changed {
-                let bits = &mut self.scope_kills[start.. end];
-                debug!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [before]",
-                       self.analysis_name, flow_exit, mut_bits_to_string(bits));
-                bits.copy_from_slice(&orig_kills[..]);
-                debug!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [after]",
-                       self.analysis_name, flow_exit, mut_bits_to_string(bits));
-            }
-            true
-        });
-    }
-}
-
-impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
-//                                ^^^^^^^^^^^^^ only needed for pretty printing
-    pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Body) {
-        //! Performs the data flow analysis.
-
-        if self.bits_per_id == 0 {
-            // Optimize the surprisingly common degenerate case.
-            return;
-        }
-
-        {
-            let words_per_id = self.words_per_id;
-            let mut propcx = PropagationContext {
-                dfcx: &mut *self,
-                changed: true
-            };
-
-            let nodes_po = cfg.graph.nodes_in_postorder(OUTGOING, cfg.entry);
-            let mut temp = vec![0; words_per_id];
-            let mut num_passes = 0;
-            while propcx.changed {
-                num_passes += 1;
-                propcx.changed = false;
-                propcx.reset(&mut temp);
-                propcx.walk_cfg(cfg, &nodes_po, &mut temp);
-            }
-            debug!("finished in {} iterations", num_passes);
-        }
-
-        debug!("Dataflow result for {}:", self.analysis_name);
-        debug!("{}", pprust::to_string(self, |s| {
-            s.cbox(pprust::indent_unit)?;
-            s.ibox(0)?;
-            s.print_expr(&body.value)
-        }));
-    }
-}
-
-impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
-    fn walk_cfg(&mut self,
-                cfg: &cfg::CFG,
-                nodes_po: &[CFGIndex],
-                in_out: &mut [usize]) {
-        debug!("DataFlowContext::walk_cfg(in_out={}) {}",
-               bits_to_string(in_out), self.dfcx.analysis_name);
-        assert!(self.dfcx.bits_per_id > 0);
-
-        // Iterate over nodes in reverse postorder
-        for &node_index in nodes_po.iter().rev() {
-            let node = cfg.graph.node(node_index);
-            debug!("DataFlowContext::walk_cfg idx={:?} id={:?} begin in_out={}",
-                   node_index, node.data.id(), bits_to_string(in_out));
-
-            let (start, end) = self.dfcx.compute_id_range(node_index);
-
-            // Initialize local bitvector with state on-entry.
-            in_out.copy_from_slice(&self.dfcx.on_entry[start.. end]);
-
-            // Compute state on-exit by applying transfer function to
-            // state on-entry.
-            self.dfcx.apply_gen_kill(node_index, in_out);
-
-            // Propagate state on-exit from node into its successors.
-            self.propagate_bits_into_graph_successors_of(in_out, cfg, node_index);
-        }
-    }
-
-    fn reset(&mut self, bits: &mut [usize]) {
-        let e = if self.dfcx.oper.initial_value() {usize::MAX} else {0};
-        for b in bits {
-            *b = e;
-        }
-    }
-
-    fn propagate_bits_into_graph_successors_of(&mut self,
-                                               pred_bits: &[usize],
-                                               cfg: &cfg::CFG,
-                                               cfgidx: CFGIndex) {
-        for (_, edge) in cfg.graph.outgoing_edges(cfgidx) {
-            self.propagate_bits_into_entry_set_for(pred_bits, edge);
-        }
-    }
-
-    fn propagate_bits_into_entry_set_for(&mut self,
-                                         pred_bits: &[usize],
-                                         edge: &cfg::CFGEdge) {
-        let source = edge.source();
-        let cfgidx = edge.target();
-        debug!("{} propagate_bits_into_entry_set_for(pred_bits={}, {:?} to {:?})",
-               self.dfcx.analysis_name, bits_to_string(pred_bits), source, cfgidx);
-        assert!(self.dfcx.bits_per_id > 0);
-
-        let (start, end) = self.dfcx.compute_id_range(cfgidx);
-        let changed = {
-            // (scoping mutable borrow of self.dfcx.on_entry)
-            let on_entry = &mut self.dfcx.on_entry[start.. end];
-            bitwise(on_entry, pred_bits, &self.dfcx.oper)
-        };
-        if changed {
-            debug!("{} changed entry set for {:?} to {}",
-                   self.dfcx.analysis_name, cfgidx,
-                   bits_to_string(&self.dfcx.on_entry[start.. end]));
-            self.changed = true;
-        }
-    }
-}
-
-fn mut_bits_to_string(words: &mut [usize]) -> String {
-    bits_to_string(words)
-}
-
-fn bits_to_string(words: &[usize]) -> String {
-    let mut result = String::new();
-    let mut sep = '[';
-
-    // Note: this is a little endian printout of bytes.
-
-    for &word in words {
-        let mut v = word;
-        for _ in 0..mem::size_of::<usize>() {
-            result.push(sep);
-            result.push_str(&format!("{:02x}", v & 0xFF));
-            v >>= 8;
-            sep = '-';
-        }
-    }
-    result.push(']');
-    return result
-}
-
-#[inline]
-fn bitwise<Op:BitwiseOperator>(out_vec: &mut [usize],
-                               in_vec: &[usize],
-                               op: &Op) -> bool {
-    assert_eq!(out_vec.len(), in_vec.len());
-    let mut changed = false;
-    for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) {
-        let old_val = *out_elt;
-        let new_val = op.join(old_val, *in_elt);
-        *out_elt = new_val;
-        changed |= old_val != new_val;
-    }
-    changed
-}
-
-fn set_bit(words: &mut [usize], bit: usize) -> bool {
-    debug!("set_bit: words={} bit={}",
-           mut_bits_to_string(words), bit_str(bit));
-    let usize_bits = mem::size_of::<usize>() * 8;
-    let word = bit / usize_bits;
-    let bit_in_word = bit % usize_bits;
-    let bit_mask = 1 << bit_in_word;
-    debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
-    let oldv = words[word];
-    let newv = oldv | bit_mask;
-    words[word] = newv;
-    oldv != newv
-}
-
-fn bit_str(bit: usize) -> String {
-    let byte = bit >> 3;
-    let lobits = 1 << (bit & 0b111);
-    format!("[{}:{}-{:02x}]", bit, byte, lobits)
-}
-
-struct Union;
-impl BitwiseOperator for Union {
-    fn join(&self, a: usize, b: usize) -> usize { a | b }
-}
-struct Subtract;
-impl BitwiseOperator for Subtract {
-    fn join(&self, a: usize, b: usize) -> usize { a & !b }
-}
index dae5709ba114a3721f86bdb41ee2fcb9ae1594e7..8ceff303774b596a265af6a1dfac05a09589914c 100644 (file)
@@ -429,8 +429,8 @@ pub enum BorrowKind {
 
     /// Data must be immutable but not aliasable.  This kind of borrow
     /// cannot currently be expressed by the user and is used only in
-    /// implicit closure bindings. It is needed when you the closure
-    /// is borrowing or mutating a mutable referent, e.g.:
+    /// implicit closure bindings. It is needed when the closure is
+    /// borrowing or mutating a mutable referent, e.g.:
     ///
     ///    let x: &mut isize = ...;
     ///    let y = || *x += 5;
@@ -443,7 +443,7 @@ pub enum BorrowKind {
     ///    let y = (&mut Env { &x }, fn_ptr);  // Closure is pair of env and fn
     ///    fn fn_ptr(env: &mut Env) { **env.x += 5; }
     ///
-    /// This is then illegal because you cannot mutate a `&mut` found
+    /// This is then illegal because you cannot mutate an `&mut` found
     /// in an aliasable location. To solve, you'd have to translate with
     /// an `&mut` borrow:
     ///
@@ -523,6 +523,8 @@ pub struct VarBindingForm<'tcx> {
     /// (b) it gives a way to separate this case from the remaining cases
     ///     for diagnostics.
     pub opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
+    /// Span of the pattern in which this variable was bound.
+    pub pat_span: Span,
 }
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
@@ -540,7 +542,8 @@ pub enum BindingForm<'tcx> {
 impl_stable_hash_for!(struct self::VarBindingForm<'tcx> {
     binding_mode,
     opt_ty_info,
-    opt_match_place
+    opt_match_place,
+    pat_span
 });
 
 mod binding_form_impl {
@@ -673,7 +676,7 @@ pub struct LocalDecl<'tcx> {
     /// ROOT SCOPE
     ///  │{ argument x: &str }
     ///  │
-    ///  │ │{ #[allow(unused_mut] } // this is actually split into 2 scopes
+    ///  │ │{ #[allow(unused_mut)] } // this is actually split into 2 scopes
     ///  │ │                        // in practice because I'm lazy.
     ///  │ │
     ///  │ │← x.source_info.scope
@@ -710,6 +713,7 @@ pub fn can_be_made_mutable(&self) -> bool {
                 binding_mode: ty::BindingMode::BindByValue(_),
                 opt_ty_info: _,
                 opt_match_place: _,
+                pat_span: _,
             }))) => true,
 
             // FIXME: might be able to thread the distinction between
@@ -729,6 +733,7 @@ pub fn is_nonref_binding(&self) -> bool {
                 binding_mode: ty::BindingMode::BindByValue(_),
                 opt_ty_info: _,
                 opt_match_place: _,
+                pat_span: _,
             }))) => true,
 
             Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf)) => true,
@@ -906,7 +911,7 @@ pub enum TerminatorKind<'tcx> {
 
     /// Drop the Place and assign the new value over it. This ensures
     /// that the assignment to `P` occurs *even if* the destructor for
-    /// place unwinds. Its semantics are best explained by by the
+    /// place unwinds. Its semantics are best explained by the
     /// elaboration:
     ///
     /// ```
index b55843ac527dfd9a90907a602bd492c48360dcb2..5991845d265b24a8ce86842d5f10d6d0e34a7dab 100644 (file)
@@ -127,14 +127,14 @@ pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> P
     /// of a closure type.
     pub fn is_upvar_field_projection<'cx, 'gcx>(&self, mir: &'cx Mir<'tcx>,
                                                 tcx: &TyCtxt<'cx, 'gcx, 'tcx>) -> Option<Field> {
-        let place = if let Place::Projection(ref proj) = self {
+        let (place, by_ref) = if let Place::Projection(ref proj) = self {
             if let ProjectionElem::Deref = proj.elem {
-                &proj.base
+                (&proj.base, true)
             } else {
-                self
+                (self, false)
             }
         } else {
-            self
+            (self, false)
         };
 
         match place {
@@ -142,14 +142,16 @@ pub fn is_upvar_field_projection<'cx, 'gcx>(&self, mir: &'cx Mir<'tcx>,
                 ProjectionElem::Field(field, _ty) => {
                     let base_ty = proj.base.ty(mir, *tcx).to_ty(*tcx);
 
-                    if  base_ty.is_closure() || base_ty.is_generator() {
+                    if (base_ty.is_closure() || base_ty.is_generator()) &&
+                        (!by_ref || mir.upvar_decls[field.index()].by_ref)
+                    {
                         Some(field)
                     } else {
                         None
                     }
                 },
                 _ => None,
-            },
+            }\f
             _ => None,
         }
     }
index 7349c520c240778f09e433cbbc4aff66d58ff523..99b2f3e59feb66253d2f4bbffe67a5a6fc2af0bc 100644 (file)
@@ -1472,11 +1472,16 @@ fn note_obligation_cause_code<T>(&self,
             ObligationCauseCode::StructInitializerSized => {
                 err.note("structs must have a statically known size to be initialized");
             }
-            ObligationCauseCode::FieldSized(ref item) => {
+            ObligationCauseCode::FieldSized { adt_kind: ref item, last } => {
                 match *item {
                     AdtKind::Struct => {
-                        err.note("only the last field of a struct may have a dynamically \
-                                  sized type");
+                        if last {
+                            err.note("the last field of a packed struct may only have a \
+                                      dynamically sized type if it does not need drop to be run");
+                        } else {
+                            err.note("only the last field of a struct may have a dynamically \
+                                      sized type");
+                        }
                     }
                     AdtKind::Union => {
                         err.note("no field of a union may have a dynamically sized type");
index 0290f2e3b13f08e335a1319ca22b64108e9d9517..08434b5f24ef9d2e19503a06fb4ae76bb5a89f78 100644 (file)
@@ -192,8 +192,8 @@ pub enum ObligationCauseCode<'tcx> {
     /// [T,..n] --> T must be Copy
     RepeatVec,
 
-    /// Types of fields (other than the last) in a struct must be sized.
-    FieldSized(AdtKind),
+    /// Types of fields (other than the last, except for packed structs) in a struct must be sized.
+    FieldSized { adt_kind: AdtKind, last: bool },
 
     /// Constant expressions must be sized.
     ConstSized,
index e1395c3fa442723c2bba781ea5918aee35bd902d..280ce75720bcfef8d309c0caefbc6197b6648102 100644 (file)
@@ -131,7 +131,7 @@ pub fn parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
             parse_error(tcx, item.span,
                         "this attribute must have a valid value",
                         "expected value here",
-                        Some(r#"eg `#[rustc_on_unimplemented = "foo"]`"#));
+                        Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#));
         }
 
         if errored {
@@ -170,7 +170,7 @@ pub fn of_item(tcx: TyCtxt<'a, 'gcx, 'tcx>,
             return Err(parse_error(tcx, attr.span,
                                    "`#[rustc_on_unimplemented]` requires a value",
                                    "value required here",
-                                   Some(r#"eg `#[rustc_on_unimplemented = "foo"]`"#)));
+                                   Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#)));
         };
         debug!("of_item({:?}/{:?}) = {:?}", trait_def_id, impl_def_id, result);
         result
@@ -213,10 +213,13 @@ pub fn evaluate(&self,
             }
         }
 
+        let options: FxHashMap<String, String> = options.into_iter()
+            .filter_map(|(k, v)| v.as_ref().map(|v| (k.to_owned(), v.to_owned())))
+            .collect();
         OnUnimplementedNote {
-            label: label.map(|l| l.format(tcx, trait_ref)),
-            message: message.map(|m| m.format(tcx, trait_ref)),
-            note: note.map(|n| n.format(tcx, trait_ref)),
+            label: label.map(|l| l.format(tcx, trait_ref, &options)),
+            message: message.map(|m| m.format(tcx, trait_ref, &options)),
+            note: note.map(|n| n.format(tcx, trait_ref, &options)),
         }
     }
 }
@@ -251,6 +254,10 @@ fn verify(&self,
                     Position::ArgumentNamed(s) if s == "Self" => (),
                     // `{ThisTraitsName}` is allowed
                     Position::ArgumentNamed(s) if s == name => (),
+                    // `{from_method}` is allowed
+                    Position::ArgumentNamed(s) if s == "from_method" => (),
+                    // `{from_desugaring}` is allowed
+                    Position::ArgumentNamed(s) if s == "from_desugaring" => (),
                     // So is `{A}` if A is a type parameter
                     Position::ArgumentNamed(s) => match generics.params.iter().find(|param| {
                         param.name == s
@@ -258,17 +265,14 @@ fn verify(&self,
                         Some(_) => (),
                         None => {
                             span_err!(tcx.sess, span, E0230,
-                                      "there is no parameter \
-                                       {} on trait {}",
-                                      s, name);
+                                      "there is no parameter `{}` on trait `{}`", s, name);
                             result = Err(ErrorReported);
                         }
                     },
                     // `{:1}` and `{}` are not to be used
                     Position::ArgumentIs(_) | Position::ArgumentImplicitlyIs(_) => {
                         span_err!(tcx.sess, span, E0231,
-                                  "only named substitution \
-                                   parameters are allowed");
+                                  "only named substitution parameters are allowed");
                         result = Err(ErrorReported);
                     }
                 }
@@ -280,7 +284,8 @@ fn verify(&self,
 
     pub fn format(&self,
                   tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                  trait_ref: ty::TraitRef<'tcx>)
+                  trait_ref: ty::TraitRef<'tcx>,
+                  options: &FxHashMap<String, String>)
                   -> String
     {
         let name = tcx.item_name(trait_ref.def_id);
@@ -296,6 +301,7 @@ pub fn format(&self,
             let name = param.name.to_string();
             Some((name, value))
         }).collect::<FxHashMap<String, String>>();
+        let empty_string = String::new();
 
         let parser = Parser::new(&self.0, None);
         parser.map(|p| {
@@ -308,14 +314,20 @@ pub fn format(&self,
                             &trait_str
                         }
                         None => {
-                            bug!("broken on_unimplemented {:?} for {:?}: \
-                                  no argument matching {:?}",
-                                 self.0, trait_ref, s)
+                            if let Some(val) = options.get(s) {
+                                val
+                            } else if s == "from_desugaring" || s == "from_method" {
+                                // don't break messages using these two arguments incorrectly
+                                &empty_string
+                            } else {
+                                bug!("broken on_unimplemented {:?} for {:?}: \
+                                      no argument matching {:?}",
+                                     self.0, trait_ref, s)
+                            }
                         }
                     },
                     _ => {
-                        bug!("broken on_unimplemented {:?} - bad \
-                              format arg", self.0)
+                        bug!("broken on_unimplemented {:?} - bad format arg", self.0)
                     }
                 }
             }
index fbd12c9fe8ecaf796a8f2be66c3c5944fa69d979..ea96c30502680362db489f3af847504fd2a8cede 100644 (file)
@@ -226,6 +226,7 @@ pub struct SelectionCache<'tcx> {
 /// parameter environment.
 #[derive(PartialEq,Eq,Debug,Clone)]
 enum SelectionCandidate<'tcx> {
+    /// If has_nested is false, there are no *further* obligations
     BuiltinCandidate { has_nested: bool },
     ParamCandidate(ty::PolyTraitRef<'tcx>),
     ImplCandidate(DefId),
@@ -2039,12 +2040,20 @@ fn candidate_should_be_dropped_in_favor_of<'o>(
         }
 
         match other.candidate {
+            // Prefer BuiltinCandidate { has_nested: false } to anything else.
+            // This is a fix for #53123 and prevents winnowing from accidentally extending the
+            // lifetime of a variable.
+            BuiltinCandidate { has_nested: false } => true,
             ParamCandidate(ref cand) => match victim.candidate {
                 AutoImplCandidate(..) => {
                     bug!(
                         "default implementations shouldn't be recorded \
                          when there are other valid candidates");
                 }
+                // Prefer BuiltinCandidate { has_nested: false } to anything else.
+                // This is a fix for #53123 and prevents winnowing from accidentally extending the
+                // lifetime of a variable.
+                BuiltinCandidate { has_nested: false } => false,
                 ImplCandidate(..) |
                 ClosureCandidate |
                 GeneratorCandidate |
@@ -2072,6 +2081,10 @@ fn candidate_should_be_dropped_in_favor_of<'o>(
                         "default implementations shouldn't be recorded \
                          when there are other valid candidates");
                 }
+                // Prefer BuiltinCandidate { has_nested: false } to anything else.
+                // This is a fix for #53123 and prevents winnowing from accidentally extending the
+                // lifetime of a variable.
+                BuiltinCandidate { has_nested: false } => false,
                 ImplCandidate(..) |
                 ClosureCandidate |
                 GeneratorCandidate |
@@ -2115,7 +2128,7 @@ fn candidate_should_be_dropped_in_favor_of<'o>(
             FnPointerCandidate |
             BuiltinObjectCandidate |
             BuiltinUnsizeCandidate |
-            BuiltinCandidate { .. } => {
+            BuiltinCandidate { has_nested: true } => {
                 match victim.candidate {
                     ParamCandidate(ref cand) => {
                         // Prefer these to a global where-clause bound
index 39e358803cbe84f7a148de58137875b746ba8af8..544e3f03c03b1c3d936999c31b0ffc8a4b5d5c39 100644 (file)
@@ -206,7 +206,7 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lif
             super::SizedReturnType => Some(super::SizedReturnType),
             super::SizedYieldType => Some(super::SizedYieldType),
             super::RepeatVec => Some(super::RepeatVec),
-            super::FieldSized(item) => Some(super::FieldSized(item)),
+            super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }),
             super::ConstSized => Some(super::ConstSized),
             super::SharedStatic => Some(super::SharedStatic),
             super::BuiltinDerivedObligation(ref cause) => {
index 45279f18117c16329e8c45b4c584e89cd47f607b..87d59d2e763cbe89743452e59379e8888f639f3a 100644 (file)
@@ -2306,24 +2306,14 @@ pub(super) fn is_all_zeros(limbs: &[Limb]) -> bool {
 
     /// One, not zero, based LSB. That is, returns 0 for a zeroed significand.
     pub(super) fn olsb(limbs: &[Limb]) -> usize {
-        for (i, &limb) in limbs.iter().enumerate() {
-            if limb != 0 {
-                return i * LIMB_BITS + limb.trailing_zeros() as usize + 1;
-            }
-        }
-
-        0
+        limbs.iter().enumerate().find(|(_, &limb)| limb != 0).map_or(0,
+            |(i, limb)| i * LIMB_BITS + limb.trailing_zeros() as usize + 1)
     }
 
     /// One, not zero, based MSB. That is, returns 0 for a zeroed significand.
     pub(super) fn omsb(limbs: &[Limb]) -> usize {
-        for (i, &limb) in limbs.iter().enumerate().rev() {
-            if limb != 0 {
-                return (i + 1) * LIMB_BITS - limb.leading_zeros() as usize;
-            }
-        }
-
-        0
+        limbs.iter().enumerate().rfind(|(_, &limb)| limb != 0).map_or(0,
+            |(i, limb)| (i + 1) * LIMB_BITS - limb.leading_zeros() as usize)
     }
 
     /// Comparison (unsigned) of two significands.
index 49bd69f8262169ad18bb2a85daa9cb487bbdf9ca..709590f649b92cab52d4e65f73867d7b98b69638 100644 (file)
@@ -91,7 +91,6 @@ struct CheckLoanCtxt<'a, 'tcx: 'a> {
     dfcx_loans: &'a LoanDataFlow<'a, 'tcx>,
     move_data: &'a move_data::FlowedMoveData<'a, 'tcx>,
     all_loans: &'a [Loan<'tcx>],
-    param_env: ty::ParamEnv<'tcx>,
     movable_generator: bool,
 }
 
@@ -215,7 +214,6 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         dfcx_loans,
         move_data,
         all_loans,
-        param_env,
         movable_generator,
     };
     let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id);
@@ -801,8 +799,7 @@ fn check_if_path_is_moved(&self,
                 use_kind,
                 &lp,
                 the_move,
-                moved_lp,
-                self.param_env);
+                moved_lp);
             false
         });
     }
index 7ce6863a7c986402d1abcd4eede1ef7bc253e931..b76931c301748c44cc995473755bb1547833c017 100644 (file)
@@ -163,15 +163,11 @@ pub fn gather_assignment<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                    move_data: &MoveData<'tcx>,
                                    assignment_id: hir::ItemLocalId,
                                    assignment_span: Span,
-                                   assignee_loan_path: Rc<LoanPath<'tcx>>,
-                                   assignee_id: hir::ItemLocalId,
-                                   mode: euv::MutateMode) {
+                                   assignee_loan_path: Rc<LoanPath<'tcx>>) {
     move_data.add_assignment(bccx.tcx,
                              assignee_loan_path,
                              assignment_id,
-                             assignment_span,
-                             assignee_id,
-                             mode);
+                             assignment_span);
 }
 
 // (keep in sync with move_error::report_cannot_move_out_of )
index 323e0997e3e4732c2d81ffafce9d8033effcb6b4..c9dcc0d9fa266beb190653e31c7526d7309f267a 100644 (file)
@@ -28,8 +28,7 @@ pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                     span: Span,
                                     cause: euv::LoanCause,
                                     cmt: &'a mc::cmt_<'tcx>,
-                                    loan_region: ty::Region<'tcx>,
-                                    _: ty::BorrowKind)
+                                    loan_region: ty::Region<'tcx>)
                                     -> Result<(),()> {
     //! Reports error if `loan_region` is larger than S
     //! where S is `item_scope` if `cmt` is an upvar,
index d08814138719a370e1c97e1faf74751db12d69ae..6c83e2dd1c206608915927e42e141bd1dcd743c8 100644 (file)
@@ -145,12 +145,11 @@ fn mutate(&mut self,
               assignment_id: ast::NodeId,
               assignment_span: Span,
               assignee_cmt: &mc::cmt_<'tcx>,
-              mode: euv::MutateMode)
+              _: euv::MutateMode)
     {
         self.guarantee_assignment_valid(assignment_id,
                                         assignment_span,
-                                        assignee_cmt,
-                                        mode);
+                                        assignee_cmt);
     }
 
     fn decl_without_init(&mut self, id: ast::NodeId, _span: Span) {
@@ -246,8 +245,7 @@ pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.bccx.tcx }
     fn guarantee_assignment_valid(&mut self,
                                   assignment_id: ast::NodeId,
                                   assignment_span: Span,
-                                  cmt: &mc::cmt_<'tcx>,
-                                  mode: euv::MutateMode) {
+                                  cmt: &mc::cmt_<'tcx>) {
 
         let opt_lp = opt_loan_path(cmt);
         debug!("guarantee_assignment_valid(assignment_id={}, cmt={:?}) opt_lp={:?}",
@@ -282,9 +280,7 @@ fn guarantee_assignment_valid(&mut self,
                                                 self.bccx.tcx.hir.node_to_hir_id(assignment_id)
                                                     .local_id,
                                                 assignment_span,
-                                                lp,
-                                                cmt.hir_id.local_id,
-                                                mode);
+                                                lp);
             }
             None => {
                 // This can occur with e.g. `*foo() = 5`.  In such
@@ -320,7 +316,7 @@ fn guarantee_valid(&mut self,
         // Check that the lifetime of the borrow does not exceed
         // the lifetime of the data being borrowed.
         if lifetime::guarantee_lifetime(self.bccx, self.item_ub,
-                                        borrow_span, cause, cmt, loan_region, req_kind).is_err() {
+                                        borrow_span, cause, cmt, loan_region).is_err() {
             return; // reported an error, no sense in reporting more.
         }
 
index a97fc666e25a66bb797dea8dcf0291ba67d28051..5b08400eb112d05ddc56fe37aca367d0eb61391c 100644 (file)
 use rustc::hir::map as hir_map;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::cfg;
-use rustc::middle::dataflow::DataFlowContext;
-use rustc::middle::dataflow::BitwiseOperator;
-use rustc::middle::dataflow::DataFlowOperator;
-use rustc::middle::dataflow::KillFrom;
 use rustc::middle::borrowck::{BorrowCheckResult, SignalledError};
 use rustc::hir::def_id::{DefId, LocalDefId};
 use rustc::middle::expr_use_visitor as euv;
@@ -54,6 +50,8 @@
 use rustc::hir;
 use rustc::hir::intravisit::{self, Visitor};
 
+use dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom};
+
 pub mod check_loans;
 
 pub mod gather_loans;
@@ -640,8 +638,7 @@ pub fn report_use_of_moved_value(&self,
                                      use_kind: MovedValueUseKind,
                                      lp: &LoanPath<'tcx>,
                                      the_move: &move_data::Move,
-                                     moved_lp: &LoanPath<'tcx>,
-                                     _param_env: ty::ParamEnv<'tcx>) {
+                                     moved_lp: &LoanPath<'tcx>) {
         let (verb, verb_participle) = match use_kind {
             MovedInUse => ("use", "used"),
             MovedInCapture => ("capture", "captured"),
@@ -806,23 +803,6 @@ pub fn report_reassigned_immutable_variable(&self,
         self.signal_error();
     }
 
-    pub fn struct_span_err_with_code<S: Into<MultiSpan>>(&self,
-                                                         s: S,
-                                                         msg: &str,
-                                                         code: DiagnosticId)
-                                                         -> DiagnosticBuilder<'a> {
-        self.tcx.sess.struct_span_err_with_code(s, msg, code)
-    }
-
-    pub fn span_err_with_code<S: Into<MultiSpan>>(
-        &self,
-        s: S,
-        msg: &str,
-        code: DiagnosticId,
-    ) {
-        self.tcx.sess.span_err_with_code(s, msg, code);
-    }
-
     fn report_bckerr(&self, err: &BckError<'a, 'tcx>) {
         let error_span = err.span.clone();
 
@@ -1255,7 +1235,7 @@ fn note_immutability_blame(&self,
                     ty::BindByReference(..) => {
                         let let_span = self.tcx.hir.span(node_id);
                         let suggestion = suggest_ref_mut(self.tcx, let_span);
-                        if let Some((let_span, replace_str)) = suggestion {
+                        if let Some(replace_str) = suggestion {
                             db.span_suggestion(
                                 let_span,
                                 "use a mutable reference instead",
index 4091ca046f44dc7f6a6ec5956d9641433711988d..979d71a0923c40ea4f468f04e80b07716bf13cb4 100644 (file)
 
 pub use self::MoveKind::*;
 
+use dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom};
+
 use borrowck::*;
 use rustc::cfg;
-use rustc::middle::dataflow::DataFlowContext;
-use rustc::middle::dataflow::BitwiseOperator;
-use rustc::middle::dataflow::DataFlowOperator;
-use rustc::middle::dataflow::KillFrom;
-use rustc::middle::expr_use_visitor as euv;
-use rustc::middle::expr_use_visitor::MutateMode;
 use rustc::ty::{self, TyCtxt};
-use rustc::util::nodemap::{FxHashMap, FxHashSet};
+use rustc::util::nodemap::FxHashMap;
 
 use std::cell::RefCell;
 use std::rc::Rc;
@@ -51,9 +47,6 @@ pub struct MoveData<'tcx> {
     /// assigned dataflow bits, but we track them because they still
     /// kill move bits.
     pub path_assignments: RefCell<Vec<Assignment>>,
-
-    /// Assignments to a variable or path, like `x = foo`, but not `x += foo`.
-    pub assignee_ids: RefCell<FxHashSet<hir::ItemLocalId>>,
 }
 
 pub struct FlowedMoveData<'a, 'tcx: 'a> {
@@ -151,9 +144,6 @@ pub struct Assignment {
 
     /// span of node where assignment occurs
     pub span: Span,
-
-    /// id for place expression on lhs of assignment
-    pub assignee_id: hir::ItemLocalId,
 }
 
 #[derive(Clone, Copy)]
@@ -388,9 +378,7 @@ fn add_move_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
     pub fn add_assignment(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           lp: Rc<LoanPath<'tcx>>,
                           assign_id: hir::ItemLocalId,
-                          span: Span,
-                          assignee_id: hir::ItemLocalId,
-                          mode: euv::MutateMode) {
+                          span: Span) {
         // Assigning to one union field automatically assigns to all its fields.
         if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind {
             if let ty::TyAdt(adt_def, _) = base_lp.ty.sty {
@@ -407,39 +395,28 @@ pub fn add_assignment(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                     LpInterior(opt_variant_id, field));
                         let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty));
                         self.add_assignment_helper(tcx, sibling_lp, assign_id,
-                                                   span, assignee_id, mode);
+                                                   span);
                     }
                     return;
                 }
             }
         }
 
-        self.add_assignment_helper(tcx, lp.clone(), assign_id, span, assignee_id, mode);
+        self.add_assignment_helper(tcx, lp.clone(), assign_id, span);
     }
 
     fn add_assignment_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              lp: Rc<LoanPath<'tcx>>,
                              assign_id: hir::ItemLocalId,
-                             span: Span,
-                             assignee_id: hir::ItemLocalId,
-                             mode: euv::MutateMode) {
-        debug!("add_assignment(lp={:?}, assign_id={:?}, assignee_id={:?}",
-               lp, assign_id, assignee_id);
+                             span: Span) {
+        debug!("add_assignment(lp={:?}, assign_id={:?}", lp, assign_id);
 
         let path_index = self.move_path(tcx, lp.clone());
 
-        match mode {
-            MutateMode::Init | MutateMode::JustWrite => {
-                self.assignee_ids.borrow_mut().insert(assignee_id);
-            }
-            MutateMode::WriteAndRead => { }
-        }
-
         let assignment = Assignment {
             path: path_index,
             id: assign_id,
             span,
-            assignee_id,
         };
 
         if self.is_var_path(path_index) {
diff --git a/src/librustc_borrowck/dataflow.rs b/src/librustc_borrowck/dataflow.rs
new file mode 100644 (file)
index 0000000..d5f30c1
--- /dev/null
@@ -0,0 +1,686 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+//! A module for propagating forward dataflow information. The analysis
+//! assumes that the items to be propagated can be represented as bits
+//! and thus uses bitvectors. Your job is simply to specify the so-called
+//! GEN and KILL bits for each expression.
+
+use rustc::cfg;
+use rustc::cfg::CFGIndex;
+use rustc::ty::TyCtxt;
+use std::io;
+use std::mem;
+use std::usize;
+use syntax::print::pprust::PrintState;
+
+use rustc_data_structures::graph::implementation::OUTGOING;
+
+use rustc::util::nodemap::FxHashMap;
+use rustc::hir;
+use rustc::hir::intravisit::{self, IdRange};
+use rustc::hir::print as pprust;
+
+
+#[derive(Copy, Clone, Debug)]
+pub enum EntryOrExit {
+    Entry,
+    Exit,
+}
+
+#[derive(Clone)]
+pub struct DataFlowContext<'a, 'tcx: 'a, O> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+
+    /// a name for the analysis using this dataflow instance
+    analysis_name: &'static str,
+
+    /// the data flow operator
+    oper: O,
+
+    /// number of bits to propagate per id
+    bits_per_id: usize,
+
+    /// number of words we will use to store bits_per_id.
+    /// equal to bits_per_id/usize::BITS rounded up.
+    words_per_id: usize,
+
+    // mapping from node to cfg node index
+    // FIXME (#6298): Shouldn't this go with CFG?
+    local_id_to_index: FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>,
+
+    // Bit sets per cfg node.  The following three fields (`gens`, `kills`,
+    // and `on_entry`) all have the same structure. For each id in
+    // `id_range`, there is a range of words equal to `words_per_id`.
+    // So, to access the bits for any given id, you take a slice of
+    // the full vector (see the method `compute_id_range()`).
+
+    /// bits generated as we exit the cfg node. Updated by `add_gen()`.
+    gens: Vec<usize>,
+
+    /// bits killed as we exit the cfg node, or non-locally jump over
+    /// it. Updated by `add_kill(KillFrom::ScopeEnd)`.
+    scope_kills: Vec<usize>,
+
+    /// bits killed as we exit the cfg node directly; if it is jumped
+    /// over, e.g. via `break`, the kills are not reflected in the
+    /// jump's effects. Updated by `add_kill(KillFrom::Execution)`.
+    action_kills: Vec<usize>,
+
+    /// bits that are valid on entry to the cfg node. Updated by
+    /// `propagate()`.
+    on_entry: Vec<usize>,
+}
+
+pub trait BitwiseOperator {
+    /// Joins two predecessor bits together, typically either `|` or `&`
+    fn join(&self, succ: usize, pred: usize) -> usize;
+}
+
+/// Parameterization for the precise form of data flow that is used.
+pub trait DataFlowOperator : BitwiseOperator {
+    /// Specifies the initial value for each bit in the `on_entry` set
+    fn initial_value(&self) -> bool;
+}
+
+struct PropagationContext<'a, 'b: 'a, 'tcx: 'b, O: 'a> {
+    dfcx: &'a mut DataFlowContext<'b, 'tcx, O>,
+    changed: bool
+}
+
+fn get_cfg_indices<'a>(id: hir::ItemLocalId,
+                       index: &'a FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>)
+                       -> &'a [CFGIndex] {
+    index.get(&id).map_or(&[], |v| &v[..])
+}
+
+impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
+    fn has_bitset_for_local_id(&self, n: hir::ItemLocalId) -> bool {
+        assert!(n != hir::DUMMY_ITEM_LOCAL_ID);
+        self.local_id_to_index.contains_key(&n)
+    }
+}
+
+impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O> {
+    fn nested(&self, state: &mut pprust::State, nested: pprust::Nested) -> io::Result<()> {
+        pprust::PpAnn::nested(&self.tcx.hir, state, nested)
+    }
+    fn pre(&self,
+           ps: &mut pprust::State,
+           node: pprust::AnnNode) -> io::Result<()> {
+        let id = match node {
+            pprust::NodeName(_) => return Ok(()),
+            pprust::NodeExpr(expr) => expr.hir_id.local_id,
+            pprust::NodeBlock(blk) => blk.hir_id.local_id,
+            pprust::NodeItem(_) |
+            pprust::NodeSubItem(_) => return Ok(()),
+            pprust::NodePat(pat) => pat.hir_id.local_id
+        };
+
+        if !self.has_bitset_for_local_id(id) {
+            return Ok(());
+        }
+
+        assert!(self.bits_per_id > 0);
+        let indices = get_cfg_indices(id, &self.local_id_to_index);
+        for &cfgidx in indices {
+            let (start, end) = self.compute_id_range(cfgidx);
+            let on_entry = &self.on_entry[start.. end];
+            let entry_str = bits_to_string(on_entry);
+
+            let gens = &self.gens[start.. end];
+            let gens_str = if gens.iter().any(|&u| u != 0) {
+                format!(" gen: {}", bits_to_string(gens))
+            } else {
+                "".to_string()
+            };
+
+            let action_kills = &self.action_kills[start .. end];
+            let action_kills_str = if action_kills.iter().any(|&u| u != 0) {
+                format!(" action_kill: {}", bits_to_string(action_kills))
+            } else {
+                "".to_string()
+            };
+
+            let scope_kills = &self.scope_kills[start .. end];
+            let scope_kills_str = if scope_kills.iter().any(|&u| u != 0) {
+                format!(" scope_kill: {}", bits_to_string(scope_kills))
+            } else {
+                "".to_string()
+            };
+
+            ps.synth_comment(
+                format!("id {}: {}{}{}{}", id.as_usize(), entry_str,
+                        gens_str, action_kills_str, scope_kills_str))?;
+            ps.s.space()?;
+        }
+        Ok(())
+    }
+}
+
+fn build_local_id_to_index(body: Option<&hir::Body>,
+                           cfg: &cfg::CFG)
+                           -> FxHashMap<hir::ItemLocalId, Vec<CFGIndex>> {
+    let mut index = FxHashMap();
+
+    // FIXME(#15020) Would it be better to fold formals from decl
+    // into cfg itself?  i.e. introduce a fn-based flow-graph in
+    // addition to the current block-based flow-graph, rather than
+    // have to put traversals like this here?
+    if let Some(body) = body {
+        add_entries_from_fn_body(&mut index, body, cfg.entry);
+    }
+
+    cfg.graph.each_node(|node_idx, node| {
+        if let cfg::CFGNodeData::AST(id) = node.data {
+            index.entry(id).or_insert(vec![]).push(node_idx);
+        }
+        true
+    });
+
+    return index;
+
+    /// Add mappings from the ast nodes for the formal bindings to
+    /// the entry-node in the graph.
+    fn add_entries_from_fn_body(index: &mut FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>,
+                                body: &hir::Body,
+                                entry: CFGIndex) {
+        use rustc::hir::intravisit::Visitor;
+
+        struct Formals<'a> {
+            entry: CFGIndex,
+            index: &'a mut FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>,
+        }
+        let mut formals = Formals { entry: entry, index: index };
+        for arg in &body.arguments {
+            formals.visit_pat(&arg.pat);
+        }
+        impl<'a, 'v> Visitor<'v> for Formals<'a> {
+            fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v> {
+                intravisit::NestedVisitorMap::None
+            }
+
+            fn visit_pat(&mut self, p: &hir::Pat) {
+                self.index.entry(p.hir_id.local_id).or_insert(vec![]).push(self.entry);
+                intravisit::walk_pat(self, p)
+            }
+        }
+    }
+}
+
+/// Flag used by `add_kill` to indicate whether the provided kill
+/// takes effect only when control flows directly through the node in
+/// question, or if the kill's effect is associated with any
+/// control-flow directly through or indirectly over the node.
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum KillFrom {
+    /// A `ScopeEnd` kill is one that takes effect when any control
+    /// flow goes over the node. A kill associated with the end of the
+    /// scope of a variable declaration `let x;` is an example of a
+    /// `ScopeEnd` kill.
+    ScopeEnd,
+
+    /// An `Execution` kill is one that takes effect only when control
+    /// flow goes through the node to completion. A kill associated
+    /// with an assignment statement `x = expr;` is an example of an
+    /// `Execution` kill.
+    Execution,
+}
+
+impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+               analysis_name: &'static str,
+               body: Option<&hir::Body>,
+               cfg: &cfg::CFG,
+               oper: O,
+               id_range: IdRange,
+               bits_per_id: usize) -> DataFlowContext<'a, 'tcx, O> {
+        let usize_bits = mem::size_of::<usize>() * 8;
+        let words_per_id = (bits_per_id + usize_bits - 1) / usize_bits;
+        let num_nodes = cfg.graph.all_nodes().len();
+
+        debug!("DataFlowContext::new(analysis_name: {}, id_range={:?}, \
+                                     bits_per_id={}, words_per_id={}) \
+                                     num_nodes: {}",
+               analysis_name, id_range, bits_per_id, words_per_id,
+               num_nodes);
+
+        let entry = if oper.initial_value() { usize::MAX } else {0};
+
+        let zeroes = vec![0; num_nodes * words_per_id];
+        let gens = zeroes.clone();
+        let kills1 = zeroes.clone();
+        let kills2 = zeroes;
+        let on_entry = vec![entry; num_nodes * words_per_id];
+
+        let local_id_to_index = build_local_id_to_index(body, cfg);
+
+        DataFlowContext {
+            tcx,
+            analysis_name,
+            words_per_id,
+            local_id_to_index,
+            bits_per_id,
+            oper,
+            gens,
+            action_kills: kills1,
+            scope_kills: kills2,
+            on_entry,
+        }
+    }
+
+    pub fn add_gen(&mut self, id: hir::ItemLocalId, bit: usize) {
+        //! Indicates that `id` generates `bit`
+        debug!("{} add_gen(id={:?}, bit={})",
+               self.analysis_name, id, bit);
+        assert!(self.local_id_to_index.contains_key(&id));
+        assert!(self.bits_per_id > 0);
+
+        let indices = get_cfg_indices(id, &self.local_id_to_index);
+        for &cfgidx in indices {
+            let (start, end) = self.compute_id_range(cfgidx);
+            let gens = &mut self.gens[start.. end];
+            set_bit(gens, bit);
+        }
+    }
+
+    pub fn add_kill(&mut self, kind: KillFrom, id: hir::ItemLocalId, bit: usize) {
+        //! Indicates that `id` kills `bit`
+        debug!("{} add_kill(id={:?}, bit={})",
+               self.analysis_name, id, bit);
+        assert!(self.local_id_to_index.contains_key(&id));
+        assert!(self.bits_per_id > 0);
+
+        let indices = get_cfg_indices(id, &self.local_id_to_index);
+        for &cfgidx in indices {
+            let (start, end) = self.compute_id_range(cfgidx);
+            let kills = match kind {
+                KillFrom::Execution => &mut self.action_kills[start.. end],
+                KillFrom::ScopeEnd =>  &mut self.scope_kills[start.. end],
+            };
+            set_bit(kills, bit);
+        }
+    }
+
+    fn apply_gen_kill(&self, cfgidx: CFGIndex, bits: &mut [usize]) {
+        //! Applies the gen and kill sets for `cfgidx` to `bits`
+        debug!("{} apply_gen_kill(cfgidx={:?}, bits={}) [before]",
+               self.analysis_name, cfgidx, mut_bits_to_string(bits));
+        assert!(self.bits_per_id > 0);
+
+        let (start, end) = self.compute_id_range(cfgidx);
+        let gens = &self.gens[start.. end];
+        bitwise(bits, gens, &Union);
+        let kills = &self.action_kills[start.. end];
+        bitwise(bits, kills, &Subtract);
+        let kills = &self.scope_kills[start.. end];
+        bitwise(bits, kills, &Subtract);
+
+        debug!("{} apply_gen_kill(cfgidx={:?}, bits={}) [after]",
+               self.analysis_name, cfgidx, mut_bits_to_string(bits));
+    }
+
+    fn compute_id_range(&self, cfgidx: CFGIndex) -> (usize, usize) {
+        let n = cfgidx.node_id();
+        let start = n * self.words_per_id;
+        let end = start + self.words_per_id;
+
+        assert!(start < self.gens.len());
+        assert!(end <= self.gens.len());
+        assert!(self.gens.len() == self.action_kills.len());
+        assert!(self.gens.len() == self.scope_kills.len());
+        assert!(self.gens.len() == self.on_entry.len());
+
+        (start, end)
+    }
+
+
+    pub fn each_bit_on_entry<F>(&self, id: hir::ItemLocalId, mut f: F) -> bool where
+        F: FnMut(usize) -> bool,
+    {
+        //! Iterates through each bit that is set on entry to `id`.
+        //! Only useful after `propagate()` has been called.
+        if !self.has_bitset_for_local_id(id) {
+            return true;
+        }
+        let indices = get_cfg_indices(id, &self.local_id_to_index);
+        for &cfgidx in indices {
+            if !self.each_bit_for_node(EntryOrExit::Entry, cfgidx, |i| f(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    pub fn each_bit_for_node<F>(&self, e: EntryOrExit, cfgidx: CFGIndex, f: F) -> bool where
+        F: FnMut(usize) -> bool,
+    {
+        //! Iterates through each bit that is set on entry/exit to `cfgidx`.
+        //! Only useful after `propagate()` has been called.
+
+        if self.bits_per_id == 0 {
+            // Skip the surprisingly common degenerate case.  (Note
+            // compute_id_range requires self.words_per_id > 0.)
+            return true;
+        }
+
+        let (start, end) = self.compute_id_range(cfgidx);
+        let on_entry = &self.on_entry[start.. end];
+        let temp_bits;
+        let slice = match e {
+            EntryOrExit::Entry => on_entry,
+            EntryOrExit::Exit => {
+                let mut t = on_entry.to_vec();
+                self.apply_gen_kill(cfgidx, &mut t);
+                temp_bits = t;
+                &temp_bits[..]
+            }
+        };
+        debug!("{} each_bit_for_node({:?}, cfgidx={:?}) bits={}",
+               self.analysis_name, e, cfgidx, bits_to_string(slice));
+        self.each_bit(slice, f)
+    }
+
+    pub fn each_gen_bit<F>(&self, id: hir::ItemLocalId, mut f: F) -> bool where
+        F: FnMut(usize) -> bool,
+    {
+        //! Iterates through each bit in the gen set for `id`.
+        if !self.has_bitset_for_local_id(id) {
+            return true;
+        }
+
+        if self.bits_per_id == 0 {
+            // Skip the surprisingly common degenerate case.  (Note
+            // compute_id_range requires self.words_per_id > 0.)
+            return true;
+        }
+
+        let indices = get_cfg_indices(id, &self.local_id_to_index);
+        for &cfgidx in indices {
+            let (start, end) = self.compute_id_range(cfgidx);
+            let gens = &self.gens[start.. end];
+            debug!("{} each_gen_bit(id={:?}, gens={})",
+                   self.analysis_name, id, bits_to_string(gens));
+            if !self.each_bit(gens, |i| f(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    fn each_bit<F>(&self, words: &[usize], mut f: F) -> bool where
+        F: FnMut(usize) -> bool,
+    {
+        //! Helper for iterating over the bits in a bit set.
+        //! Returns false on the first call to `f` that returns false;
+        //! if all calls to `f` return true, then returns true.
+
+        let usize_bits = mem::size_of::<usize>() * 8;
+        for (word_index, &word) in words.iter().enumerate() {
+            if word != 0 {
+                let base_index = word_index * usize_bits;
+                for offset in 0..usize_bits {
+                    let bit = 1 << offset;
+                    if (word & bit) != 0 {
+                        // NB: we round up the total number of bits
+                        // that we store in any given bit set so that
+                        // it is an even multiple of usize::BITS.  This
+                        // means that there may be some stray bits at
+                        // the end that do not correspond to any
+                        // actual value.  So before we callback, check
+                        // whether the bit_index is greater than the
+                        // actual value the user specified and stop
+                        // iterating if so.
+                        let bit_index = base_index + offset as usize;
+                        if bit_index >= self.bits_per_id {
+                            return true;
+                        } else if !f(bit_index) {
+                            return false;
+                        }
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    pub fn add_kills_from_flow_exits(&mut self, cfg: &cfg::CFG) {
+        //! Whenever you have a `break` or `continue` statement, flow
+        //! exits through any number of enclosing scopes on its way to
+        //! the new destination. This function infers the kill bits of
+        //! those control operators based on the kill bits associated
+        //! with those scopes.
+        //!
+        //! This is usually called (if it is called at all), after
+        //! all add_gen and add_kill calls, but before propagate.
+
+        debug!("{} add_kills_from_flow_exits", self.analysis_name);
+        if self.bits_per_id == 0 {
+            // Skip the surprisingly common degenerate case.  (Note
+            // compute_id_range requires self.words_per_id > 0.)
+            return;
+        }
+        cfg.graph.each_edge(|_edge_index, edge| {
+            let flow_exit = edge.source();
+            let (start, end) = self.compute_id_range(flow_exit);
+            let mut orig_kills = self.scope_kills[start.. end].to_vec();
+
+            let mut changed = false;
+            for &id in &edge.data.exiting_scopes {
+                let opt_cfg_idx = self.local_id_to_index.get(&id);
+                match opt_cfg_idx {
+                    Some(indices) => {
+                        for &cfg_idx in indices {
+                            let (start, end) = self.compute_id_range(cfg_idx);
+                            let kills = &self.scope_kills[start.. end];
+                            if bitwise(&mut orig_kills, kills, &Union) {
+                                debug!("scope exits: scope id={:?} \
+                                        (node={:?} of {:?}) added killset: {}",
+                                       id, cfg_idx, indices,
+                                       bits_to_string(kills));
+                                changed = true;
+                            }
+                        }
+                    }
+                    None => {
+                        debug!("{} add_kills_from_flow_exits flow_exit={:?} \
+                                no cfg_idx for exiting_scope={:?}",
+                               self.analysis_name, flow_exit, id);
+                    }
+                }
+            }
+
+            if changed {
+                let bits = &mut self.scope_kills[start.. end];
+                debug!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [before]",
+                       self.analysis_name, flow_exit, mut_bits_to_string(bits));
+                bits.copy_from_slice(&orig_kills[..]);
+                debug!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [after]",
+                       self.analysis_name, flow_exit, mut_bits_to_string(bits));
+            }
+            true
+        });
+    }
+}
+
+impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
+//                                ^^^^^^^^^^^^^ only needed for pretty printing
+    pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Body) {
+        //! Performs the data flow analysis.
+
+        if self.bits_per_id == 0 {
+            // Optimize the surprisingly common degenerate case.
+            return;
+        }
+
+        {
+            let words_per_id = self.words_per_id;
+            let mut propcx = PropagationContext {
+                dfcx: &mut *self,
+                changed: true
+            };
+
+            let nodes_po = cfg.graph.nodes_in_postorder(OUTGOING, cfg.entry);
+            let mut temp = vec![0; words_per_id];
+            let mut num_passes = 0;
+            while propcx.changed {
+                num_passes += 1;
+                propcx.changed = false;
+                propcx.reset(&mut temp);
+                propcx.walk_cfg(cfg, &nodes_po, &mut temp);
+            }
+            debug!("finished in {} iterations", num_passes);
+        }
+
+        debug!("Dataflow result for {}:", self.analysis_name);
+        debug!("{}", pprust::to_string(self, |s| {
+            s.cbox(pprust::indent_unit)?;
+            s.ibox(0)?;
+            s.print_expr(&body.value)
+        }));
+    }
+}
+
+impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
+    fn walk_cfg(&mut self,
+                cfg: &cfg::CFG,
+                nodes_po: &[CFGIndex],
+                in_out: &mut [usize]) {
+        debug!("DataFlowContext::walk_cfg(in_out={}) {}",
+               bits_to_string(in_out), self.dfcx.analysis_name);
+        assert!(self.dfcx.bits_per_id > 0);
+
+        // Iterate over nodes in reverse postorder
+        for &node_index in nodes_po.iter().rev() {
+            let node = cfg.graph.node(node_index);
+            debug!("DataFlowContext::walk_cfg idx={:?} id={:?} begin in_out={}",
+                   node_index, node.data.id(), bits_to_string(in_out));
+
+            let (start, end) = self.dfcx.compute_id_range(node_index);
+
+            // Initialize local bitvector with state on-entry.
+            in_out.copy_from_slice(&self.dfcx.on_entry[start.. end]);
+
+            // Compute state on-exit by applying transfer function to
+            // state on-entry.
+            self.dfcx.apply_gen_kill(node_index, in_out);
+
+            // Propagate state on-exit from node into its successors.
+            self.propagate_bits_into_graph_successors_of(in_out, cfg, node_index);
+        }
+    }
+
+    fn reset(&mut self, bits: &mut [usize]) {
+        let e = if self.dfcx.oper.initial_value() {usize::MAX} else {0};
+        for b in bits {
+            *b = e;
+        }
+    }
+
+    fn propagate_bits_into_graph_successors_of(&mut self,
+                                               pred_bits: &[usize],
+                                               cfg: &cfg::CFG,
+                                               cfgidx: CFGIndex) {
+        for (_, edge) in cfg.graph.outgoing_edges(cfgidx) {
+            self.propagate_bits_into_entry_set_for(pred_bits, edge);
+        }
+    }
+
+    fn propagate_bits_into_entry_set_for(&mut self,
+                                         pred_bits: &[usize],
+                                         edge: &cfg::CFGEdge) {
+        let source = edge.source();
+        let cfgidx = edge.target();
+        debug!("{} propagate_bits_into_entry_set_for(pred_bits={}, {:?} to {:?})",
+               self.dfcx.analysis_name, bits_to_string(pred_bits), source, cfgidx);
+        assert!(self.dfcx.bits_per_id > 0);
+
+        let (start, end) = self.dfcx.compute_id_range(cfgidx);
+        let changed = {
+            // (scoping mutable borrow of self.dfcx.on_entry)
+            let on_entry = &mut self.dfcx.on_entry[start.. end];
+            bitwise(on_entry, pred_bits, &self.dfcx.oper)
+        };
+        if changed {
+            debug!("{} changed entry set for {:?} to {}",
+                   self.dfcx.analysis_name, cfgidx,
+                   bits_to_string(&self.dfcx.on_entry[start.. end]));
+            self.changed = true;
+        }
+    }
+}
+
+fn mut_bits_to_string(words: &mut [usize]) -> String {
+    bits_to_string(words)
+}
+
+fn bits_to_string(words: &[usize]) -> String {
+    let mut result = String::new();
+    let mut sep = '[';
+
+    // Note: this is a little endian printout of bytes.
+
+    for &word in words {
+        let mut v = word;
+        for _ in 0..mem::size_of::<usize>() {
+            result.push(sep);
+            result.push_str(&format!("{:02x}", v & 0xFF));
+            v >>= 8;
+            sep = '-';
+        }
+    }
+    result.push(']');
+    return result
+}
+
+#[inline]
+fn bitwise<Op:BitwiseOperator>(out_vec: &mut [usize],
+                               in_vec: &[usize],
+                               op: &Op) -> bool {
+    assert_eq!(out_vec.len(), in_vec.len());
+    let mut changed = false;
+    for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) {
+        let old_val = *out_elt;
+        let new_val = op.join(old_val, *in_elt);
+        *out_elt = new_val;
+        changed |= old_val != new_val;
+    }
+    changed
+}
+
+fn set_bit(words: &mut [usize], bit: usize) -> bool {
+    debug!("set_bit: words={} bit={}",
+           mut_bits_to_string(words), bit_str(bit));
+    let usize_bits = mem::size_of::<usize>() * 8;
+    let word = bit / usize_bits;
+    let bit_in_word = bit % usize_bits;
+    let bit_mask = 1 << bit_in_word;
+    debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
+    let oldv = words[word];
+    let newv = oldv | bit_mask;
+    words[word] = newv;
+    oldv != newv
+}
+
+fn bit_str(bit: usize) -> String {
+    let byte = bit >> 3;
+    let lobits = 1 << (bit & 0b111);
+    format!("[{}:{}-{:02x}]", bit, byte, lobits)
+}
+
+struct Union;
+impl BitwiseOperator for Union {
+    fn join(&self, a: usize, b: usize) -> usize { a | b }
+}
+struct Subtract;
+impl BitwiseOperator for Subtract {
+    fn join(&self, a: usize, b: usize) -> usize { a & !b }
+}
index 22867ba5b55a4ae779ebef38fa6469abc5e90ed0..dddd6a354c115bd6f95c24c62f68a8720cfc8294 100644 (file)
@@ -21,7 +21,7 @@
 use borrowck::{BorrowckCtxt, LoanPath};
 use dot;
 use rustc::cfg::CFGIndex;
-use rustc::middle::dataflow::{DataFlowOperator, DataFlowContext, EntryOrExit};
+use dataflow::{DataFlowOperator, DataFlowContext, EntryOrExit};
 use std::rc::Rc;
 use dot::IntoCow;
 
index aa85582432b75f5e12b1a6557377a8eeede61667..16da8c8a3b8bf6651dc41d8b70ef0f9b7cc8341d 100644 (file)
@@ -39,4 +39,6 @@
 
 pub mod graphviz;
 
+mod dataflow;
+
 pub use borrowck::provide;
index e0a30ef5dbc9abe10befecbda24285ef84a394fd..ef98fae9cc7ee46af16dc668a0b2cecf9954a7ee 100644 (file)
@@ -1079,6 +1079,9 @@ fn finalize(&mut self) -> Command {
         // For now we just never have an entry symbol
         self.cmd.arg("--no-entry");
 
+        // Make the default table accessible
+        self.cmd.arg("--export-table");
+
         let mut cmd = Command::new("");
         ::std::mem::swap(&mut cmd, &mut self.cmd);
         cmd
index 18a1e9129b34284bd6949794742d7b83bedba6ef..2acc29acb0caafd0325520d054fd1c18969d3127 100644 (file)
@@ -97,12 +97,7 @@ pub fn maybe_map<F, U>(&self, mut f: F) -> Option<TransitiveRelation<U>>
     {
         let mut result = TransitiveRelation::new();
         for edge in &self.edges {
-            f(&self.elements[edge.source.0]).and_then(|source| {
-                f(&self.elements[edge.target.0]).and_then(|target| {
-                    result.add(source, target);
-                    Some(())
-                })
-            })?;
+            result.add(f(&self.elements[edge.source.0])?, f(&self.elements[edge.target.0])?);
         }
         Some(result)
     }
index 967a8d90330968acdeb4106eb0931aa6b4a88a4f..f96b9b8082fa799d2aee174bd92565d7b2cf0c1b 100644 (file)
@@ -151,7 +151,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
     let location_table = &LocationTable::new(mir);
 
     let mut errors_buffer = Vec::new();
-    let (move_data, move_errors): (MoveData<'tcx>, Option<Vec<MoveError<'tcx>>>) =
+    let (move_data, move_errors): (MoveData<'tcx>, Option<Vec<(Place<'tcx>, MoveError<'tcx>)>>) =
         match MoveData::gather_moves(mir, tcx) {
             Ok(move_data) => (move_data, None),
             Err((move_data, move_errors)) => (move_data, Some(move_errors)),
index 4d988fef450b8a527f5a5e341dca51b9a62e779d..56ca4db098f87217f9534118238e08b1f3956a38 100644 (file)
@@ -8,14 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::hir;
+use core::unicode::property::Pattern_White_Space;
 use rustc::mir::*;
 use rustc::ty;
-use rustc_data_structures::indexed_vec::Idx;
 use rustc_errors::DiagnosticBuilder;
+use rustc_data_structures::indexed_vec::Idx;
 use syntax_pos::Span;
 
 use borrow_check::MirBorrowckCtxt;
+use borrow_check::prefixes::PrefixSet;
 use dataflow::move_paths::{IllegalMoveOrigin, IllegalMoveOriginKind};
 use dataflow::move_paths::{LookupResult, MoveError, MovePathIndex};
 use util::borrowck_errors::{BorrowckErrors, Origin};
 // let (&x, &y) = (&String::new(), &String::new());
 #[derive(Debug)]
 enum GroupedMoveError<'tcx> {
-    // Match place can't be moved from
+    // Place expression can't be moved from,
     // e.g. match x[0] { s => (), } where x: &[String]
-    MovesFromMatchPlace {
+    MovesFromPlace {
+        original_path: Place<'tcx>,
         span: Span,
         move_from: Place<'tcx>,
         kind: IllegalMoveOriginKind<'tcx>,
         binds_to: Vec<Local>,
     },
-    // Part of a pattern can't be moved from,
+    // Part of a value expression can't be moved from,
     // e.g. match &String::new() { &x => (), }
-    MovesFromPattern {
+    MovesFromValue {
+        original_path: Place<'tcx>,
         span: Span,
         move_from: MovePathIndex,
         kind: IllegalMoveOriginKind<'tcx>,
@@ -53,23 +56,27 @@ enum GroupedMoveError<'tcx> {
     },
     // Everything that isn't from pattern matching.
     OtherIllegalMove {
+        original_path: Place<'tcx>,
         span: Span,
         kind: IllegalMoveOriginKind<'tcx>,
     },
 }
 
 impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
-    pub(crate) fn report_move_errors(&mut self, move_errors: Vec<MoveError<'tcx>>) {
+    pub(crate) fn report_move_errors(&mut self, move_errors: Vec<(Place<'tcx>, MoveError<'tcx>)>) {
         let grouped_errors = self.group_move_errors(move_errors);
         for error in grouped_errors {
             self.report(error);
         }
     }
 
-    fn group_move_errors(&self, errors: Vec<MoveError<'tcx>>) -> Vec<GroupedMoveError<'tcx>> {
+    fn group_move_errors(
+        &self,
+        errors: Vec<(Place<'tcx>, MoveError<'tcx>)>
+    ) -> Vec<GroupedMoveError<'tcx>> {
         let mut grouped_errors = Vec::new();
-        for error in errors {
-            self.append_to_grouped_errors(&mut grouped_errors, error);
+        for (original_path, error) in errors {
+            self.append_to_grouped_errors(&mut grouped_errors, original_path, error);
         }
         grouped_errors
     }
@@ -77,6 +84,7 @@ fn group_move_errors(&self, errors: Vec<MoveError<'tcx>>) -> Vec<GroupedMoveErro
     fn append_to_grouped_errors(
         &self,
         grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
+        original_path: Place<'tcx>,
         error: MoveError<'tcx>,
     ) {
         match error {
@@ -111,11 +119,13 @@ fn append_to_grouped_errors(
                         opt_match_place: Some((ref opt_match_place, match_span)),
                         binding_mode: _,
                         opt_ty_info: _,
+                        pat_span: _,
                     }))) = local_decl.is_user_variable
                     {
                         self.append_binding_error(
                             grouped_errors,
                             kind,
+                            original_path,
                             move_from,
                             *local,
                             opt_match_place,
@@ -127,6 +137,7 @@ fn append_to_grouped_errors(
                 }
                 grouped_errors.push(GroupedMoveError::OtherIllegalMove {
                     span: stmt_source_info.span,
+                    original_path,
                     kind,
                 });
             }
@@ -137,6 +148,7 @@ fn append_binding_error(
         &self,
         grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
         kind: IllegalMoveOriginKind<'tcx>,
+        original_path: Place<'tcx>,
         move_from: &Place<'tcx>,
         bind_to: Local,
         match_place: &Option<Place<'tcx>>,
@@ -144,7 +156,7 @@ fn append_binding_error(
         statement_span: Span,
     ) {
         debug!(
-            "append_to_grouped_errors(match_place={:?}, match_span={:?})",
+            "append_binding_error(match_place={:?}, match_span={:?})",
             match_place, match_span
         );
 
@@ -155,7 +167,7 @@ fn append_binding_error(
             // Error with the match place
             LookupResult::Parent(_) => {
                 for ge in &mut *grouped_errors {
-                    if let GroupedMoveError::MovesFromMatchPlace { span, binds_to, .. } = ge {
+                    if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge {
                         if match_span == *span {
                             debug!("appending local({:?}) to list", bind_to);
                             if !binds_to.is_empty() {
@@ -173,9 +185,10 @@ fn append_binding_error(
                 } else {
                     (vec![bind_to], match_span)
                 };
-                grouped_errors.push(GroupedMoveError::MovesFromMatchPlace {
+                grouped_errors.push(GroupedMoveError::MovesFromPlace {
                     span,
                     move_from: match_place.clone(),
+                    original_path,
                     kind,
                     binds_to,
                 });
@@ -188,7 +201,7 @@ fn append_binding_error(
                     _ => unreachable!("Probably not unreachable..."),
                 };
                 for ge in &mut *grouped_errors {
-                    if let GroupedMoveError::MovesFromPattern {
+                    if let GroupedMoveError::MovesFromValue {
                         span,
                         move_from: other_mpi,
                         binds_to,
@@ -203,9 +216,10 @@ fn append_binding_error(
                     }
                 }
                 debug!("found a new move error location");
-                grouped_errors.push(GroupedMoveError::MovesFromPattern {
+                grouped_errors.push(GroupedMoveError::MovesFromValue {
                     span: match_span,
                     move_from: mpi,
+                    original_path,
                     kind,
                     binds_to: vec![bind_to],
                 });
@@ -215,12 +229,23 @@ fn append_binding_error(
 
     fn report(&mut self, error: GroupedMoveError<'tcx>) {
         let (mut err, err_span) = {
-            let (span, kind): (Span, &IllegalMoveOriginKind) = match error {
-                GroupedMoveError::MovesFromMatchPlace { span, ref kind, .. }
-                | GroupedMoveError::MovesFromPattern { span, ref kind, .. }
-                | GroupedMoveError::OtherIllegalMove { span, ref kind } => (span, kind),
-            };
+            let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind) =
+                match error {
+                    GroupedMoveError::MovesFromPlace {
+                        span,
+                        ref original_path,
+                        ref kind,
+                        ..
+                    } |
+                    GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } |
+                    GroupedMoveError::OtherIllegalMove { span, ref original_path, ref kind } => {
+                        (span, original_path, kind)
+                    },
+                };
             let origin = Origin::Mir;
+            debug!("report: original_path={:?} span={:?}, kind={:?} \
+                   original_path.is_upvar_field_projection={:?}", original_path, span, kind,
+                   original_path.is_upvar_field_projection(self.mir, &self.tcx));
             (
                 match kind {
                     IllegalMoveOriginKind::Static => {
@@ -231,22 +256,17 @@ fn report(&mut self, error: GroupedMoveError<'tcx>) {
                         // borrow to provide feedback about why this
                         // was a move rather than a copy.
                         let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx);
+                        let is_upvar_field_projection =
+                            self.prefixes(&original_path, PrefixSet::All)
+                            .any(|p| p.is_upvar_field_projection(self.mir, &self.tcx)
+                                 .is_some());
                         match ty.sty {
                             ty::TyArray(..) | ty::TySlice(..) => self
                                 .tcx
                                 .cannot_move_out_of_interior_noncopy(span, ty, None, origin),
                             ty::TyClosure(def_id, closure_substs)
-                                if !self.mir.upvar_decls.is_empty()
-                                    && {
-                                        match place {
-                                            Place::Projection(ref proj) => {
-                                                proj.base == Place::Local(Local::new(1))
-                                            }
-                                            Place::Promoted(_) |
-                                            Place::Local(_) | Place::Static(_) => unreachable!(),
-                                        }
-                                    } =>
-                            {
+                                if !self.mir.upvar_decls.is_empty() && is_upvar_field_projection
+                            => {
                                 let closure_kind_ty =
                                     closure_substs.closure_kind_ty(def_id, self.tcx);
                                 let closure_kind = closure_kind_ty.to_opt_closure_kind();
@@ -262,7 +282,28 @@ fn report(&mut self, error: GroupedMoveError<'tcx>) {
                                     }
                                     None => bug!("closure kind not inferred by borrowck"),
                                 };
-                                self.tcx.cannot_move_out_of(span, place_description, origin)
+                                debug!("report: closure_kind_ty={:?} closure_kind={:?} \
+                                       place_description={:?}", closure_kind_ty, closure_kind,
+                                       place_description);
+
+                                let mut diag = self.tcx.cannot_move_out_of(
+                                    span, place_description, origin);
+
+                                for prefix in self.prefixes(&original_path, PrefixSet::All) {
+                                    if let Some(field) = prefix.is_upvar_field_projection(
+                                            self.mir, &self.tcx) {
+                                        let upvar_decl = &self.mir.upvar_decls[field.index()];
+                                        let upvar_hir_id =
+                                            upvar_decl.var_hir_id.assert_crate_local();
+                                        let upvar_node_id =
+                                            self.tcx.hir.hir_to_node_id(upvar_hir_id);
+                                        let upvar_span = self.tcx.hir.span(upvar_node_id);
+                                        diag.span_label(upvar_span, "captured outer variable");
+                                        break;
+                                    }
+                                }
+
+                                diag
                             }
                             _ => self
                                 .tcx
@@ -291,111 +332,140 @@ fn add_move_hints(
         err: &mut DiagnosticBuilder<'a>,
         span: Span,
     ) {
+        let snippet = self.tcx.sess.codemap().span_to_snippet(span).unwrap();
         match error {
-            GroupedMoveError::MovesFromMatchPlace {
+            GroupedMoveError::MovesFromPlace {
                 mut binds_to,
                 move_from,
                 ..
             } => {
-                // Ok to suggest a borrow, since the target can't be moved from
-                // anyway.
-                if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
-                    match move_from {
-                        Place::Projection(ref proj)
-                            if self.suitable_to_remove_deref(proj, &snippet) =>
-                        {
-                            err.span_suggestion(
-                                span,
-                                "consider removing this dereference operator",
-                                (&snippet[1..]).to_owned(),
-                            );
-                        }
-                        _ => {
-                            err.span_suggestion(
-                                span,
-                                "consider using a reference instead",
-                                format!("&{}", snippet),
-                            );
-                        }
-                    }
-
-                    binds_to.sort();
-                    binds_to.dedup();
-                    for local in binds_to {
-                        let bind_to = &self.mir.local_decls[local];
-                        let binding_span = bind_to.source_info.span;
-                        err.span_label(
-                            binding_span,
-                            format!(
-                                "move occurs because {} has type `{}`, \
-                                 which does not implement the `Copy` trait",
-                                bind_to.name.unwrap(),
-                                bind_to.ty
-                            ),
-                        );
-                    }
+                let try_remove_deref = match move_from {
+                    Place::Projection(box PlaceProjection {
+                        elem: ProjectionElem::Deref,
+                        ..
+                    }) => true,
+                    _ => false,
+                };
+                if try_remove_deref && snippet.starts_with('*') {
+                    // The snippet doesn't start with `*` in (e.g.) index
+                    // expressions `a[b]`, which roughly desugar to
+                    // `*Index::index(&a, b)` or
+                    // `*IndexMut::index_mut(&mut a, b)`.
+                    err.span_suggestion(
+                        span,
+                        "consider removing the `*`",
+                        snippet[1..].to_owned(),
+                    );
+                } else {
+                    err.span_suggestion(
+                        span,
+                        "consider borrowing here",
+                        format!("&{}", snippet),
+                    );
                 }
+
+                binds_to.sort();
+                binds_to.dedup();
+                self.add_move_error_details(err, &binds_to);
             }
-            GroupedMoveError::MovesFromPattern { mut binds_to, .. } => {
-                // Suggest ref, since there might be a move in
-                // another match arm
+            GroupedMoveError::MovesFromValue { mut binds_to, .. } => {
                 binds_to.sort();
                 binds_to.dedup();
-                let mut multipart_suggestion = Vec::with_capacity(binds_to.len());
-                for (j, local) in binds_to.into_iter().enumerate() {
-                    let bind_to = &self.mir.local_decls[local];
-                    let binding_span = bind_to.source_info.span;
+                self.add_move_error_suggestions(err, &binds_to);
+                self.add_move_error_details(err, &binds_to);
+            }
+            // No binding. Nothing to suggest.
+            GroupedMoveError::OtherIllegalMove { .. } => (),
+        }
+    }
 
-                    // Suggest ref mut when the user has already written mut.
-                    let ref_kind = match bind_to.mutability {
-                        Mutability::Not => "ref",
-                        Mutability::Mut => "ref mut",
-                    };
-                    if j == 0 {
-                        err.span_label(binding_span, format!("data moved here"));
+    fn add_move_error_suggestions(
+        &self,
+        err: &mut DiagnosticBuilder<'a>,
+        binds_to: &[Local],
+    ) {
+        let mut suggestions: Vec<(Span, &str, String)> = Vec::new();
+        for local in binds_to {
+            let bind_to = &self.mir.local_decls[*local];
+            if let Some(
+                ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+                    pat_span,
+                    ..
+                }))
+            ) = bind_to.is_user_variable {
+                let pat_snippet = self
+                    .tcx.sess.codemap()
+                    .span_to_snippet(pat_span)
+                    .unwrap();
+                if pat_snippet.starts_with('&') {
+                    let pat_snippet = pat_snippet[1..].trim_left();
+                    let suggestion;
+                    let to_remove;
+                    if pat_snippet.starts_with("mut")
+                        && pat_snippet["mut".len()..].starts_with(Pattern_White_Space)
+                    {
+                        suggestion = pat_snippet["mut".len()..].trim_left();
+                        to_remove = "&mut";
                     } else {
-                        err.span_label(binding_span, format!("... and here"));
-                    }
-                    match bind_to.name {
-                        Some(name) => {
-                            multipart_suggestion.push((binding_span,
-                                                       format!("{} {}", ref_kind, name)));
-                        }
-                        None => {
-                            err.span_label(
-                                span,
-                                format!("Local {:?} is not suitable for ref", bind_to),
-                            );
-                        }
+                        suggestion = pat_snippet;
+                        to_remove = "&";
                     }
+                    suggestions.push((
+                        pat_span,
+                        to_remove,
+                        suggestion.to_owned(),
+                    ));
                 }
-                err.multipart_suggestion("to prevent move, use ref or ref mut",
-                                         multipart_suggestion);
             }
-            // Nothing to suggest.
-            GroupedMoveError::OtherIllegalMove { .. } => (),
+        }
+        suggestions.sort_unstable_by_key(|&(span, _, _)| span);
+        suggestions.dedup_by_key(|&mut (span, _, _)| span);
+        for (span, to_remove, suggestion) in suggestions {
+            err.span_suggestion(
+                span,
+                &format!("consider removing the `{}`", to_remove),
+                suggestion
+            );
         }
     }
 
-    fn suitable_to_remove_deref(&self, proj: &PlaceProjection<'tcx>, snippet: &str) -> bool {
-        let is_shared_ref = |ty: ty::Ty| match ty.sty {
-            ty::TypeVariants::TyRef(.., hir::Mutability::MutImmutable) => true,
-            _ => false,
-        };
+    fn add_move_error_details(
+        &self,
+        err: &mut DiagnosticBuilder<'a>,
+        binds_to: &[Local],
+    ) {
+        let mut noncopy_var_spans = Vec::new();
+        for (j, local) in binds_to.into_iter().enumerate() {
+            let bind_to = &self.mir.local_decls[*local];
+            let binding_span = bind_to.source_info.span;
+
+            if j == 0 {
+                err.span_label(binding_span, format!("data moved here"));
+            } else {
+                err.span_label(binding_span, format!("...and here"));
+            }
 
-        proj.elem == ProjectionElem::Deref && snippet.starts_with('*') && match proj.base {
-            Place::Local(local) => {
-                let local_decl = &self.mir.local_decls[local];
-                // If this is a temporary, then this could be from an
-                // overloaded * operator.
-                local_decl.is_user_variable.is_some() && is_shared_ref(local_decl.ty)
+            if binds_to.len() == 1 {
+                err.span_note(
+                    binding_span,
+                    &format!(
+                        "move occurs because `{}` has type `{}`, \
+                            which does not implement the `Copy` trait",
+                        bind_to.name.unwrap(),
+                        bind_to.ty
+                    ),
+                );
+            } else {
+                noncopy_var_spans.push(binding_span);
             }
-            Place::Promoted(_) => true,
-            Place::Static(ref st) => is_shared_ref(st.ty),
-            Place::Projection(ref proj) => match proj.elem {
-                ProjectionElem::Field(_, ty) => is_shared_ref(ty),
-                _ => false,
-            },
+        }
+
+        if binds_to.len() > 1 {
+            err.span_note(
+                noncopy_var_spans,
+                "move occurs because these variables have types that \
+                    don't implement the `Copy` trait",
+            );
         }
     }
 }
index e8862320ddf3fcc83ce454ad0b92cae14743edd7..f11135fc026f53acd940600a43d226a733416c30 100644 (file)
@@ -36,10 +36,18 @@ pub(super) fn report_mutability_error(
         error_access: AccessKind,
         location: Location,
     ) {
+        debug!(
+            "report_mutability_error(\
+                access_place={:?}, span={:?}, the_place_err={:?}, error_access={:?}, location={:?},\
+            )",
+            access_place, span, the_place_err, error_access, location,
+        );
+
         let mut err;
         let item_msg;
         let reason;
         let access_place_desc = self.describe_place(access_place);
+        debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
 
         match the_place_err {
             Place::Local(local) => {
@@ -63,7 +71,7 @@ pub(super) fn report_mutability_error(
                 ));
 
                 item_msg = format!("`{}`", access_place_desc.unwrap());
-                if self.is_upvar(access_place) {
+                if access_place.is_upvar_field_projection(self.mir, &self.tcx).is_some() {
                     reason = ", as it is not declared as mutable".to_string();
                 } else {
                     let name = self.mir.upvar_decls[upvar_index.index()].debug_name;
@@ -82,7 +90,8 @@ pub(super) fn report_mutability_error(
                         the_place_err.ty(self.mir, self.tcx).to_ty(self.tcx)
                     ));
 
-                    reason = if self.is_upvar(access_place) {
+                    reason = if access_place.is_upvar_field_projection(self.mir,
+                                                                       &self.tcx).is_some() {
                         ", as it is a captured variable in a `Fn` closure".to_string()
                     } else {
                         ", as `Fn` closures cannot mutate their captured variables".to_string()
@@ -155,6 +164,8 @@ pub(super) fn report_mutability_error(
             }) => bug!("Unexpected immutable place."),
         }
 
+        debug!("report_mutability_error: item_msg={:?}, reason={:?}", item_msg, reason);
+
         // `act` and `acted_on` are strings that let us abstract over
         // the verbs used in some diagnostic messages.
         let act;
@@ -199,6 +210,8 @@ pub(super) fn report_mutability_error(
             }
         };
 
+        debug!("report_mutability_error: act={:?}, acted_on={:?}", act, acted_on);
+
         match the_place_err {
             // We want to suggest users use `let mut` for local (user
             // variable) mutations...
@@ -316,7 +329,11 @@ pub(super) fn report_mutability_error(
                     ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm {
                         binding_mode: ty::BindingMode::BindByReference(_),
                         ..
-                    })) => suggest_ref_mut(self.tcx, local_decl.source_info.span),
+                    })) => {
+                        let pattern_span = local_decl.source_info.span;
+                        suggest_ref_mut(self.tcx, pattern_span)
+                            .map(|replacement| (pattern_span, replacement))
+                    }
 
                     //
                     ClearCrossCrate::Set(mir::BindingForm::RefForGuard) => unreachable!(),
@@ -382,31 +399,6 @@ pub(super) fn report_mutability_error(
 
         err.buffer(&mut self.errors_buffer);
     }
-
-    // Does this place refer to what the user sees as an upvar
-    fn is_upvar(&self, place: &Place<'tcx>) -> bool {
-        match *place {
-            Place::Projection(box Projection {
-                ref base,
-                elem: ProjectionElem::Field(_, _),
-            }) => {
-                let base_ty = base.ty(self.mir, self.tcx).to_ty(self.tcx);
-                is_closure_or_generator(base_ty)
-            }
-            Place::Projection(box Projection {
-                base:
-                    Place::Projection(box Projection {
-                        ref base,
-                        elem: ProjectionElem::Field(upvar_index, _),
-                    }),
-                elem: ProjectionElem::Deref,
-            }) => {
-                let base_ty = base.ty(self.mir, self.tcx).to_ty(self.tcx);
-                is_closure_or_generator(base_ty) && self.mir.upvar_decls[upvar_index.index()].by_ref
-            }
-            _ => false,
-        }
-    }
 }
 
 fn suggest_ampmut_self<'cx, 'gcx, 'tcx>(
index 6b6ec749bcbe6efd1124d6f529264564a4aab661..b317bb7cff0e3c9a6e0b720f0dd0b2a63e1123f9 100644 (file)
@@ -321,9 +321,10 @@ pub fn place_into_pattern(&mut self,
         block.unit()
     }
 
-    /// Declares the bindings of the given pattern and returns the visibility scope
-    /// for the bindings in this patterns, if such a scope had to be created.
-    /// NOTE: Declaring the bindings should always be done in their drop scope.
+    /// Declares the bindings of the given patterns and returns the visibility
+    /// scope for the bindings in these patterns, if such a scope had to be
+    /// created. NOTE: Declaring the bindings should always be done in their
+    /// drop scope.
     pub fn declare_bindings(&mut self,
                             mut visibility_scope: Option<SourceScope>,
                             scope_span: Span,
@@ -356,7 +357,8 @@ pub fn declare_bindings(&mut self,
             let visibility_scope = visibility_scope.unwrap();
             this.declare_binding(source_info, visibility_scope, mutability, name, mode,
                                  num_patterns, var, ty, has_guard,
-                                 opt_match_place.map(|(x, y)| (x.cloned(), y)));
+                                 opt_match_place.map(|(x, y)| (x.cloned(), y)),
+                                 patterns[0].span);
         });
         visibility_scope
     }
@@ -1181,7 +1183,8 @@ fn declare_binding(&mut self,
                        var_id: NodeId,
                        var_ty: Ty<'tcx>,
                        has_guard: ArmHasGuard,
-                       opt_match_place: Option<(Option<Place<'tcx>>, Span)>)
+                       opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
+                       pat_span: Span)
     {
         debug!("declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \
                 visibility_scope={:?}, source_info={:?})",
@@ -1207,6 +1210,7 @@ fn declare_binding(&mut self,
                 // Instead, just abandon providing diagnostic info.
                 opt_ty_info: None,
                 opt_match_place,
+                pat_span,
             }))),
         };
         let for_arm_body = self.local_decls.push(local.clone());
index 054bd69c361b92115eb6c60dd32e67ec3cccbcd4..c0c431804d8c1ea52fcf1716084e06c761586e55 100644 (file)
@@ -763,6 +763,7 @@ fn args_and_body(&mut self,
                                     binding_mode,
                                     opt_ty_info,
                                     opt_match_place: Some((Some(place.clone()), span)),
+                                    pat_span: span,
                                 })))
                             };
                         self.var_indices.insert(var, LocalsForNode::One(local));
index 44e46e90549a706950d97da0750bd124f62035df..60030f270205523937958bbb7f78ab341002015c 100644 (file)
@@ -27,7 +27,7 @@ struct MoveDataBuilder<'a, 'gcx: 'tcx, 'tcx: 'a> {
     mir: &'a Mir<'tcx>,
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     data: MoveData<'tcx>,
-    errors: Vec<MoveError<'tcx>>,
+    errors: Vec<(Place<'tcx>, MoveError<'tcx>)>,
 }
 
 impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> {
@@ -186,7 +186,9 @@ fn move_path_for_projection(&mut self,
 }
 
 impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> {
-    fn finalize(self) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<MoveError<'tcx>>)> {
+    fn finalize(
+        self
+    ) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
         debug!("{}", {
             debug!("moves for {:?}:", self.mir.span);
             for (j, mo) in self.data.moves.iter_enumerated() {
@@ -207,9 +209,10 @@ fn finalize(self) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<MoveError<'tcx>
     }
 }
 
-pub(super) fn gather_moves<'a, 'gcx, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>)
-                                           -> Result<MoveData<'tcx>,
-                                                     (MoveData<'tcx>, Vec<MoveError<'tcx>>)> {
+pub(super) fn gather_moves<'a, 'gcx, 'tcx>(
+    mir: &Mir<'tcx>,
+    tcx: TyCtxt<'a, 'gcx, 'tcx>
+) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
     let mut builder = MoveDataBuilder::new(mir, tcx);
 
     builder.gather_args();
@@ -407,7 +410,7 @@ fn gather_move(&mut self, place: &Place<'tcx>) {
         let path = match self.move_path_for(place) {
             Ok(path) | Err(MoveError::UnionMove { path }) => path,
             Err(error @ MoveError::IllegalMove { .. }) => {
-                self.builder.errors.push(error);
+                self.builder.errors.push((place.clone(), error));
                 return;
             }
         };
index 64bfd36b7eeb6d92faaeb0a19b77c1dcf5c46fb6..7b4cbdf7131b0e67b2c3b78b5c2a3a29210be39a 100644 (file)
@@ -313,7 +313,7 @@ fn cannot_move_out_of(location: Location, kind: IllegalMoveOriginKind<'tcx>) ->
 
 impl<'a, 'gcx, 'tcx> MoveData<'tcx> {
     pub fn gather_moves(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>)
-                        -> Result<Self, (Self, Vec<MoveError<'tcx>>)> {
+                        -> Result<Self, (Self, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
         builder::gather_moves(mir, tcx)
     }
 }
index 42682c34407cab08c713731ac8fc89d4dadbc097..bda80ff562c75ede8ef6cbacc79b5982d36de066 100644 (file)
@@ -35,6 +35,7 @@
 #![feature(try_trait)]
 #![feature(unicode_internals)]
 #![feature(step_trait)]
+#![feature(slice_concat_ext)]
 
 #![recursion_limit="256"]
 
index 78e9dd23e83ae718387a9fa5bd1e47e2a50028e3..fe6fefe89fd66b59cab4e0e5b4887eb165fbc1ce 100644 (file)
 /// If possible, suggest replacing `ref` with `ref mut`.
 pub fn suggest_ref_mut<'cx, 'gcx, 'tcx>(
     tcx: ty::TyCtxt<'cx, 'gcx, 'tcx>,
-    pattern_span: Span,
-) -> Option<(Span, String)> {
-    let hi_src = tcx.sess.codemap().span_to_snippet(pattern_span).unwrap();
+    binding_span: Span,
+) -> Option<(String)> {
+    let hi_src = tcx.sess.codemap().span_to_snippet(binding_span).unwrap();
     if hi_src.starts_with("ref")
         && hi_src["ref".len()..].starts_with(Pattern_White_Space)
     {
         let replacement = format!("ref mut{}", &hi_src["ref".len()..]);
-        Some((pattern_span, replacement))
+        Some(replacement)
     } else {
         None
     }
diff --git a/src/librustc_target/spec/aarch64_pc_windows_msvc.rs b/src/librustc_target/spec/aarch64_pc_windows_msvc.rs
new file mode 100644 (file)
index 0000000..8747f23
--- /dev/null
@@ -0,0 +1,35 @@
+// 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.
+
+use spec::{LinkerFlavor, Target, TargetResult, PanicStrategy, LldFlavor};
+
+pub fn target() -> TargetResult {
+    let mut base = super::windows_msvc_base::opts();
+    base.max_atomic_width = Some(64);
+    base.has_elf_tls = true;
+
+    // FIXME: this shouldn't be panic=abort, it should be panic=unwind
+    base.panic_strategy = PanicStrategy::Abort;
+    base.linker = Some("rust-lld".to_owned());
+
+    Ok(Target {
+        llvm_target: "aarch64-pc-windows-msvc".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "64".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".to_string(),
+        arch: "aarch64".to_string(),
+        target_os: "windows".to_string(),
+        target_env: "msvc".to_string(),
+        target_vendor: "pc".to_string(),
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Link),
+        options: base,
+    })
+}
index d55762e03eee3d3e3a40a8ded6e9c1f060a6ea2d..3a18c56f4fc5960f1accb22743d6c25fe896869b 100644 (file)
@@ -355,6 +355,7 @@ fn $module() {
     ("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu),
     ("i686-pc-windows-gnu", i686_pc_windows_gnu),
 
+    ("aarch64-pc-windows-msvc", aarch64_pc_windows_msvc),
     ("x86_64-pc-windows-msvc", x86_64_pc_windows_msvc),
     ("i686-pc-windows-msvc", i686_pc_windows_msvc),
     ("i586-pc-windows-msvc", i586_pc_windows_msvc),
index e20904930792e76b00297969de45a8b43d7dc273..6e0c0bac186f4a652fddfb7c78851ea5d805006b 100644 (file)
@@ -167,7 +167,13 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
 
         let scope = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
 
-        let ty = self.fcx.tables.borrow().expr_ty_adjusted(expr);
+        // Record the unadjusted type
+        let ty = self.fcx.tables.borrow().expr_ty(expr);
         self.record(ty, scope, Some(expr), expr.span);
+
+        // Also include the adjusted types, since these can result in MIR locals
+        for adjustment in self.fcx.tables.borrow().expr_adjustments(expr) {
+            self.record(adjustment.target, scope, Some(expr), expr.span);
+        }
     }
 }
index 38743cc9cf65f4d8bfdbaa529567a3a0cae4d02c..4b609779540f02f674e9645dab463195e7e4874e 100644 (file)
@@ -258,25 +258,35 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     ty.needs_drop(fcx_tcx, fcx_tcx.param_env(def_id))
                 }
             };
-            let unsized_len = if
+            let all_sized =
                 all_sized ||
                 variant.fields.is_empty() ||
-                needs_drop_copy()
-            {
+                needs_drop_copy();
+            let unsized_len = if all_sized {
                 0
             } else {
                 1
             };
-            for field in &variant.fields[..variant.fields.len() - unsized_len] {
+            for (idx, field) in variant.fields[..variant.fields.len() - unsized_len]
+                .iter()
+                .enumerate()
+            {
+                let last = idx == variant.fields.len() - 1;
                 fcx.register_bound(
                     field.ty,
                     fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem),
-                    traits::ObligationCause::new(field.span,
-                                                    fcx.body_id,
-                                                    traits::FieldSized(match item.node.adt_kind() {
-                                                    Some(i) => i,
-                                                    None => bug!(),
-                                                    })));
+                    traits::ObligationCause::new(
+                        field.span,
+                        fcx.body_id,
+                        traits::FieldSized {
+                            adt_kind: match item.node.adt_kind() {
+                                Some(i) => i,
+                                None => bug!(),
+                            },
+                            last
+                        }
+                    )
+                );
             }
 
             // All field types must be well-formed.
index f0c40d1d491e21835828b5ecf4a671d91c729de1..e163fc68cbda73b4d20917f0fb9086be1eb4554d 100644 (file)
@@ -9,5 +9,5 @@ path = "lib.rs"
 
 [dependencies]
 pulldown-cmark = { version = "0.1.2", default-features = false }
-minifier = "0.0.14"
+minifier = "0.0.19"
 tempfile = "3"
index a2cb79582a14c94cd6aa5da7335ce5a4ee054dc5..2ed7f7a926a4808a02843d7bbc87d6cff5073f7c 100644 (file)
@@ -165,8 +165,8 @@ a {
        color: #ddd;
 }
 
-.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow), .docblock-short
-a:not(.srclink):not(.test-arrow), .stability a {
+.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),
+.docblock-short a:not(.srclink):not(.test-arrow), .stability a {
        color: #D2991D;
 }
 
index 6a3c1988977e7a66c87705316fec21eda58a16c6..f7cb51163ecfc2153f861b1e61aa3e1ad0ef8369 100644 (file)
@@ -165,8 +165,8 @@ a {
        color: #000;
 }
 
-.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow), .docblock-short
-a:not(.srclink):not(.test-arrow), .stability a {
+.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),
+.docblock-short a:not(.srclink):not(.test-arrow), .stability a {
        color: #3873AD;
 }
 
index 0361718eb7337d9fb9003605b4bdbaa6dc116189..35ef6327de5fd81f73c63b2092cf79fc6da36745 100644 (file)
@@ -365,6 +365,9 @@ fn description(&self) -> &str { "encoder error" }
 }
 
 impl From<fmt::Error> for EncoderError {
+    /// Converts a [`fmt::Error`] into `EncoderError`
+    ///
+    /// This conversion does not allocate memory.
     fn from(err: fmt::Error) -> EncoderError { EncoderError::FmtError(err) }
 }
 
@@ -1387,10 +1390,9 @@ fn pop(&mut self) {
 
     // Used by Parser to test whether the top-most element is an index.
     fn last_is_index(&self) -> bool {
-        if let Some(InternalIndex(_)) = self.stack.last() {
-            true
-        } else {
-            false
+        match self.stack.last() {
+            Some(InternalIndex(_)) => true,
+            _ => false,
         }
     }
 
index 02a96b01cca28e82ba75d962d6922baa44b3dfca..59cf741487e443710cdd1e32222abe4cf8a7c92b 100644 (file)
@@ -1247,6 +1247,34 @@ pub fn recv(&self) -> Result<T, RecvError> {
     /// [`SyncSender`]: struct.SyncSender.html
     /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err
     ///
+    /// # Known Issues
+    ///
+    /// There is currently a known issue (see [`#39364`]) that causes `recv_timeout`
+    /// to panic unexpectedly with the following example:
+    ///
+    /// ```no_run
+    /// use std::sync::mpsc::channel;
+    /// use std::thread;
+    /// use std::time::Duration;
+    ///
+    /// let (tx, rx) = channel::<String>();
+    ///
+    /// thread::spawn(move || {
+    ///     let d = Duration::from_millis(10);
+    ///     loop {
+    ///         println!("recv");
+    ///         let _r = rx.recv_timeout(d);
+    ///     }
+    /// });
+    ///
+    /// thread::sleep(Duration::from_millis(100));
+    /// let _c1 = tx.clone();
+    ///
+    /// thread::sleep(Duration::from_secs(1));
+    /// ```
+    ///
+    /// [`#39364`]: https://github.com/rust-lang/rust/issues/39364
+    ///
     /// # Examples
     ///
     /// Successfully receiving value before encountering timeout:
index 7ef4e203571b28e6624138655fd58252de1bb403..f64cae810b9ac76bf5a54b317e1bf0df1a6b9b1e 100644 (file)
@@ -229,6 +229,7 @@ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
         self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
         c::IMAGE_FILE_MACHINE_I386
     }
+
     #[cfg(target_arch = "x86_64")]
     fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
         self.AddrPC.Offset = ctx.Rip as u64;
@@ -240,6 +241,17 @@ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
         c::IMAGE_FILE_MACHINE_AMD64
     }
 
+    #[cfg(target_arch = "aarch64")]
+    fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+        self.AddrPC.Offset = ctx.Pc as u64;
+        self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrStack.Offset = ctx.Sp as u64;
+        self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrFrame.Offset = ctx.Fp as u64;
+        self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        c::IMAGE_FILE_MACHINE_ARM64
+    }
+
     fn get_addr(&self) -> *const u8 {
         (self.AddrPC.Offset - 1) as *const u8
     }
@@ -260,6 +272,7 @@ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
         self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
         c::IMAGE_FILE_MACHINE_I386
     }
+
     #[cfg(target_arch = "x86_64")]
     fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
         self.AddrPC.Offset = ctx.Rip as u64;
@@ -271,6 +284,17 @@ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
         c::IMAGE_FILE_MACHINE_AMD64
     }
 
+    #[cfg(target_arch = "aarch64")]
+    fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+        self.AddrPC.Offset = ctx.Pc as u64;
+        self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrStack.Offset = ctx.Sp as u64;
+        self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        self.AddrFrame.Offset = ctx.Fp as u64;
+        self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+        c::IMAGE_FILE_MACHINE_ARM64
+    }
+
     fn get_addr(&self) -> *const u8 {
         (self.AddrPC.Offset - 1) as *const u8
     }
index 6f81afe66f95b694ae1123d9da74bfd501103a43..e514a56dcc43681dcb3fd8875e0b900402fa3d9f 100644 (file)
@@ -280,6 +280,9 @@ pub struct ipv6_mreq {
 #[cfg(target_arch = "x86_64")]
 #[cfg(feature = "backtrace")]
 pub const IMAGE_FILE_MACHINE_AMD64: DWORD = 0x8664;
+#[cfg(target_arch = "aarch64")]
+#[cfg(feature = "backtrace")]
+pub const IMAGE_FILE_MACHINE_ARM64: DWORD = 0xAA64;
 
 pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
 pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
@@ -791,9 +794,68 @@ pub struct FLOATING_SAVE_AREA {
 // will not appear in the final documentation. This should be also defined for
 // other architectures supported by Windows such as ARM, and for historical
 // interest, maybe MIPS and PowerPC as well.
-#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86"))))]
+#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))))]
 pub enum CONTEXT {}
 
+#[cfg(target_arch = "aarch64")]
+pub const ARM64_MAX_BREAKPOINTS: usize = 8;
+
+#[cfg(target_arch = "aarch64")]
+pub const ARM64_MAX_WATCHPOINTS: usize = 2;
+
+#[cfg(target_arch = "aarch64")]
+#[repr(C)]
+pub struct ARM64_NT_NEON128 {
+    pub D: [f64; 2],
+}
+
+#[cfg(target_arch = "aarch64")]
+#[repr(C, align(16))]
+pub struct CONTEXT {
+    pub ContextFlags: DWORD,
+    pub Cpsr: DWORD,
+    pub X0: u64,
+    pub X1: u64,
+    pub X2: u64,
+    pub X3: u64,
+    pub X4: u64,
+    pub X5: u64,
+    pub X6: u64,
+    pub X7: u64,
+    pub X8: u64,
+    pub X9: u64,
+    pub X10: u64,
+    pub X11: u64,
+    pub X12: u64,
+    pub X13: u64,
+    pub X14: u64,
+    pub X15: u64,
+    pub X16: u64,
+    pub X17: u64,
+    pub X18: u64,
+    pub X19: u64,
+    pub X20: u64,
+    pub X21: u64,
+    pub X22: u64,
+    pub X23: u64,
+    pub X24: u64,
+    pub X25: u64,
+    pub X26: u64,
+    pub X27: u64,
+    pub X28: u64,
+    pub Fp: u64,
+    pub Lr: u64,
+    pub Sp: u64,
+    pub Pc: u64,
+    pub V: [ARM64_NT_NEON128; 32],
+    pub Fpcr: DWORD,
+    pub Fpsr: DWORD,
+    pub Bcr: [DWORD; ARM64_MAX_BREAKPOINTS],
+    pub Bvr: [DWORD; ARM64_MAX_BREAKPOINTS],
+    pub Wcr: [DWORD; ARM64_MAX_WATCHPOINTS],
+    pub Wvr: [DWORD; ARM64_MAX_WATCHPOINTS],
+}
+
 #[repr(C)]
 pub struct SOCKADDR_STORAGE_LH {
     pub ss_family: ADDRESS_FAMILY,
index 0d12ecf8fe3a1e12024088e54e202da0c2c8bd41..ccf79de909fa9dd4ca6b51ecafa0f53dce4e8918 100644 (file)
@@ -266,8 +266,12 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD {
 // handlers.
 //
 // https://msdn.microsoft.com/en-us/library/dn774154.aspx
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+#[allow(unreachable_code)]
 pub unsafe fn abort_internal() -> ! {
-    asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
-    ::intrinsics::unreachable();
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    {
+        asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
+        ::intrinsics::unreachable();
+    }
+    ::intrinsics::abort();
 }
index 879f555ba03ee958d6961f122b7b1c3e759eac75..5857bd282f0bc6823cb9a2505117b96594eaa089 100644 (file)
@@ -607,7 +607,7 @@ fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItemKind>
 }
 
 impl Lit {
-    fn tokens(&self) -> TokenStream {
+    crate fn tokens(&self) -> TokenStream {
         TokenTree::Token(self.span, self.node.token()).into()
     }
 }
@@ -794,7 +794,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -
         );
 
         let start_span = parser.span;
-        let (path, tokens) = panictry!(parser.parse_path_and_tokens());
+        let (path, tokens) = panictry!(parser.parse_meta_item_unrestricted());
         let end_span = parser.span;
         if parser.token != token::Eof {
             parse_sess.span_diagnostic
index 4fe78bf829a1ca732332530dbb2ad64f82e0b1ae..b4e35a9d56496371ed32ccd82ec9ef294f74ac93 100644 (file)
@@ -90,7 +90,7 @@ fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
             let cfg = parser.parse_meta_item()?;
             parser.expect(&token::Comma)?;
             let lo = parser.span.lo();
-            let (path, tokens) = parser.parse_path_and_tokens()?;
+            let (path, tokens) = parser.parse_meta_item_unrestricted()?;
             parser.expect(&token::CloseDelim(token::Paren))?;
             Ok((cfg, path, tokens, parser.prev_span.with_lo(lo)))
         }) {
index 98fbbe4bdef0c2759e2b464afe4519b7da023855..395e5c98652326091ed5ce6f79d573698426722c 100644 (file)
@@ -1526,27 +1526,29 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) {
             }
         }
 
-        match attr.parse_meta(self.context.parse_sess) {
-            Ok(meta) => {
-                // allow attr_literals in #[repr(align(x))] and #[repr(packed(n))]
-                let mut allow_attr_literal = false;
-                if attr.path == "repr" {
-                    if let Some(content) = meta.meta_item_list() {
-                        allow_attr_literal = content.iter().any(
-                            |c| c.check_name("align") || c.check_name("packed"));
+        if !self.context.features.unrestricted_attribute_tokens {
+            // Unfortunately, `parse_meta` cannot be called speculatively because it can report
+            // errors by itself, so we have to call it only if the feature is disabled.
+            match attr.parse_meta(self.context.parse_sess) {
+                Ok(meta) => {
+                    // allow attr_literals in #[repr(align(x))] and #[repr(packed(n))]
+                    let mut allow_attr_literal = false;
+                    if attr.path == "repr" {
+                        if let Some(content) = meta.meta_item_list() {
+                            allow_attr_literal = content.iter().any(
+                                |c| c.check_name("align") || c.check_name("packed"));
+                        }
                     }
-                }
 
-                if !allow_attr_literal && contains_novel_literal(&meta) {
-                    gate_feature_post!(&self, attr_literals, attr.span,
-                                    "non-string literals in attributes, or string \
-                                    literals in top-level positions, are experimental");
+                    if !allow_attr_literal && contains_novel_literal(&meta) {
+                        gate_feature_post!(&self, attr_literals, attr.span,
+                                        "non-string literals in attributes, or string \
+                                        literals in top-level positions, are experimental");
+                    }
+                }
+                Err(mut err) => {
+                    err.help("try enabling `#![feature(unrestricted_attribute_tokens)]`").emit()
                 }
-            }
-            Err(mut err) => {
-                err.cancel();
-                gate_feature_post!(&self, unrestricted_attribute_tokens, attr.span,
-                                    "arbitrary tokens in non-macro attributes are unstable");
             }
         }
     }
index 4d59f64bb6b57d3572ff704a196383fecb757508..b0136c3e18b468a5f05e835068c99e3f11f5629d 100644 (file)
@@ -12,9 +12,9 @@
 use ast;
 use codemap::respan;
 use parse::{SeqSep, PResult};
-use parse::token::{self, Nonterminal};
+use parse::token::{self, Nonterminal, DelimToken};
 use parse::parser::{Parser, TokenType, PathStyle};
-use tokenstream::TokenStream;
+use tokenstream::{TokenStream, TokenTree};
 
 #[derive(Debug)]
 enum InnerAttributeParsePolicy<'a> {
@@ -116,7 +116,7 @@ fn parse_attribute_with_inner_parse_policy(&mut self,
                 };
 
                 self.expect(&token::OpenDelim(token::Bracket))?;
-                let (path, tokens) = self.parse_path_and_tokens()?;
+                let (path, tokens) = self.parse_meta_item_unrestricted()?;
                 self.expect(&token::CloseDelim(token::Bracket))?;
                 let hi = self.prev_span;
 
@@ -138,7 +138,16 @@ fn parse_attribute_with_inner_parse_policy(&mut self,
         })
     }
 
-    crate fn parse_path_and_tokens(&mut self) -> PResult<'a, (ast::Path, TokenStream)> {
+    /// Parse an inner part of attribute - path and following tokens.
+    /// The tokens must be either a delimited token stream, or empty token stream,
+    /// or the "legacy" key-value form.
+    /// PATH `(` TOKEN_STREAM `)`
+    /// PATH `[` TOKEN_STREAM `]`
+    /// PATH `{` TOKEN_STREAM `}`
+    /// PATH
+    /// PATH `=` TOKEN_TREE
+    /// The delimiters or `=` are still put into the resulting token stream.
+    crate fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenStream)> {
         let meta = match self.token {
             token::Interpolated(ref nt) => match nt.0 {
                 Nonterminal::NtMeta(ref meta) => Some(meta.clone()),
@@ -150,7 +159,22 @@ fn parse_attribute_with_inner_parse_policy(&mut self,
             self.bump();
             (meta.ident, meta.node.tokens(meta.span))
         } else {
-            (self.parse_path(PathStyle::Mod)?, self.parse_tokens())
+            let path = self.parse_path(PathStyle::Mod)?;
+            let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) ||
+               self.check(&token::OpenDelim(DelimToken::Bracket)) ||
+               self.check(&token::OpenDelim(DelimToken::Brace)) {
+                   self.parse_token_tree().into()
+            } else if self.eat(&token::Eq) {
+                let eq = TokenTree::Token(self.prev_span, token::Eq);
+                let tree = match self.token {
+                    token::CloseDelim(_) | token::Eof => self.unexpected()?,
+                    _ => self.parse_token_tree(),
+                };
+                TokenStream::concat(vec![eq.into(), tree.into()])
+            } else {
+                TokenStream::empty()
+            };
+            (path, tokens)
         })
     }
 
index 20a585b6601a51da4b3cf4f273991efc37958200..2c53dbdc402a5b2c415919adb12382a10d9efd5e 100644 (file)
@@ -63,6 +63,7 @@ fn vertical_trim(lines: Vec<String>) -> Vec<String> {
         if !lines.is_empty() && lines[0].chars().all(|c| c == '*') {
             i += 1;
         }
+
         while i < j && lines[i].trim().is_empty() {
             i += 1;
         }
@@ -74,9 +75,11 @@ fn vertical_trim(lines: Vec<String>) -> Vec<String> {
                .all(|c| c == '*') {
             j -= 1;
         }
+
         while j > i && lines[j - 1].trim().is_empty() {
             j -= 1;
         }
+
         lines[i..j].to_vec()
     }
 
@@ -85,6 +88,7 @@ fn horizontal_trim(lines: Vec<String>) -> Vec<String> {
         let mut i = usize::MAX;
         let mut can_trim = true;
         let mut first = true;
+
         for line in &lines {
             for (j, c) in line.chars().enumerate() {
                 if j > i || !"* \t".contains(c) {
@@ -119,7 +123,8 @@ fn horizontal_trim(lines: Vec<String>) -> Vec<String> {
     }
 
     // one-line comments lose their prefix
-    const ONELINERS: &'static [&'static str] = &["///!", "///", "//!", "//"];
+    const ONELINERS: &[&str] = &["///!", "///", "//!", "//"];
+
     for prefix in ONELINERS {
         if comment.starts_with(*prefix) {
             return (&comment[prefix.len()..]).to_string();
@@ -205,6 +210,7 @@ fn all_whitespace(s: &str, col: CharPos) -> Option<usize> {
     let len = s.len();
     let mut col = col.to_usize();
     let mut cursor: usize = 0;
+
     while col > 0 && cursor < len {
         let ch = char_at(s, cursor);
         if !ch.is_whitespace() {
@@ -213,7 +219,8 @@ fn all_whitespace(s: &str, col: CharPos) -> Option<usize> {
         cursor += ch.len_utf8();
         col -= 1;
     }
-    return Some(cursor);
+
+    Some(cursor)
 }
 
 fn trim_whitespace_prefix_and_push_line(lines: &mut Vec<String>, s: String, col: CharPos) {
@@ -246,11 +253,13 @@ fn read_block_comment(rdr: &mut StringReader,
         "src_index={}, end_src_index={}, line_begin_pos={}",
         src_index, end_src_index, rdr.filemap.line_begin_pos(rdr.pos).to_u32());
     let mut n = 0;
+
     while src_index < end_src_index {
         let c = char_at(&rdr.src, src_index);
         src_index += c.len_utf8();
         n += 1;
     }
+
     let col = CharPos(n);
 
     rdr.bump();
@@ -358,10 +367,10 @@ pub struct Literal {
 // it appears this function is called only from pprust... that's
 // probably not a good thing.
 pub fn gather_comments_and_literals(sess: &ParseSess, path: FileName, srdr: &mut dyn Read)
-                                    -> (Vec<Comment>, Vec<Literal>) {
-    let mut src = Vec::new();
-    srdr.read_to_end(&mut src).unwrap();
-    let src = String::from_utf8(src).unwrap();
+    -> (Vec<Comment>, Vec<Literal>)
+{
+    let mut src = String::new();
+    srdr.read_to_string(&mut src).unwrap();
     let cm = CodeMap::new(sess.codemap().path_mapping().clone());
     let filemap = cm.new_filemap(path, src);
     let mut rdr = lexer::StringReader::new_raw(sess, filemap, None);
@@ -370,6 +379,7 @@ pub fn gather_comments_and_literals(sess: &ParseSess, path: FileName, srdr: &mut
     let mut literals: Vec<Literal> = Vec::new();
     let mut code_to_the_left = false; // Only code
     let mut anything_to_the_left = false; // Code or comments
+
     while !rdr.is_eof() {
         loop {
             // Eat all the whitespace and count blank lines.
index f9b9e95ead1b6a389e2d488cf9f9530cdd67216e..5913c63bfaa5f6f238c0bbff004d3685deb98a6d 100644 (file)
@@ -73,23 +73,23 @@ impl<'a> StringReader<'a> {
     fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span {
         self.mk_sp_and_raw(lo, hi).0
     }
+
     fn mk_sp_and_raw(&self, lo: BytePos, hi: BytePos) -> (Span, Span) {
         let raw = Span::new(lo, hi, NO_EXPANSION);
-        let real = unwrap_or!(self.override_span, raw);
+        let real = self.override_span.unwrap_or(raw);
+
         (real, raw)
     }
+
     fn mk_ident(&self, string: &str) -> Ident {
         let mut ident = Ident::from_str(string);
         if let Some(span) = self.override_span {
             ident.span = span;
         }
+
         ident
     }
 
-    fn next_token(&mut self) -> TokenAndSpan where Self: Sized {
-        let res = self.try_next_token();
-        self.unwrap_or_abort(res)
-    }
     fn unwrap_or_abort(&mut self, res: Result<TokenAndSpan, ()>) -> TokenAndSpan {
         match res {
             Ok(tok) => tok,
@@ -99,6 +99,25 @@ fn unwrap_or_abort(&mut self, res: Result<TokenAndSpan, ()>) -> TokenAndSpan {
             }
         }
     }
+
+    fn next_token(&mut self) -> TokenAndSpan where Self: Sized {
+        let res = self.try_next_token();
+        self.unwrap_or_abort(res)
+    }
+
+    /// Return the next token. EFFECT: advances the string_reader.
+    pub fn try_next_token(&mut self) -> Result<TokenAndSpan, ()> {
+        assert!(self.fatal_errs.is_empty());
+        let ret_val = TokenAndSpan {
+            tok: replace(&mut self.peek_tok, token::Whitespace),
+            sp: self.peek_span,
+        };
+        self.advance_token()?;
+        self.span_src_raw = self.peek_span_src_raw;
+
+        Ok(ret_val)
+    }
+
     fn try_real_token(&mut self) -> Result<TokenAndSpan, ()> {
         let mut t = self.try_next_token()?;
         loop {
@@ -109,36 +128,32 @@ fn try_real_token(&mut self) -> Result<TokenAndSpan, ()> {
                 _ => break,
             }
         }
+
         self.token = t.tok.clone();
         self.span = t.sp;
+
         Ok(t)
     }
+
     pub fn real_token(&mut self) -> TokenAndSpan {
         let res = self.try_real_token();
         self.unwrap_or_abort(res)
     }
+
+    #[inline]
     fn is_eof(&self) -> bool {
         self.ch.is_none()
     }
-    /// Return the next token. EFFECT: advances the string_reader.
-    pub fn try_next_token(&mut self) -> Result<TokenAndSpan, ()> {
-        assert!(self.fatal_errs.is_empty());
-        let ret_val = TokenAndSpan {
-            tok: replace(&mut self.peek_tok, token::Whitespace),
-            sp: self.peek_span,
-        };
-        self.advance_token()?;
-        self.span_src_raw = self.peek_span_src_raw;
-        Ok(ret_val)
-    }
 
     fn fail_unterminated_raw_string(&self, pos: BytePos, hash_count: u16) {
         let mut err = self.struct_span_fatal(pos, pos, "unterminated raw string");
         err.span_label(self.mk_sp(pos, pos), "unterminated raw string");
+
         if hash_count > 0 {
             err.note(&format!("this raw string should be terminated with `\"{}`",
                               "#".repeat(hash_count as usize)));
         }
+
         err.emit();
         FatalError.raise();
     }
@@ -146,12 +161,15 @@ fn fail_unterminated_raw_string(&self, pos: BytePos, hash_count: u16) {
     fn fatal(&self, m: &str) -> FatalError {
         self.fatal_span(self.peek_span, m)
     }
+
     pub fn emit_fatal_errors(&mut self) {
         for err in &mut self.fatal_errs {
             err.emit();
         }
+
         self.fatal_errs.clear();
     }
+
     pub fn peek(&self) -> TokenAndSpan {
         // FIXME(pcwalton): Bad copy!
         TokenAndSpan {
@@ -161,15 +179,18 @@ pub fn peek(&self) -> TokenAndSpan {
     }
 
     /// For comments.rs, which hackily pokes into next_pos and ch
-    fn new_raw(sess: &'a ParseSess, filemap: Lrc<syntax_pos::FileMap>,
-                   override_span: Option<Span>) -> Self {
+    fn new_raw(sess: &'a ParseSess, filemap: Lrc<syntax_pos::FileMap>, override_span: Option<Span>)
+        -> Self
+    {
         let mut sr = StringReader::new_raw_internal(sess, filemap, override_span);
         sr.bump();
+
         sr
     }
 
     fn new_raw_internal(sess: &'a ParseSess, filemap: Lrc<syntax_pos::FileMap>,
-                        override_span: Option<Span>) -> Self {
+        override_span: Option<Span>) -> Self
+    {
         if filemap.src.is_none() {
             sess.span_diagnostic.bug(&format!("Cannot lex filemap without source: {}",
                                               filemap.name));
@@ -199,12 +220,14 @@ fn new_raw_internal(sess: &'a ParseSess, filemap: Lrc<syntax_pos::FileMap>,
     }
 
     pub fn new(sess: &'a ParseSess, filemap: Lrc<syntax_pos::FileMap>, override_span: Option<Span>)
-               -> Self {
+        -> Self
+    {
         let mut sr = StringReader::new_raw(sess, filemap, override_span);
         if sr.advance_token().is_err() {
             sr.emit_fatal_errors();
             FatalError.raise();
         }
+
         sr
     }
 
@@ -229,9 +252,11 @@ pub fn retokenize(sess: &'a ParseSess, mut span: Span) -> Self {
             sr.emit_fatal_errors();
             FatalError.raise();
         }
+
         sr
     }
 
+    #[inline]
     fn ch_is(&self, c: char) -> bool {
         self.ch == Some(c)
     }
@@ -276,26 +301,23 @@ fn fatal_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char)
         let mut m = m.to_string();
         m.push_str(": ");
         Self::push_escaped_char_for_msg(&mut m, c);
+
         self.fatal_span_(from_pos, to_pos, &m[..])
     }
 
-    fn struct_span_fatal(&self,
-                         from_pos: BytePos,
-                         to_pos: BytePos,
-                         m: &str)
-                         -> DiagnosticBuilder<'a> {
+    fn struct_span_fatal(&self, from_pos: BytePos, to_pos: BytePos, m: &str)
+        -> DiagnosticBuilder<'a>
+    {
         self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), m)
     }
 
-    fn struct_fatal_span_char(&self,
-                              from_pos: BytePos,
-                              to_pos: BytePos,
-                              m: &str,
-                              c: char)
-                              -> DiagnosticBuilder<'a> {
+    fn struct_fatal_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char)
+        -> DiagnosticBuilder<'a>
+    {
         let mut m = m.to_string();
         m.push_str(": ");
         Self::push_escaped_char_for_msg(&mut m, c);
+
         self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), &m[..])
     }
 
@@ -307,15 +329,14 @@ fn err_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) {
         Self::push_escaped_char_for_msg(&mut m, c);
         self.err_span_(from_pos, to_pos, &m[..]);
     }
-    fn struct_err_span_char(&self,
-                            from_pos: BytePos,
-                            to_pos: BytePos,
-                            m: &str,
-                            c: char)
-                            -> DiagnosticBuilder<'a> {
+
+    fn struct_err_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char)
+        -> DiagnosticBuilder<'a>
+    {
         let mut m = m.to_string();
         m.push_str(": ");
         Self::push_escaped_char_for_msg(&mut m, c);
+
         self.sess.span_diagnostic.struct_span_err(self.mk_sp(from_pos, to_pos), &m[..])
     }
 
@@ -324,6 +345,7 @@ fn struct_err_span_char(&self,
     fn fatal_span_verbose(&self, from_pos: BytePos, to_pos: BytePos, mut m: String) -> FatalError {
         m.push_str(": ");
         m.push_str(&self.src[self.src_index(from_pos)..self.src_index(to_pos)]);
+
         self.fatal_span_(from_pos, to_pos, &m[..])
     }
 
@@ -354,6 +376,7 @@ fn advance_token(&mut self) -> Result<(), ()> {
                 };
             }
         }
+
         Ok(())
     }
 
@@ -468,6 +491,7 @@ fn nextch(&self) -> Option<char> {
         }
     }
 
+    #[inline]
     fn nextch_is(&self, c: char) -> bool {
         self.nextch() == Some(c)
     }
@@ -484,6 +508,7 @@ fn nextnextch(&self) -> Option<char> {
         None
     }
 
+    #[inline]
     fn nextnextch_is(&self, c: char) -> bool {
         self.nextnextch() == Some(c)
     }
@@ -493,8 +518,10 @@ fn scan_optional_raw_name(&mut self) -> Option<ast::Name> {
         if !ident_start(self.ch) {
             return None;
         }
+
         let start = self.pos;
         self.bump();
+
         while ident_continue(self.ch) {
             self.bump();
         }
@@ -709,6 +736,7 @@ fn scan_block_comment(&mut self) -> Option<TokenAndSpan> {
     fn scan_digits(&mut self, real_radix: u32, scan_radix: u32) -> usize {
         assert!(real_radix <= scan_radix);
         let mut len = 0;
+
         loop {
             let c = self.ch;
             if c == Some('_') {
@@ -736,31 +764,29 @@ fn scan_digits(&mut self, real_radix: u32, scan_radix: u32) -> usize {
 
     /// Lex a LIT_INTEGER or a LIT_FLOAT
     fn scan_number(&mut self, c: char) -> token::Lit {
-        let num_digits;
         let mut base = 10;
         let start_bpos = self.pos;
-
         self.bump();
 
-        if c == '0' {
+        let num_digits = if c == '0' {
             match self.ch.unwrap_or('\0') {
                 'b' => {
                     self.bump();
                     base = 2;
-                    num_digits = self.scan_digits(2, 10);
+                    self.scan_digits(2, 10)
                 }
                 'o' => {
                     self.bump();
                     base = 8;
-                    num_digits = self.scan_digits(8, 10);
+                    self.scan_digits(8, 10)
                 }
                 'x' => {
                     self.bump();
                     base = 16;
-                    num_digits = self.scan_digits(16, 16);
+                    self.scan_digits(16, 16)
                 }
                 '0'..='9' | '_' | '.' | 'e' | 'E' => {
-                    num_digits = self.scan_digits(10, 10) + 1;
+                    self.scan_digits(10, 10) + 1
                 }
                 _ => {
                     // just a 0
@@ -768,15 +794,14 @@ fn scan_number(&mut self, c: char) -> token::Lit {
                 }
             }
         } else if c.is_digit(10) {
-            num_digits = self.scan_digits(10, 10) + 1;
+            self.scan_digits(10, 10) + 1
         } else {
-            num_digits = 0;
-        }
+            0
+        };
 
         if num_digits == 0 {
-            self.err_span_(start_bpos,
-                           self.pos,
-                           "no valid digits found for number");
+            self.err_span_(start_bpos, self.pos, "no valid digits found for number");
+
             return token::Integer(Symbol::intern("0"));
         }
 
@@ -794,6 +819,7 @@ fn scan_number(&mut self, c: char) -> token::Lit {
             }
             let pos = self.pos;
             self.check_float_base(start_bpos, pos, base);
+
             token::Float(self.name_from(start_bpos))
         } else {
             // it might be a float if it has an exponent
@@ -873,7 +899,8 @@ fn scan_char_or_byte(&mut self,
                          first_source_char: char,
                          ascii_only: bool,
                          delim: char)
-                         -> bool {
+                         -> bool
+    {
         match first_source_char {
             '\\' => {
                 // '\X' for some X must be a character constant:
@@ -1008,6 +1035,7 @@ fn scan_unicode_escape(&mut self, delim: char) -> bool {
                            "overlong unicode escape (must have at most 6 hex digits)");
             valid = false;
         }
+
         loop {
             match self.ch {
                 Some('}') => {
@@ -1043,6 +1071,7 @@ fn scan_unicode_escape(&mut self, delim: char) -> bool {
             }
             self.bump();
         }
+
         valid
     }
 
@@ -1050,9 +1079,11 @@ fn scan_unicode_escape(&mut self, delim: char) -> bool {
     fn scan_float_exponent(&mut self) {
         if self.ch_is('e') || self.ch_is('E') {
             self.bump();
+
             if self.ch_is('-') || self.ch_is('+') {
                 self.bump();
             }
+
             if self.scan_digits(10, 10) == 0 {
                 let mut err = self.struct_span_fatal(
                     self.pos, self.next_pos,
@@ -1125,6 +1156,7 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                     ('b', Some('r'), Some('#')) => (false, false),
                     _ => (true, false),
                 };
+
             if is_ident_start {
                 let raw_start = self.pos;
                 if is_raw_ident {
@@ -1135,6 +1167,7 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
 
                 let start = self.pos;
                 self.bump();
+
                 while ident_continue(self.ch) {
                     self.bump();
                 }
@@ -1142,16 +1175,19 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                 return Ok(self.with_str_from(start, |string| {
                     // FIXME: perform NFKC normalization here. (Issue #2253)
                     let ident = self.mk_ident(string);
+
                     if is_raw_ident && (ident.is_path_segment_keyword() ||
                                         ident.name == keywords::Underscore.name()) {
                         self.fatal_span_(raw_start, self.pos,
                             &format!("`r#{}` is not currently supported.", ident.name)
                         ).raise();
                     }
+
                     if is_raw_ident {
                         let span = self.mk_sp(raw_start, self.pos);
                         self.sess.raw_identifier_spans.borrow_mut().push(span);
                     }
+
                     token::Ident(ident, is_raw_ident)
                 }));
             }
@@ -1337,14 +1373,11 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                     return Ok(token::Lifetime(ident));
                 }
 
-                let valid = self.scan_char_or_byte(start,
-                                                   c2,
-                                                   // ascii_only =
-                                                   false,
-                                                   '\'');
+                let valid = self.scan_char_or_byte(start, c2, /* ascii_only */ false, '\'');
 
                 if !self.ch_is('\'') {
                     let pos = self.pos;
+
                     loop {
                         self.bump();
                         if self.ch_is('\'') {
@@ -1370,6 +1403,7 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                             break;
                         }
                     }
+
                     self.fatal_span_verbose(start_with_quote, pos,
                         String::from("character literal may only contain one codepoint")).raise();
                 }
@@ -1379,8 +1413,10 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                 } else {
                     Symbol::intern("0")
                 };
+
                 self.bump(); // advance ch past token
                 let suffix = self.scan_optional_raw_name();
+
                 Ok(token::Literal(token::Char(id), suffix))
             }
             'b' => {
@@ -1392,12 +1428,14 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                     _ => unreachable!(),  // Should have been a token::Ident above.
                 };
                 let suffix = self.scan_optional_raw_name();
+
                 Ok(token::Literal(lit, suffix))
             }
             '"' => {
                 let start_bpos = self.pos;
                 let mut valid = true;
                 self.bump();
+
                 while !self.ch_is('"') {
                     if self.is_eof() {
                         let last_bpos = self.pos;
@@ -1409,11 +1447,7 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                     let ch_start = self.pos;
                     let ch = self.ch.unwrap();
                     self.bump();
-                    valid &= self.scan_char_or_byte(ch_start,
-                                                    ch,
-                                                    // ascii_only =
-                                                    false,
-                                                    '"');
+                    valid &= self.scan_char_or_byte(ch_start, ch, /* ascii_only */ false, '"');
                 }
                 // adjust for the ASCII " at the start of the literal
                 let id = if valid {
@@ -1423,6 +1457,7 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                 };
                 self.bump();
                 let suffix = self.scan_optional_raw_name();
+
                 Ok(token::Literal(token::Str_(id), suffix))
             }
             'r' => {
@@ -1492,6 +1527,7 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                     }
                     self.bump();
                 }
+
                 self.bump();
                 let id = if valid {
                     self.name_from_to(content_start_bpos, content_end_bpos)
@@ -1499,6 +1535,7 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                     Symbol::intern("??")
                 };
                 let suffix = self.scan_optional_raw_name();
+
                 Ok(token::Literal(token::StrRaw(id, hash_count), suffix))
             }
             '-' => {
@@ -1555,6 +1592,7 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                                                           c);
                 unicode_chars::check_for_substitution(self, c, &mut err);
                 self.fatal_errs.push(err);
+
                 Err(())
             }
         }
@@ -1572,9 +1610,11 @@ fn read_to_eol(&mut self) -> String {
             val.push(self.ch.unwrap());
             self.bump();
         }
+
         if self.ch_is('\n') {
             self.bump();
         }
+
         val
     }
 
@@ -1626,9 +1666,11 @@ fn scan_byte(&mut self) -> token::Lit {
             Symbol::intern("?")
         };
         self.bump(); // advance ch past token
+
         token::Byte(id)
     }
 
+    #[inline]
     fn scan_byte_escape(&mut self, delim: char, below_0x7f_only: bool) -> bool {
         self.scan_hex_digits(2, delim, below_0x7f_only)
     }
@@ -1653,12 +1695,14 @@ fn scan_byte_string(&mut self) -> token::Lit {
                                             true,
                                             '"');
         }
+
         let id = if valid {
             self.name_from(start)
         } else {
             Symbol::intern("??")
         };
         self.bump();
+
         token::ByteStr(id)
     }
 
@@ -1716,25 +1760,26 @@ fn scan_raw_byte_string(&mut self) -> token::Lit {
             }
             self.bump();
         }
+
         self.bump();
-        token::ByteStrRaw(self.name_from_to(content_start_bpos, content_end_bpos),
-                                 hash_count)
+
+        token::ByteStrRaw(self.name_from_to(content_start_bpos, content_end_bpos), hash_count)
     }
 }
 
 // This tests the character for the unicode property 'PATTERN_WHITE_SPACE' which
 // is guaranteed to be forward compatible. http://unicode.org/reports/tr31/#R3
+#[inline]
 crate fn is_pattern_whitespace(c: Option<char>) -> bool {
     c.map_or(false, Pattern_White_Space)
 }
 
+#[inline]
 fn in_range(c: Option<char>, lo: char, hi: char) -> bool {
-    match c {
-        Some(c) => lo <= c && c <= hi,
-        _ => false,
-    }
+    c.map_or(false, |c| lo <= c && c <= hi)
 }
 
+#[inline]
 fn is_dec_digit(c: Option<char>) -> bool {
     in_range(c, '0', '9')
 }
index 36c220fa0d943d34f3aa4973c6618008ca4261a8..1e7855e68ddc64efa04f6f738e11ae63e2b06881 100644 (file)
@@ -17,9 +17,11 @@ impl<'a> StringReader<'a> {
     // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`.
     crate fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
         let mut tts = Vec::new();
+
         while self.token != token::Eof {
             tts.push(self.parse_token_tree()?);
         }
+
         Ok(TokenStream::concat(tts))
     }
 
@@ -30,6 +32,7 @@ fn parse_token_trees_until_close_delim(&mut self) -> TokenStream {
             if let token::CloseDelim(..) = self.token {
                 return TokenStream::concat(tts);
             }
+
             match self.parse_token_tree() {
                 Ok(tree) => tts.push(tree),
                 Err(mut e) => {
@@ -48,6 +51,7 @@ fn parse_token_tree(&mut self) -> PResult<'a, TokenStream> {
                 for &(_, sp) in &self.open_braces {
                     err.span_help(sp, "did you mean to close this delimiter?");
                 }
+
                 Err(err)
             },
             token::OpenDelim(delim) => {
@@ -129,6 +133,7 @@ fn parse_token_tree(&mut self) -> PResult<'a, TokenStream> {
                 let raw = self.span_src_raw;
                 self.real_token();
                 let is_joint = raw.hi() == self.span_src_raw.lo() && token::is_op(&self.token);
+
                 Ok(if is_joint { tt.joint() } else { tt.into() })
             }
         }
index a32b515672ecaba229bc572b095fb18801ee66fa..88ff8582da80194ec0c24936970cf8517f9f350b 100644 (file)
@@ -15,7 +15,7 @@
 use errors::DiagnosticBuilder;
 use super::StringReader;
 
-const UNICODE_ARRAY: &'static [(char, &'static str, char)] = &[
+const UNICODE_ARRAY: &[(char, &str, char)] = &[
     ('
', "Line Separator", ' '),
     ('
', "Paragraph Separator", ' '),
     (' ', "Ogham Space mark", ' '),
index 0e45cacaf38c91727ae3227bb5763898eed3ec13..345464c66642570e2e39a6d22358f54192c5b5f8 100644 (file)
@@ -825,7 +825,7 @@ fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> {
     ///
     /// This method will automatically add `tok` to `expected_tokens` if `tok` is not
     /// encountered.
-    fn check(&mut self, tok: &token::Token) -> bool {
+    crate fn check(&mut self, tok: &token::Token) -> bool {
         let is_present = self.token == *tok;
         if !is_present { self.expected_tokens.push(TokenType::Token(tok.clone())); }
         is_present
@@ -4719,7 +4719,12 @@ pub fn parse_block(&mut self) -> PResult<'a, P<Block>> {
         if !self.eat(&token::OpenDelim(token::Brace)) {
             let sp = self.span;
             let tok = self.this_token_to_string();
+            let mut do_not_suggest_help = false;
             let mut e = self.span_fatal(sp, &format!("expected `{{`, found `{}`", tok));
+            if self.token.is_keyword(keywords::In) || self.token == token::Colon {
+                do_not_suggest_help = true;
+                e.span_label(sp, "expected `{`");
+            }
 
             // Check to see if the user has written something like
             //
@@ -4729,7 +4734,8 @@ pub fn parse_block(&mut self) -> PResult<'a, P<Block>> {
             // Which is valid in other languages, but not Rust.
             match self.parse_stmt_without_recovery(false) {
                 Ok(Some(stmt)) => {
-                    if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace)) {
+                    if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace))
+                        || do_not_suggest_help {
                         // if the next token is an open brace (e.g., `if a b {`), the place-
                         // inside-a-block suggestion would be more likely wrong than right
                         return Err(e);
index 30094223d08585c81e7beb4d0d0044acdeb4a615..060ea1ea9b1329634d2ab6281b467c302563a1d9 100644 (file)
@@ -324,7 +324,14 @@ pub fn test_main_static(tests: &[TestDescAndFn]) {
 /// test is considered a failure. By default, invokes `report()`
 /// and checks for a `0` result.
 pub fn assert_test_result<T: Termination>(result: T) {
-    assert_eq!(result.report(), 0);
+    let code = result.report();
+    assert_eq!(
+        code,
+        0,
+        "the test returned a termination value with a non-zero status code ({}) \
+         which indicates a failure",
+        code
+    );
 }
 
 #[derive(Copy, Clone, Debug)]
index 4be2874ed4ff6e3b5e4aee5559b630ac08ce1ff8..baeb019df1ca0491a0c1c531df5788f8aacbb23d 100644 (file)
 #![feature(plugin)]
 #![plugin(macro_crate_test)]
 
-#[noop_attribute"x"] //~ ERROR expected one of
-fn night() { }
-
-#[noop_attribute("hi"), rank = 2] //~ ERROR unexpected token
+#[noop_attribute("hi", rank = a)] //~ ERROR expected unsuffixed literal or identifier, found a
 fn knight() { }
 
 #[noop_attribute("/user", data= = "<user")] //~ ERROR literal or identifier
index 8d53699c0640e0bb2ce3088491c9329cc8d73ce2..df3f7a239b926b9132e752ebe953f35ab49368fe 100644 (file)
@@ -21,7 +21,7 @@
 #[C] //~ ERROR: The attribute `C` is currently unknown to the compiler
 #[B(D)]
 #[B(E = "foo")]
-#[B arbitrary tokens] //~ ERROR arbitrary tokens in non-macro attributes are unstable
+#[B(arbitrary tokens)] //~ ERROR expected one of `(`, `)`, `,`, `::`, or `=`, found `tokens`
 struct B;
 
 fn main() {}
index 9a0171c2ae5ea205296d129bfae6d8c965c104fc..0798aa549f0b2cd4d2a8ac905551509ad165be54 100644 (file)
@@ -41,12 +41,6 @@ mod _test2_inner {
 #[a = y] //~ ERROR: must only be followed by a delimiter token
 fn _test3() {}
 
-#[a = ] //~ ERROR: must only be followed by a delimiter token
-fn _test4() {}
-
-#[a () = ] //~ ERROR: must only be followed by a delimiter token
-fn _test5() {}
-
 fn attrs() {
     // Statement, item
     #[a] // OK
diff --git a/src/test/parse-fail/attr-bad-meta-2.rs b/src/test/parse-fail/attr-bad-meta-2.rs
new file mode 100644 (file)
index 0000000..ce640a3
--- /dev/null
@@ -0,0 +1,12 @@
+// 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.
+
+#[path =] //~ ERROR unexpected token: `]`
+mod m {}
diff --git a/src/test/parse-fail/attr-bad-meta-3.rs b/src/test/parse-fail/attr-bad-meta-3.rs
new file mode 100644 (file)
index 0000000..92e2a59
--- /dev/null
@@ -0,0 +1,12 @@
+// 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.
+
+#[path() token] //~ ERROR expected `]`, found `token`
+mod m {}
index 41db88121cb5292ef9adc410391404a7d7dfcbbc..6f9d794dc2dc302d36eb0f298e1af0652f338344 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// asterisk is bogus
-#[path*] //~ ERROR arbitrary tokens in non-macro attributes are unstable
+#![feature(unrestricted_attribute_tokens)]
+
+#[path*] //~ ERROR expected one of `(`, `::`, `=`, `[`, `]`, or `{`, found `*`
 mod m {}
index 7b521f2b9138a21bb01c40d2ae9ea1d7ff0ebdb5..e1aabad4142f93cae3f0d00698034e7efe1eb09d 100644 (file)
@@ -19,7 +19,7 @@
 #[proc_macro_derive(B, attributes(B, C))]
 pub fn derive(input: TokenStream) -> TokenStream {
     let input = input.to_string();
-    assert!(input.contains("#[B arbitrary tokens]"));
+    assert!(input.contains("#[B [ arbitrary tokens ]]"));
     assert!(input.contains("struct B {"));
     assert!(input.contains("#[C]"));
     "".parse().unwrap()
index 918d2c17123e88b427106040538b454fd8a6b529..1de6496e29f8b22fc6a6d8d92bfd7dbb7208b84c 100644 (file)
@@ -16,7 +16,7 @@
 extern crate derive_b;
 
 #[derive(Debug, PartialEq, derive_b::B, Eq, Copy, Clone)]
-#[cfg_attr(all(), B arbitrary tokens)]
+#[cfg_attr(all(), B[arbitrary tokens])]
 struct B {
     #[C]
     a: u64
diff --git a/src/test/run-pass/generator/issue-52398.rs b/src/test/run-pass/generator/issue-52398.rs
new file mode 100644 (file)
index 0000000..0fb8f27
--- /dev/null
@@ -0,0 +1,35 @@
+// 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.
+
+#![feature(generators)]
+
+use std::cell::RefCell;
+
+struct A;
+
+impl A {
+    fn test(&self, a: ()) {}
+}
+
+fn main() {
+    // Test that the MIR local with type &A created for the auto-borrow adjustment
+    // is caught by typeck
+    move || {
+        A.test(yield);
+    };
+
+    // Test that the std::cell::Ref temporary returned from the `borrow` call
+    // is caught by typeck
+    let y = RefCell::new(true);
+    static move || {
+        yield *y.borrow();
+        return "Done";
+    };
+}
diff --git a/src/test/run-pass/nll/issue-53123-raw-pointer-cast.rs b/src/test/run-pass/nll/issue-53123-raw-pointer-cast.rs
new file mode 100644 (file)
index 0000000..7959f17
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(nll)]
+#![allow(unused_variables)]
+
+pub trait TryTransform {
+    fn try_transform<F>(self, f: F)
+    where
+        Self: Sized,
+        F: FnOnce(Self);
+}
+
+impl<'a, T> TryTransform for &'a mut T {
+    fn try_transform<F>(self, f: F)
+    where
+        // The bug was that `Self: Sized` caused the lifetime of `this` to "extend" for all
+        // of 'a instead of only lasting as long as the binding is used (for just that line).
+        Self: Sized,
+        F: FnOnce(Self),
+    {
+        let this: *mut T = self as *mut T;
+        f(self);
+    }
+}
+
+fn main() {
+}
index e1401653ba356a3330bbbcffabd5ab2ae28168ee..18ca34b117db7a943aa2b5543fd3f39af1e8ba8e 100644 (file)
@@ -17,6 +17,6 @@
 use foo::foo;
 
 #[ foo ( let y: u32 = "z"; ) ] //~ ERROR: mismatched types
-#[ bar let x: u32 = "y"; ] //~ ERROR: mismatched types
+#[ bar { let x: u32 = "y"; } ] //~ ERROR: mismatched types
 fn main() {
 }
index fe62bd23b87c9bc4a6e2421bcdd0a7ac0c205881..a6cbf79209e2e0dccd4ce9bbb221439dd7544276 100644 (file)
@@ -8,10 +8,10 @@ LL | #[ foo ( let y: u32 = "z"; ) ] //~ ERROR: mismatched types
               found type `&'static str`
 
 error[E0308]: mismatched types
-  --> $DIR/attribute-spans-preserved.rs:20:21
+  --> $DIR/attribute-spans-preserved.rs:20:23
    |
-LL | #[ bar let x: u32 = "y"; ] //~ ERROR: mismatched types
-   |                     ^^^ expected u32, found reference
+LL | #[ bar { let x: u32 = "y"; } ] //~ ERROR: mismatched types
+   |                       ^^^ expected u32, found reference
    |
    = note: expected type `u32`
               found type `&'static str`
index 33dc064ef680f313d8bedc215f569f4ecf7cb269..b1487fcd5edbdd7b8db1619f214b78db01b78de0 100644 (file)
@@ -1 +1 @@
-fn main (  ) { let y : u32 = "z" ; let x : u32 = "y" ; }
+fn main (  ) { let y : u32 = "z" ; { let x : u32 = "y" ; } }
diff --git a/src/test/ui/E0508-fail.ast.nll.stderr b/src/test/ui/E0508-fail.ast.nll.stderr
new file mode 100644 (file)
index 0000000..fda6c24
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array
+  --> $DIR/E0508-fail.rs:18:18
+   |
+LL |     let _value = array[0];  //[ast]~ ERROR [E0508]
+   |                  ^^^^^^^^
+   |                  |
+   |                  cannot move out of here
+   |                  help: consider borrowing here: `&array[0]`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0508`.
index faf7411af317b15b2f8faf13cb99ff2a052cd173..fda6c24dc8710a8e5d97bf5bf119d843e95cb793 100644 (file)
@@ -5,7 +5,7 @@ LL |     let _value = array[0];  //[ast]~ ERROR [E0508]
    |                  ^^^^^^^^
    |                  |
    |                  cannot move out of here
-   |                  help: consider using a reference instead: `&array[0]`
+   |                  help: consider borrowing here: `&array[0]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/E0508.nll.stderr b/src/test/ui/E0508.nll.stderr
new file mode 100644 (file)
index 0000000..025ff87
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array
+  --> $DIR/E0508.rs:15:18
+   |
+LL |     let _value = array[0];  //~ ERROR [E0508]
+   |                  ^^^^^^^^
+   |                  |
+   |                  cannot move out of here
+   |                  help: consider borrowing here: `&array[0]`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0508`.
index 2aa8f1c3813090291fbca72df73f78ee8f2f8785..b9de60f43f703f72c82096ffa92e995bea3c211d 100644 (file)
@@ -2,10 +2,16 @@ error[E0507]: cannot move out of borrowed content
   --> $DIR/access-mode-in-closures.rs:19:15
    |
 LL |         match *s { sty(v) => v } //~ ERROR cannot move out
-   |               ^^       - move occurs because v has type `std::vec::Vec<isize>`, which does not implement the `Copy` trait
+   |               ^^       - data moved here
    |               |
    |               cannot move out of borrowed content
-   |               help: consider removing this dereference operator: `s`
+   |               help: consider removing the `*`: `s`
+   |
+note: move occurs because `v` has type `std::vec::Vec<isize>`, which does not implement the `Copy` trait
+  --> $DIR/access-mode-in-closures.rs:19:24
+   |
+LL |         match *s { sty(v) => v } //~ ERROR cannot move out
+   |                        ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/attr-eq-token-tree.rs b/src/test/ui/attr-eq-token-tree.rs
new file mode 100644 (file)
index 0000000..c759e62
--- /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-pass
+
+#![feature(custom_attribute, unrestricted_attribute_tokens)]
+
+#[my_attr = !] // OK under feature gate
+fn main() {}
index f9e517def14060e049e7d8629c1058e35691cc4b..25eb69ad9377dfe21b260a35ad50463847956d75 100644 (file)
@@ -2,28 +2,46 @@ error[E0507]: cannot move out of borrowed content
   --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:22:15
    |
 LL |     for &a in x.iter() {    //~ ERROR cannot move out
-   |          -    ^^^^^^^^ cannot move out of borrowed content
-   |          |
-   |          data moved here
-   |          help: to prevent move, use ref or ref mut: `ref a`
+   |         --    ^^^^^^^^ cannot move out of borrowed content
+   |         ||
+   |         |data moved here
+   |         help: consider removing the `&`: `a`
+   |
+note: move occurs because `a` has type `&mut i32`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:22:10
+   |
+LL |     for &a in x.iter() {    //~ ERROR cannot move out
+   |          ^
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:28:15
    |
 LL |     for &a in &f.a {  //~ ERROR cannot move out
-   |          -    ^^^^ cannot move out of borrowed content
-   |          |
-   |          data moved here
-   |          help: to prevent move, use ref or ref mut: `ref a`
+   |         --    ^^^^ cannot move out of borrowed content
+   |         ||
+   |         |data moved here
+   |         help: consider removing the `&`: `a`
+   |
+note: move occurs because `a` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:28:10
+   |
+LL |     for &a in &f.a {  //~ ERROR cannot move out
+   |          ^
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:32:15
    |
 LL |     for &a in x.iter() {    //~ ERROR cannot move out
-   |          -    ^^^^^^^^ cannot move out of borrowed content
-   |          |
-   |          data moved here
-   |          help: to prevent move, use ref or ref mut: `ref a`
+   |         --    ^^^^^^^^ cannot move out of borrowed content
+   |         ||
+   |         |data moved here
+   |         help: consider removing the `&`: `a`
+   |
+note: move occurs because `a` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:32:10
+   |
+LL |     for &a in x.iter() {    //~ ERROR cannot move out
+   |          ^
 
 error: aborting due to 3 previous errors
 
index 05a022a726cd977b8013c8bfb45b07db329944cd..45fa1764f7027230af918979f7648d00e8a418cb 100644 (file)
@@ -1,6 +1,8 @@
 error[E0507]: cannot move out of captured variable in an `Fn` closure
   --> $DIR/borrowck-in-static.rs:15:17
    |
+LL |     let x = Box::new(0);
+   |         - captured outer variable
 LL |     Box::new(|| x) //~ ERROR cannot move out of captured outer variable
    |                 ^ cannot move out of captured variable in an `Fn` closure
 
index 55c6a40d281bc0c55dc1c9d02b52de582e9c3364..cdbfab8bd054a1903c2d53ce953bc577d7f9faeb 100644 (file)
@@ -5,7 +5,7 @@ LL |         let _b = *y; //~ ERROR cannot move out
    |                  ^^
    |                  |
    |                  cannot move out of borrowed content
-   |                  help: consider removing this dereference operator: `y`
+   |                  help: consider removing the `*`: `y`
 
 error: aborting due to previous error
 
index f5b7ca22278e43444d39349423d0e7f91b5c7092..9f56b26648b2ac9de625c77df93d3b03f0610ff5 100644 (file)
@@ -1,6 +1,9 @@
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
   --> $DIR/borrowck-move-by-capture.rs:19:29
    |
+LL |     let bar: Box<_> = box 3;
+   |         --- captured outer variable
+LL |     let _g = to_fn_mut(|| {
 LL |         let _h = to_fn_once(move || -> isize { *bar }); //~ ERROR cannot move out of
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of captured variable in an `FnMut` closure
 
index 1b913471924b799a19fbcefa11978ce2bef67d0a..2df520a936c9d4a9975563d5eb6221917fda2853 100644 (file)
@@ -5,14 +5,24 @@ LL |     match *f {             //~ ERROR cannot move out of
    |           ^^
    |           |
    |           cannot move out of borrowed content
-   |           help: consider removing this dereference operator: `f`
+   |           help: consider removing the `*`: `f`
 LL |                            //~| cannot move out
 LL |         Foo::Foo1(num1,
-   |                   ---- move occurs because num1 has type `std::boxed::Box<u32>`, which does not implement the `Copy` trait
+   |                   ---- data moved here
 LL |                   num2) => (),
-   |                   ---- move occurs because num2 has type `std::boxed::Box<u32>`, which does not implement the `Copy` trait
+   |                   ---- ...and here
 LL |         Foo::Foo2(num) => (),
-   |                   --- move occurs because num has type `std::boxed::Box<u32>`, which does not implement the `Copy` trait
+   |                   --- ...and here
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/borrowck-move-error-with-note.rs:23:19
+   |
+LL |         Foo::Foo1(num1,
+   |                   ^^^^
+LL |                   num2) => (),
+   |                   ^^^^
+LL |         Foo::Foo2(num) => (),
+   |                   ^^^
 
 error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
   --> $DIR/borrowck-move-error-with-note.rs:39:11
@@ -23,12 +33,15 @@ LL |     match (S {f: "foo".to_string(), g: "bar".to_string()}) {
 LL |             f: _s,
    |                -- data moved here
 LL |             g: _t
-   |                -- ... and here
-help: to prevent move, use ref or ref mut
+   |                -- ...and here
    |
-LL |             f: ref _s,
-LL |             g: ref _t
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/borrowck-move-error-with-note.rs:42:16
    |
+LL |             f: _s,
+   |                ^^
+LL |             g: _t
+   |                ^^
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/borrowck-move-error-with-note.rs:57:11
@@ -37,10 +50,16 @@ LL |     match a.a {           //~ ERROR cannot move out of
    |           ^^^
    |           |
    |           cannot move out of borrowed content
-   |           help: consider using a reference instead: `&a.a`
+   |           help: consider borrowing here: `&a.a`
 LL |                           //~| cannot move out
 LL |         n => {
-   |         - move occurs because n has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+   |         - data moved here
+   |
+note: move occurs because `n` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-error-with-note.rs:59:9
+   |
+LL |         n => {
+   |         ^
 
 error: aborting due to 3 previous errors
 
index 4f692bfc55e427cb92ed903d240d51e4269da96c..f823a6f08d789485e47546b7e9fa34f4ec5f1f34 100644 (file)
@@ -5,7 +5,7 @@ LL |     let y = *x; //~ ERROR cannot move out of dereference of raw pointer
    |             ^^
    |             |
    |             cannot move out of borrowed content
-   |             help: consider using a reference instead: `&*x`
+   |             help: consider removing the `*`: `x`
 
 error: aborting due to previous error
 
index f670936dbac17b7a4bee7dac9c2e38d198641daa..49c2ec0dcf4e7c996e77b3f918f482664288f74f 100644 (file)
@@ -5,8 +5,14 @@ LL | fn arg_item(&_x: &String) {}
    |             ^--
    |             ||
    |             |data moved here
-   |             |help: to prevent move, use ref or ref mut: `ref _x`
    |             cannot move out of borrowed content
+   |             help: consider removing the `&`: `_x`
+   |
+note: move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-in-irrefut-pat.rs:16:14
+   |
+LL | fn arg_item(&_x: &String) {}
+   |              ^^
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/borrowck-move-in-irrefut-pat.rs:21:11
@@ -15,17 +21,29 @@ LL |     with(|&_x| ())
    |           ^--
    |           ||
    |           |data moved here
-   |           |help: to prevent move, use ref or ref mut: `ref _x`
    |           cannot move out of borrowed content
+   |           help: consider removing the `&`: `_x`
+   |
+note: move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-in-irrefut-pat.rs:21:12
+   |
+LL |     with(|&_x| ())
+   |            ^^
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/borrowck-move-in-irrefut-pat.rs:27:15
    |
 LL |     let &_x = &"hi".to_string();
-   |          --   ^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
-   |          |
-   |          data moved here
-   |          help: to prevent move, use ref or ref mut: `ref _x`
+   |         ---   ^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+   |         ||
+   |         |data moved here
+   |         help: consider removing the `&`: `_x`
+   |
+note: move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-in-irrefut-pat.rs:27:10
+   |
+LL |     let &_x = &"hi".to_string();
+   |          ^^
 
 error: aborting due to 3 previous errors
 
index f670936dbac17b7a4bee7dac9c2e38d198641daa..49c2ec0dcf4e7c996e77b3f918f482664288f74f 100644 (file)
@@ -5,8 +5,14 @@ LL | fn arg_item(&_x: &String) {}
    |             ^--
    |             ||
    |             |data moved here
-   |             |help: to prevent move, use ref or ref mut: `ref _x`
    |             cannot move out of borrowed content
+   |             help: consider removing the `&`: `_x`
+   |
+note: move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-in-irrefut-pat.rs:16:14
+   |
+LL | fn arg_item(&_x: &String) {}
+   |              ^^
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/borrowck-move-in-irrefut-pat.rs:21:11
@@ -15,17 +21,29 @@ LL |     with(|&_x| ())
    |           ^--
    |           ||
    |           |data moved here
-   |           |help: to prevent move, use ref or ref mut: `ref _x`
    |           cannot move out of borrowed content
+   |           help: consider removing the `&`: `_x`
+   |
+note: move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-in-irrefut-pat.rs:21:12
+   |
+LL |     with(|&_x| ())
+   |            ^^
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/borrowck-move-in-irrefut-pat.rs:27:15
    |
 LL |     let &_x = &"hi".to_string();
-   |          --   ^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
-   |          |
-   |          data moved here
-   |          help: to prevent move, use ref or ref mut: `ref _x`
+   |         ---   ^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+   |         ||
+   |         |data moved here
+   |         help: consider removing the `&`: `_x`
+   |
+note: move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-in-irrefut-pat.rs:27:10
+   |
+LL |     let &_x = &"hi".to_string();
+   |          ^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.nll.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.nll.stderr
new file mode 100644 (file)
index 0000000..b9c47e6
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/borrowck-move-out-of-overloaded-deref.rs:14:14
+   |
+LL |     let _x = *Rc::new("hi".to_string());
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              |
+   |              cannot move out of borrowed content
+   |              help: consider removing the `*`: `Rc::new("hi".to_string())`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
index 15c7011d71671c90b0852f028ce47060a1102c0d..34f9f035188b8d4276c21c2f5afc674365cb5f29 100644 (file)
@@ -5,10 +5,13 @@ LL |     match (S {f:"foo".to_string()}) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
 LL |         //[mir]~^ ERROR [E0509]
 LL |         S {f:_s} => {}
-   |              --
-   |              |
-   |              data moved here
-   |              help: to prevent move, use ref or ref mut: `ref _s`
+   |              -- data moved here
+   |
+note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:22:14
+   |
+LL |         S {f:_s} => {}
+   |              ^^
 
 error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
   --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:28:20
@@ -17,7 +20,12 @@ LL |     let S {f:_s} = S {f:"foo".to_string()};
    |              --    ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
    |              |
    |              data moved here
-   |              help: to prevent move, use ref or ref mut: `ref _s`
+   |
+note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:28:14
+   |
+LL |     let S {f:_s} = S {f:"foo".to_string()};
+   |              ^^
 
 error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
   --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:33:19
@@ -26,8 +34,13 @@ LL | fn move_in_fn_arg(S {f:_s}: S) {
    |                   ^^^^^--^
    |                   |    |
    |                   |    data moved here
-   |                   |    help: to prevent move, use ref or ref mut: `ref _s`
    |                   cannot move out of here
+   |
+note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:33:24
+   |
+LL | fn move_in_fn_arg(S {f:_s}: S) {
+   |                        ^^
 
 error: aborting due to 3 previous errors
 
index 15c7011d71671c90b0852f028ce47060a1102c0d..34f9f035188b8d4276c21c2f5afc674365cb5f29 100644 (file)
@@ -5,10 +5,13 @@ LL |     match (S {f:"foo".to_string()}) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
 LL |         //[mir]~^ ERROR [E0509]
 LL |         S {f:_s} => {}
-   |              --
-   |              |
-   |              data moved here
-   |              help: to prevent move, use ref or ref mut: `ref _s`
+   |              -- data moved here
+   |
+note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:22:14
+   |
+LL |         S {f:_s} => {}
+   |              ^^
 
 error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
   --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:28:20
@@ -17,7 +20,12 @@ LL |     let S {f:_s} = S {f:"foo".to_string()};
    |              --    ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
    |              |
    |              data moved here
-   |              help: to prevent move, use ref or ref mut: `ref _s`
+   |
+note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:28:14
+   |
+LL |     let S {f:_s} = S {f:"foo".to_string()};
+   |              ^^
 
 error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
   --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:33:19
@@ -26,8 +34,13 @@ LL | fn move_in_fn_arg(S {f:_s}: S) {
    |                   ^^^^^--^
    |                   |    |
    |                   |    data moved here
-   |                   |    help: to prevent move, use ref or ref mut: `ref _s`
    |                   cannot move out of here
+   |
+note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:33:24
+   |
+LL | fn move_in_fn_arg(S {f:_s}: S) {
+   |                        ^^
 
 error: aborting due to 3 previous errors
 
index c69ae8755a957dcdebeff4e25172412f6f622cf1..278c33c71e24549f00090137180e5a32f9df8d7d 100644 (file)
@@ -4,10 +4,13 @@ error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
 LL |     match S("foo".to_string()) {
    |           ^^^^^^^^^^^^^^^^^^^^ cannot move out of here
 LL |         S(_s) => {}
-   |           --
-   |           |
-   |           data moved here
-   |           help: to prevent move, use ref or ref mut: `ref _s`
+   |           -- data moved here
+   |
+note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:18:11
+   |
+LL |         S(_s) => {}
+   |           ^^
 
 error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
   --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:24:17
@@ -16,7 +19,12 @@ LL |     let S(_s) = S("foo".to_string());
    |           --    ^^^^^^^^^^^^^^^^^^^^ cannot move out of here
    |           |
    |           data moved here
-   |           help: to prevent move, use ref or ref mut: `ref _s`
+   |
+note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:24:11
+   |
+LL |     let S(_s) = S("foo".to_string());
+   |           ^^
 
 error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
   --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:28:19
@@ -25,8 +33,13 @@ LL | fn move_in_fn_arg(S(_s): S) {
    |                   ^^--^
    |                   | |
    |                   | data moved here
-   |                   | help: to prevent move, use ref or ref mut: `ref _s`
    |                   cannot move out of here
+   |
+note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:28:21
+   |
+LL | fn move_in_fn_arg(S(_s): S) {
+   |                     ^^
 
 error: aborting due to 3 previous errors
 
index 95a7894d532546e1f8dd942b7c11e536c906eb22..f3430ba4e06c9038310a8f087594447e8b89dbce 100644 (file)
@@ -7,14 +7,23 @@ LL |                 &[Foo { string: a },
    |                                 - data moved here
 ...
 LL |                   Foo { string: b }] => {
-   |                                 - ... and here
-help: to prevent move, use ref or ref mut
+   |                                 - ...and here
    |
-LL |                 &[Foo { string: ref a },
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/borrowck-move-out-of-vec-tail.rs:30:33
+   |
+LL |                 &[Foo { string: a },
+   |                                 ^
+...
+LL |                   Foo { string: b }] => {
+   |                                 ^
+help: consider removing the `&`
+   |
+LL |                 [Foo { string: a },
 LL |                 //~^ ERROR cannot move out of type `[Foo]`
 LL |                 //~| cannot move out
 LL |                 //~| to prevent move
-LL |                   Foo { string: ref b }] => {
+LL |                   Foo { string: b }] => {
    |
 
 error: aborting due to previous error
index 4a72d7f33026652970b485baf7aa76e090aaba8b..92e10c258c269efbd9cca6855d1dcd0e351bf573 100644 (file)
@@ -5,7 +5,7 @@ LL |     let bad = v[0];
    |               ^^^^
    |               |
    |               cannot move out of borrowed content
-   |               help: consider using a reference instead: `&v[0]`
+   |               help: consider borrowing here: `&v[0]`
 
 error: aborting due to previous error
 
index 2779132590e2c00b57e1b06f1a9d372b2af166fd..d5b17119d85f52abeb645cf07b1f5b8c24f2ec8e 100644 (file)
@@ -28,10 +28,21 @@ error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy sli
 LL |     match vec {
    |           ^^^ cannot move out of here
 LL |         &mut [_a, //~ ERROR cannot move out
-   |               --
-   |               |
-   |               data moved here
-   |               help: to prevent move, use ref or ref mut: `ref _a`
+   |               -- data moved here
+   |
+note: move occurs because `_a` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-vec-pattern-nesting.rs:44:15
+   |
+LL |         &mut [_a, //~ ERROR cannot move out
+   |               ^^
+help: consider removing the `&mut`
+   |
+LL |         [_a, //~ ERROR cannot move out
+LL |             //~| cannot move out
+LL |             //~| to prevent move
+LL |             ..
+LL |         ] => {
+   |
 
 error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
   --> $DIR/borrowck-vec-pattern-nesting.rs:57:13
@@ -40,7 +51,7 @@ LL |     let a = vec[0]; //~ ERROR cannot move out
    |             ^^^^^^
    |             |
    |             cannot move out of here
-   |             help: consider using a reference instead: `&vec[0]`
+   |             help: consider borrowing here: `&vec[0]`
 
 error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
   --> $DIR/borrowck-vec-pattern-nesting.rs:64:11
@@ -49,10 +60,19 @@ LL |     match vec {
    |           ^^^ cannot move out of here
 ...
 LL |          _b] => {}
-   |          --
-   |          |
-   |          data moved here
-   |          help: to prevent move, use ref or ref mut: `ref _b`
+   |          -- data moved here
+   |
+note: move occurs because `_b` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+  --> $DIR/borrowck-vec-pattern-nesting.rs:67:10
+   |
+LL |          _b] => {}
+   |          ^^
+help: consider removing the `&mut`
+   |
+LL |         [ //~ ERROR cannot move out
+LL |         //~^ cannot move out
+LL |          _b] => {}
+   |
 
 error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
   --> $DIR/borrowck-vec-pattern-nesting.rs:70:13
@@ -61,7 +81,7 @@ LL |     let a = vec[0]; //~ ERROR cannot move out
    |             ^^^^^^
    |             |
    |             cannot move out of here
-   |             help: consider using a reference instead: `&vec[0]`
+   |             help: consider borrowing here: `&vec[0]`
 
 error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
   --> $DIR/borrowck-vec-pattern-nesting.rs:77:11
@@ -69,14 +89,18 @@ error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy sli
 LL |     match vec {
    |           ^^^ cannot move out of here
 LL |         &mut [_a, _b, _c] => {}  //~ ERROR cannot move out
-   |               --  --  -- ... and here
-   |               |   |
-   |               |   ... and here
-   |               data moved here
-help: to prevent move, use ref or ref mut
-   |
-LL |         &mut [ref _a, ref _b, ref _c] => {}  //~ ERROR cannot move out
-   |               ^^^^^^  ^^^^^^  ^^^^^^
+   |         -----------------
+   |         |     |   |   |
+   |         |     |   |   ...and here
+   |         |     |   ...and here
+   |         |     data moved here
+   |         help: consider removing the `&mut`: `[_a, _b, _c]`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/borrowck-vec-pattern-nesting.rs:78:15
+   |
+LL |         &mut [_a, _b, _c] => {}  //~ ERROR cannot move out
+   |               ^^  ^^  ^^
 
 error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
   --> $DIR/borrowck-vec-pattern-nesting.rs:82:13
@@ -85,7 +109,7 @@ LL |     let a = vec[0]; //~ ERROR cannot move out
    |             ^^^^^^
    |             |
    |             cannot move out of here
-   |             help: consider using a reference instead: `&vec[0]`
+   |             help: consider borrowing here: `&vec[0]`
 
 error: aborting due to 8 previous errors
 
index 20713c3392e8e9c23e0f2cfe66337beee321ede3..d4340938eebc14880e7b4409021344c26f733c86 100644 (file)
@@ -5,8 +5,13 @@ LL |     let opt = a.iter().enumerate().find(|(_, &s)| {
    |                                          ^^^^^-^
    |                                          |    |
    |                                          |    data moved here
-   |                                          |    help: to prevent move, use ref or ref mut: `ref s`
    |                                          cannot move out of borrowed content
+   |
+note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/issue-51415.rs:16:47
+   |
+LL |     let opt = a.iter().enumerate().find(|(_, &s)| {
+   |                                               ^
 
 error: aborting due to previous error
 
index 07a9f374b2c3935fd2368bd4bdee6ab7c960082d..0eb5fc8c324356ad358fa2438ac9bb1c992834a0 100644 (file)
@@ -1,6 +1,9 @@
 error[E0507]: cannot move out of captured variable in an `Fn` closure
   --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:21:9
    |
+LL |     let y = vec![format!("World")];
+   |         - captured outer variable
+LL |     call(|| {
 LL |         y.into_iter();
    |         ^ cannot move out of captured variable in an `Fn` closure
 
index 4ba9b3aeb5d5da423591f7b3554db573cdaad917..491b5b5bd74abef53a40f7b6d0e963f9c0683bd5 100644 (file)
@@ -5,10 +5,16 @@ LL |     match &s.x {
    |           ^^^^ cannot move out of borrowed content
 LL |         &E::Foo => {}
 LL |         &E::Bar(identifier) => f(identifier.clone())  //~ ERROR cannot move
-   |                 ----------
-   |                 |
-   |                 data moved here
-   |                 help: to prevent move, use ref or ref mut: `ref identifier`
+   |         -------------------
+   |         |       |
+   |         |       data moved here
+   |         help: consider removing the `&`: `E::Bar(identifier)`
+   |
+note: move occurs because `identifier` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/by-move-pattern-binding.rs:26:17
+   |
+LL |         &E::Bar(identifier) => f(identifier.clone())  //~ ERROR cannot move
+   |                 ^^^^^^^^^^
 
 error: aborting due to previous error
 
index b265ec8bddac689c663c9d8b1d35e527f397e2c6..5522e22fb1fa28089a33a6c8851a39b7b52cf70a 100644 (file)
@@ -56,7 +56,7 @@ LL |     let y = { static x: Box<isize> = box 3; x };
    |                                             ^
    |                                             |
    |                                             cannot move out of static item
-   |                                             help: consider using a reference instead: `&x`
+   |                                             help: consider borrowing here: `&x`
 
 error[E0010]: allocations are not allowed in statics
   --> $DIR/check-static-values-constraints.rs:120:38
index a1fbcf1430db93b2b4a40c3077ee87db39a4cce9..e334472f9d6e1b26cba8b06eb20fe2ccdd999cfe 100644 (file)
@@ -4,10 +4,13 @@ error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
 LL |     match (S {f:"foo".to_string()}) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
 LL |         S {f:_s} => {} //~ ERROR cannot move out
-   |              --
-   |              |
-   |              data moved here
-   |              help: to prevent move, use ref or ref mut: `ref _s`
+   |              -- data moved here
+   |
+note: move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/overlapping_spans.rs:21:14
+   |
+LL |         S {f:_s} => {} //~ ERROR cannot move out
+   |              ^^
 
 error: aborting due to previous error
 
index a8be048d7df6c25c5e0e2c8551704e01d546f7a4..8e0599370287fb886ef239e8b593c5088c94d7dd 100644 (file)
@@ -5,7 +5,12 @@ LL |     let X { x: y } = x; //~ ERROR cannot move out of type
    |                -     ^ cannot move out of here
    |                |
    |                data moved here
-   |                help: to prevent move, use ref or ref mut: `ref y`
+   |
+note: move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/disallowed-deconstructing-destructing-struct-let.rs:22:16
+   |
+LL |     let X { x: y } = x; //~ ERROR cannot move out of type
+   |                ^
 
 error: aborting due to previous error
 
index 9f0d2d5f0e1891e42d588a51db7c0b663dd22428..dd1a3ef2a2b9835c1403c0796b7475cb4b7de57d 100644 (file)
@@ -4,10 +4,13 @@ error[E0509]: cannot move out of type `X`, which implements the `Drop` trait
 LL |     match x {
    |           ^ cannot move out of here
 LL |         X { x: y } => println!("contents: {}", y)
-   |                -
-   |                |
-   |                data moved here
-   |                help: to prevent move, use ref or ref mut: `ref y`
+   |                - data moved here
+   |
+note: move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/disallowed-deconstructing-destructing-struct-match.rs:25:16
+   |
+LL |         X { x: y } => println!("contents: {}", y)
+   |                ^
 
 error: aborting due to previous error
 
index cb6cc44a73597686f222eeb76d9fcbc3721f6d35..613b359c299b80238f2a9ab34803032d6147204e 100644 (file)
@@ -4,7 +4,7 @@ error[E0232]: `#[rustc_on_unimplemented]` requires a value
 LL | #[rustc_on_unimplemented]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ value required here
    |
-   = note: eg `#[rustc_on_unimplemented = "foo"]`
+   = note: eg `#[rustc_on_unimplemented(message="foo")]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0509.nll.stderr b/src/test/ui/error-codes/E0509.nll.stderr
new file mode 100644 (file)
index 0000000..723b083
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0509]: cannot move out of type `DropStruct`, which implements the `Drop` trait
+  --> $DIR/E0509.rs:26:23
+   |
+LL |     let fancy_field = drop_struct.fancy; //~ ERROR E0509
+   |                       ^^^^^^^^^^^^^^^^^
+   |                       |
+   |                       cannot move out of here
+   |                       help: consider borrowing here: `&drop_struct.fancy`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0509`.
diff --git a/src/test/ui/issue-51602.rs b/src/test/ui/issue-51602.rs
new file mode 100644 (file)
index 0000000..a3edecb
--- /dev/null
@@ -0,0 +1,15 @@
+// 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.
+
+fn main(){
+    if i in 1..10 {
+        break;
+    }
+}
diff --git a/src/test/ui/issue-51602.stderr b/src/test/ui/issue-51602.stderr
new file mode 100644 (file)
index 0000000..ac079b4
--- /dev/null
@@ -0,0 +1,10 @@
+error: expected `{`, found `in`
+  --> $DIR/issue-51602.rs:12:10
+   |
+LL |     if i in 1..10 {
+   |     --   ^^ expected `{`
+   |     |
+   |     this `if` statement has a condition, but no block
+
+error: aborting due to previous error
+
index 29bda252b9115f180495870e819928142669be9c..72d21d47d86fa765985da974e0b8b2664837d7fa 100644 (file)
@@ -8,15 +8,16 @@ LL |         (&[], &[hd, ..]) | (&[hd, ..], &[])
    |                 -- data moved here
 ...
 LL |         (&[hd1, ..], &[hd2, ..])
-   |                        --- ... and here
-help: to prevent move, use ref or ref mut
+   |                        --- ...and here
    |
-LL |         (&[], &[ref hd, ..]) | (&[hd, ..], &[])
-LL |             => println!("one empty"),
-LL |         //~^^ ERROR: cannot move out of type `[T]`, a non-copy slice
-LL |         //~^^^ ERROR: cannot move out of type `[T]`, a non-copy slice
-LL |         (&[hd1, ..], &[ref hd2, ..])
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/issue-12567.rs:16:17
    |
+LL |         (&[], &[hd, ..]) | (&[hd, ..], &[])
+   |                 ^^
+...
+LL |         (&[hd1, ..], &[hd2, ..])
+   |                        ^^^
 
 error[E0508]: cannot move out of type `[T]`, a non-copy slice
   --> $DIR/issue-12567.rs:14:11
@@ -28,15 +29,16 @@ LL |         (&[], &[hd, ..]) | (&[hd, ..], &[])
    |                 -- data moved here
 ...
 LL |         (&[hd1, ..], &[hd2, ..])
-   |            --- ... and here
-help: to prevent move, use ref or ref mut
+   |            --- ...and here
    |
-LL |         (&[], &[ref hd, ..]) | (&[hd, ..], &[])
-LL |             => println!("one empty"),
-LL |         //~^^ ERROR: cannot move out of type `[T]`, a non-copy slice
-LL |         //~^^^ ERROR: cannot move out of type `[T]`, a non-copy slice
-LL |         (&[ref hd1, ..], &[hd2, ..])
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/issue-12567.rs:16:17
    |
+LL |         (&[], &[hd, ..]) | (&[hd, ..], &[])
+   |                 ^^
+...
+LL |         (&[hd1, ..], &[hd2, ..])
+   |            ^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-17718-static-move.nll.stderr b/src/test/ui/issues/issue-17718-static-move.nll.stderr
new file mode 100644 (file)
index 0000000..f8da3c3
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0507]: cannot move out of static item
+  --> $DIR/issue-17718-static-move.rs:16:14
+   |
+LL |     let _a = FOO; //~ ERROR: cannot move out of static item
+   |              ^^^
+   |              |
+   |              cannot move out of static item
+   |              help: consider borrowing here: `&FOO`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
index fc94cc423c53138d3c35bcbbdfef22648835772e..3a6784eed67dd35d3adaaadb90b1bcd59d38ebc7 100644 (file)
@@ -5,7 +5,7 @@ LL |     let a = unsafe { *mut_ref() };
    |                      ^^^^^^^^^^
    |                      |
    |                      cannot move out of borrowed content
-   |                      help: consider using a reference instead: `&*mut_ref()`
+   |                      help: consider removing the `*`: `mut_ref()`
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/issue-20801.rs:39:22
@@ -14,7 +14,7 @@ LL |     let b = unsafe { *imm_ref() };
    |                      ^^^^^^^^^^
    |                      |
    |                      cannot move out of borrowed content
-   |                      help: consider using a reference instead: `&*imm_ref()`
+   |                      help: consider removing the `*`: `imm_ref()`
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/issue-20801.rs:42:22
@@ -23,7 +23,7 @@ LL |     let c = unsafe { *mut_ptr() };
    |                      ^^^^^^^^^^
    |                      |
    |                      cannot move out of borrowed content
-   |                      help: consider using a reference instead: `&*mut_ptr()`
+   |                      help: consider removing the `*`: `mut_ptr()`
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/issue-20801.rs:45:22
@@ -32,7 +32,7 @@ LL |     let d = unsafe { *const_ptr() };
    |                      ^^^^^^^^^^^^
    |                      |
    |                      cannot move out of borrowed content
-   |                      help: consider using a reference instead: `&*const_ptr()`
+   |                      help: consider removing the `*`: `const_ptr()`
 
 error: aborting due to 4 previous errors
 
index ed9db2ea55ed93f809d92ad75e9e64000f8c8dba..c9a29ac2199c0a4ecc773a4b02adca17281d2ba6 100644 (file)
@@ -7,7 +7,7 @@ LL |     data: T, //~ ERROR the size for values of type
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = help: consider adding a `where T: std::marker::Sized` bound
-   = note: only the last field of a struct may have a dynamically sized type
+   = note: the last field of a packed struct may only have a dynamically sized type if it does not need drop to be run
 
 error: aborting due to previous error
 
index 162e43abc0ac47a0e915200ff2df12e647227194..9020d3778c3730820347651be4554a9b7d9c1f0b 100644 (file)
@@ -5,7 +5,7 @@ LL |     let e = f.v[0]; //~ ERROR cannot move out of indexed content
    |             ^^^^^^
    |             |
    |             cannot move out of borrowed content
-   |             help: consider using a reference instead: `&f.v[0]`
+   |             help: consider borrowing here: `&f.v[0]`
 
 error: aborting due to previous error
 
index cd75be24589dfbf443bd00671ba8dc3e43056891..a80e9a5fe091f70343247033078fb2881a09d61d 100644 (file)
@@ -5,9 +5,15 @@ LL |     let (a, b) = x[0]; //~ ERROR cannot move out of indexed content
    |          -  -    ^^^^
    |          |  |    |
    |          |  |    cannot move out of borrowed content
-   |          |  |    help: consider using a reference instead: `&x[0]`
-   |          |  move occurs because b has type `std::string::String`, which does not implement the `Copy` trait
-   |          move occurs because a has type `std::string::String`, which does not implement the `Copy` trait
+   |          |  |    help: consider borrowing here: `&x[0]`
+   |          |  ...and here
+   |          data moved here
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/issue-40402-2.rs:15:10
+   |
+LL |     let (a, b) = x[0]; //~ ERROR cannot move out of indexed content
+   |          ^  ^
 
 error: aborting due to previous error
 
index 4ccd24fa4592141da4799057f4c26a3cc9978ccd..a9345e86f724817652892986419e26b313268195 100644 (file)
@@ -1,6 +1,8 @@
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
   --> $DIR/issue-4335.rs:16:20
    |
+LL | fn f<'r, T>(v: &'r T) -> Box<FnMut() -> T + 'r> {
+   |             - captured outer variable
 LL |     id(Box::new(|| *v))
    |                    ^^ cannot move out of captured variable in an `FnMut` closure
 
diff --git a/src/test/ui/macros/issue-30143.rs b/src/test/ui/macros/issue-30143.rs
new file mode 100644 (file)
index 0000000..b7fb5b3
--- /dev/null
@@ -0,0 +1,21 @@
+// 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.
+
+use std::fmt::Write;
+
+fn main() {
+    println!(0);
+    //~^ ERROR format argument must be a string literal
+    eprintln!('a');
+    //~^ ERROR format argument must be a string literal
+    let mut s = String::new();
+    writeln!(s, true).unwrap();
+    //~^ ERROR format argument must be a string literal
+}
diff --git a/src/test/ui/macros/issue-30143.stderr b/src/test/ui/macros/issue-30143.stderr
new file mode 100644 (file)
index 0000000..56834f6
--- /dev/null
@@ -0,0 +1,32 @@
+error: format argument must be a string literal
+  --> $DIR/issue-30143.rs:14:14
+   |
+LL |     println!(0);
+   |              ^
+help: you might be missing a string literal to format with
+   |
+LL |     println!("{}", 0);
+   |              ^^^^^
+
+error: format argument must be a string literal
+  --> $DIR/issue-30143.rs:16:15
+   |
+LL |     eprintln!('a');
+   |               ^^^
+help: you might be missing a string literal to format with
+   |
+LL |     eprintln!("{}", 'a');
+   |               ^^^^^
+
+error: format argument must be a string literal
+  --> $DIR/issue-30143.rs:19:17
+   |
+LL |     writeln!(s, true).unwrap();
+   |                 ^^^^
+help: you might be missing a string literal to format with
+   |
+LL |     writeln!(s, "{}", true).unwrap();
+   |                 ^^^^^
+
+error: aborting due to 3 previous errors
+
index a77b172487600fa30accb038d043a483d2b8fe98..111375b369363e9e2821f961da5e3c4d5dc8dd77 100644 (file)
@@ -8,5 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[doc = $not_there] //~ ERROR arbitrary tokens in non-macro attributes are unstable
+#![feature(unrestricted_attribute_tokens)]
+
+#[doc = $not_there] //~ ERROR expected `]`, found `not_there`
 fn main() { }
index 48132dddf1a42492773aea8a0f6804e41ddd178c..c403872ecb38581bb4c9bc6cf0d533a51997dd92 100644 (file)
@@ -1,11 +1,8 @@
-error[E0658]: arbitrary tokens in non-macro attributes are unstable (see issue #44690)
-  --> $DIR/macro-attribute.rs:11:1
+error: expected `]`, found `not_there`
+  --> $DIR/macro-attribute.rs:13:10
    |
-LL | #[doc = $not_there] //~ ERROR arbitrary tokens in non-macro attributes are unstable
-   | ^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(unrestricted_attribute_tokens)] to the crate attributes to enable
+LL | #[doc = $not_there] //~ ERROR expected `]`, found `not_there`
+   |          ^^^^^^^^^ expected `]`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
index 2815e1be70983377e45eaae934acb59da450eee7..7290d18beb74e9388990b29fe87aaa62a6b25570 100644 (file)
@@ -10,6 +10,7 @@
 
 // normalize-stderr-test: "The system cannot find the file specified\." -> "No such file or directory"
 // ignore-tidy-linelength
+// ignore-stage1
 
 // test that errors in a (selection) of macros don't kill compilation
 // immediately, so that we get more errors listed at a time.
index 084042acc974d698f5655013cec24e281707ce81..efb2c248813d7bd13237b65eaacb8aa43d8d0bbc 100644 (file)
@@ -1,47 +1,47 @@
 error[E0665]: `Default` cannot be derived for enums, only structs
-  --> $DIR/macros-nonfatal-errors.rs:20:10
+  --> $DIR/macros-nonfatal-errors.rs:21:10
    |
 LL | #[derive(Default)] //~ ERROR
    |          ^^^^^^^
 
 error: inline assembly must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:24:10
+  --> $DIR/macros-nonfatal-errors.rs:25:10
    |
 LL |     asm!(invalid); //~ ERROR
    |          ^^^^^^^
 
 error: concat_idents! requires ident args.
-  --> $DIR/macros-nonfatal-errors.rs:26:5
+  --> $DIR/macros-nonfatal-errors.rs:27:5
    |
 LL |     concat_idents!("not", "idents"); //~ ERROR
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:28:17
+  --> $DIR/macros-nonfatal-errors.rs:29:17
    |
 LL |     option_env!(invalid); //~ ERROR
    |                 ^^^^^^^
 
 error: expected string literal
-  --> $DIR/macros-nonfatal-errors.rs:29:10
+  --> $DIR/macros-nonfatal-errors.rs:30:10
    |
 LL |     env!(invalid); //~ ERROR
    |          ^^^^^^^
 
 error: expected string literal
-  --> $DIR/macros-nonfatal-errors.rs:30:10
+  --> $DIR/macros-nonfatal-errors.rs:31:10
    |
 LL |     env!(foo, abr, baz); //~ ERROR
    |          ^^^
 
 error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined
-  --> $DIR/macros-nonfatal-errors.rs:31:5
+  --> $DIR/macros-nonfatal-errors.rs:32:5
    |
 LL |     env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); //~ ERROR
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0658]: non-ident macro paths are experimental (see issue #35896)
-  --> $DIR/macros-nonfatal-errors.rs:33:5
+  --> $DIR/macros-nonfatal-errors.rs:34:5
    |
 LL |     foo::blah!(); //~ ERROR
    |     ^^^^^^^^^
@@ -49,7 +49,7 @@ LL |     foo::blah!(); //~ ERROR
    = help: add #![feature(use_extern_macros)] to the crate attributes to enable
 
 error: format argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:35:13
+  --> $DIR/macros-nonfatal-errors.rs:36:13
    |
 LL |     format!(invalid); //~ ERROR
    |             ^^^^^^^
@@ -59,37 +59,37 @@ LL |     format!("{}", invalid); //~ ERROR
    |             ^^^^^
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:37:14
+  --> $DIR/macros-nonfatal-errors.rs:38:14
    |
 LL |     include!(invalid); //~ ERROR
    |              ^^^^^^^
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:39:18
+  --> $DIR/macros-nonfatal-errors.rs:40:18
    |
 LL |     include_str!(invalid); //~ ERROR
    |                  ^^^^^^^
 
 error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: No such file or directory (os error 2)
-  --> $DIR/macros-nonfatal-errors.rs:40:5
+  --> $DIR/macros-nonfatal-errors.rs:41:5
    |
 LL |     include_str!("i'd be quite surprised if a file with this name existed"); //~ ERROR
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:41:20
+  --> $DIR/macros-nonfatal-errors.rs:42:20
    |
 LL |     include_bytes!(invalid); //~ ERROR
    |                    ^^^^^^^
 
 error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: No such file or directory (os error 2)
-  --> $DIR/macros-nonfatal-errors.rs:42:5
+  --> $DIR/macros-nonfatal-errors.rs:43:5
    |
 LL |     include_bytes!("i'd be quite surprised if a file with this name existed"); //~ ERROR
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: trace_macros! accepts only `true` or `false`
-  --> $DIR/macros-nonfatal-errors.rs:44:5
+  --> $DIR/macros-nonfatal-errors.rs:45:5
    |
 LL |     trace_macros!(invalid); //~ ERROR
    |     ^^^^^^^^^^^^^^^^^^^^^^^
index b061b6a7963859daed322b322498da6a7c3dd45c..aa62b457ecdf378cef6c96e4a6256aa36293a886 100644 (file)
@@ -4,10 +4,13 @@ error[E0508]: cannot move out of type `[A]`, a non-copy slice
 LL |     match a {
    |           ^ cannot move out of here
 LL |         box [a] => {}, //~ ERROR cannot move out of type `[A]`, a non-copy slice
-   |              -
-   |              |
-   |              data moved here
-   |              help: to prevent move, use ref or ref mut: `ref a`
+   |              - data moved here
+   |
+note: move occurs because `a` has type `A`, which does not implement the `Copy` trait
+  --> $DIR/move-out-of-slice-1.rs:18:14
+   |
+LL |         box [a] => {}, //~ ERROR cannot move out of type `[A]`, a non-copy slice
+   |              ^
 
 error: aborting due to previous error
 
index 94f2074b45d4c0a444f38b6606876e5eefdb3097..1f22ab148185296bbf3ca71abe0a75ca06630a3d 100644 (file)
@@ -5,10 +5,16 @@ LL |             match hellothere.x { //~ ERROR cannot move out
    |                   ^^^^^^^^^^^^
    |                   |
    |                   cannot move out of borrowed content
-   |                   help: consider using a reference instead: `&hellothere.x`
+   |                   help: consider borrowing here: `&hellothere.x`
 ...
 LL |                 box E::Bar(x) => println!("{}", x.to_string()),
-   |                            - move occurs because x has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+   |                            - data moved here
+   |
+note: move occurs because `x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+  --> $DIR/moves-based-on-type-block-bad.rs:37:28
+   |
+LL |                 box E::Bar(x) => println!("{}", x.to_string()),
+   |                            ^
 
 error: aborting due to previous error
 
index 4f2220b0de34107df84154575b4c1e0d6df41df8..13a6fc15ce3185b7ebbbd5093d018c515fad9293 100644 (file)
@@ -1,6 +1,8 @@
 error[E0507]: cannot move out of captured variable in an `Fn` closure
   --> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:21:28
    |
+LL |     let i = box 3;
+   |         - captured outer variable
 LL |     let _f = to_fn(|| test(i)); //~ ERROR cannot move out
    |                            ^ cannot move out of captured variable in an `Fn` closure
 
index 814e11b6f0682f5feccb0a49fce9885b48d65dbd..6a4c8f2e8d81570161b7d251523acb9c6483235f 100644 (file)
@@ -5,7 +5,7 @@ LL |     let x = { *r }; //~ ERROR
    |               ^^
    |               |
    |               cannot move out of borrowed content
-   |               help: consider removing this dereference operator: `r`
+   |               help: consider removing the `*`: `r`
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/cannot-move-block-spans.rs:16:22
@@ -14,7 +14,7 @@ LL |     let y = unsafe { *r }; //~ ERROR
    |                      ^^
    |                      |
    |                      cannot move out of borrowed content
-   |                      help: consider removing this dereference operator: `r`
+   |                      help: consider removing the `*`: `r`
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/cannot-move-block-spans.rs:17:26
@@ -23,7 +23,7 @@ LL |     let z = loop { break *r; }; //~ ERROR
    |                          ^^
    |                          |
    |                          cannot move out of borrowed content
-   |                          help: consider removing this dereference operator: `r`
+   |                          help: consider removing the `*`: `r`
 
 error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array
   --> $DIR/cannot-move-block-spans.rs:21:15
@@ -32,7 +32,7 @@ LL |     let x = { arr[0] }; //~ ERROR
    |               ^^^^^^
    |               |
    |               cannot move out of here
-   |               help: consider using a reference instead: `&arr[0]`
+   |               help: consider borrowing here: `&arr[0]`
 
 error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array
   --> $DIR/cannot-move-block-spans.rs:22:22
@@ -41,7 +41,7 @@ LL |     let y = unsafe { arr[0] }; //~ ERROR
    |                      ^^^^^^
    |                      |
    |                      cannot move out of here
-   |                      help: consider using a reference instead: `&arr[0]`
+   |                      help: consider borrowing here: `&arr[0]`
 
 error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array
   --> $DIR/cannot-move-block-spans.rs:23:26
@@ -50,7 +50,7 @@ LL |     let z = loop { break arr[0]; }; //~ ERROR
    |                          ^^^^^^
    |                          |
    |                          cannot move out of here
-   |                          help: consider using a reference instead: `&arr[0]`
+   |                          help: consider borrowing here: `&arr[0]`
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/cannot-move-block-spans.rs:27:38
@@ -59,7 +59,7 @@ LL |     let x = { let mut u = 0; u += 1; *r }; //~ ERROR
    |                                      ^^
    |                                      |
    |                                      cannot move out of borrowed content
-   |                                      help: consider removing this dereference operator: `r`
+   |                                      help: consider removing the `*`: `r`
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/cannot-move-block-spans.rs:28:45
@@ -68,7 +68,7 @@ LL |     let y = unsafe { let mut u = 0; u += 1; *r }; //~ ERROR
    |                                             ^^
    |                                             |
    |                                             cannot move out of borrowed content
-   |                                             help: consider removing this dereference operator: `r`
+   |                                             help: consider removing the `*`: `r`
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/cannot-move-block-spans.rs:29:49
@@ -77,7 +77,7 @@ LL |     let z = loop { let mut u = 0; u += 1; break *r; u += 2; }; //~ ERROR
    |                                                 ^^
    |                                                 |
    |                                                 cannot move out of borrowed content
-   |                                                 help: consider removing this dereference operator: `r`
+   |                                                 help: consider removing the `*`: `r`
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs b/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs
new file mode 100644 (file)
index 0000000..dc40b0c
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(nll)]
+
+fn expect_fn<F>(f: F) where F : Fn() {
+    f();
+}
+
+fn main() {
+   {
+       let x = (vec![22], vec![44]);
+       expect_fn(|| drop(x.0));
+       //~^ ERROR cannot move out of captured variable in an `Fn` closure [E0507]
+   }
+}
diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr
new file mode 100644 (file)
index 0000000..51f1956
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0507]: cannot move out of captured variable in an `Fn` closure
+  --> $DIR/issue-52663-span-decl-captured-variable.rs:20:26
+   |
+LL |        let x = (vec![22], vec![44]);
+   |            - captured outer variable
+LL |        expect_fn(|| drop(x.0));
+   |                          ^^^ cannot move out of captured variable in an `Fn` closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
index 53d60d3f6d649a4b4ec0b3d9efbc1dc8c14f4ba7..592768363096cae2d0d60a37ee35a0eefb81d24b 100644 (file)
@@ -5,7 +5,7 @@ LL |     let b = *a;
    |             ^^
    |             |
    |             cannot move out of borrowed content
-   |             help: consider removing this dereference operator: `a`
+   |             help: consider removing the `*`: `a`
 
 error[E0508]: cannot move out of type `[A; 1]`, a non-copy array
   --> $DIR/move-errors.rs:25:13
@@ -14,7 +14,7 @@ LL |     let b = a[0];
    |             ^^^^
    |             |
    |             cannot move out of here
-   |             help: consider using a reference instead: `&a[0]`
+   |             help: consider borrowing here: `&a[0]`
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/move-errors.rs:32:13
@@ -23,7 +23,7 @@ LL |     let s = **r;
    |             ^^^
    |             |
    |             cannot move out of borrowed content
-   |             help: consider using a reference instead: `&**r`
+   |             help: consider removing the `*`: `*r`
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/move-errors.rs:40:13
@@ -32,7 +32,7 @@ LL |     let s = *r;
    |             ^^
    |             |
    |             cannot move out of borrowed content
-   |             help: consider using a reference instead: `&*r`
+   |             help: consider removing the `*`: `r`
 
 error[E0508]: cannot move out of type `[A; 1]`, a non-copy array
   --> $DIR/move-errors.rs:45:13
@@ -41,7 +41,7 @@ LL |     let a = [A("".to_string())][0];
    |             ^^^^^^^^^^^^^^^^^^^^^^
    |             |
    |             cannot move out of here
-   |             help: consider using a reference instead: `&[A("".to_string())][0]`
+   |             help: consider borrowing here: `&[A("".to_string())][0]`
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/move-errors.rs:51:16
@@ -50,8 +50,14 @@ LL |     let A(s) = *a;
    |           -    ^^
    |           |    |
    |           |    cannot move out of borrowed content
-   |           |    help: consider removing this dereference operator: `a`
-   |           move occurs because s has type `std::string::String`, which does not implement the `Copy` trait
+   |           |    help: consider removing the `*`: `a`
+   |           data moved here
+   |
+note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/move-errors.rs:51:11
+   |
+LL |     let A(s) = *a;
+   |           ^
 
 error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
   --> $DIR/move-errors.rs:57:19
@@ -60,7 +66,12 @@ LL |     let C(D(s)) = c;
    |             -     ^ cannot move out of here
    |             |
    |             data moved here
-   |             help: to prevent move, use ref or ref mut: `ref s`
+   |
+note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/move-errors.rs:57:13
+   |
+LL |     let C(D(s)) = c;
+   |             ^
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/move-errors.rs:64:9
@@ -75,12 +86,20 @@ LL |     match x[0] {
    |           ^^^^
    |           |
    |           cannot move out of here
-   |           help: consider using a reference instead: `&x[0]`
+   |           help: consider borrowing here: `&x[0]`
 LL |     //~^ ERROR
 LL |         B::U(d) => (),
-   |              - move occurs because d has type `D`, which does not implement the `Copy` trait
+   |              - data moved here
 LL |         B::V(s) => (),
-   |              - move occurs because s has type `std::string::String`, which does not implement the `Copy` trait
+   |              - ...and here
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/move-errors.rs:89:14
+   |
+LL |         B::U(d) => (),
+   |              ^
+LL |         B::V(s) => (),
+   |              ^
 
 error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
   --> $DIR/move-errors.rs:96:11
@@ -89,10 +108,13 @@ LL |     match x {
    |           ^ cannot move out of here
 ...
 LL |         B::U(D(s)) => (),
-   |                -
-   |                |
-   |                data moved here
-   |                help: to prevent move, use ref or ref mut: `ref s`
+   |                - data moved here
+   |
+note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/move-errors.rs:99:16
+   |
+LL |         B::U(D(s)) => (),
+   |                ^
 
 error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
   --> $DIR/move-errors.rs:105:11
@@ -101,10 +123,13 @@ LL |     match x {
    |           ^ cannot move out of here
 ...
 LL |         (D(s), &t) => (),
-   |            -
-   |            |
-   |            data moved here
-   |            help: to prevent move, use ref or ref mut: `ref s`
+   |            - data moved here
+   |
+note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/move-errors.rs:108:12
+   |
+LL |         (D(s), &t) => (),
+   |            ^
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/move-errors.rs:105:11
@@ -113,10 +138,13 @@ LL |     match x {
    |           ^ cannot move out of borrowed content
 ...
 LL |         (D(s), &t) => (),
-   |                 -
-   |                 |
-   |                 data moved here
-   |                 help: to prevent move, use ref or ref mut: `ref t`
+   |                 - data moved here
+   |
+note: move occurs because `t` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/move-errors.rs:108:17
+   |
+LL |         (D(s), &t) => (),
+   |                 ^
 
 error[E0509]: cannot move out of type `F`, which implements the `Drop` trait
   --> $DIR/move-errors.rs:115:11
@@ -125,13 +153,15 @@ LL |     match x {
    |           ^ cannot move out of here
 LL |     //~^ ERROR
 LL |         F(s, mut t) => (),
-   |           -  ----- ... and here
+   |           -  ----- ...and here
    |           |
    |           data moved here
-help: to prevent move, use ref or ref mut
    |
-LL |         F(ref s, ref mut t) => (),
-   |           ^^^^^  ^^^^^^^^^
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/move-errors.rs:117:11
+   |
+LL |         F(s, mut t) => (),
+   |           ^  ^^^^^
 
 error[E0507]: cannot move out of borrowed content
   --> $DIR/move-errors.rs:123:11
@@ -140,10 +170,16 @@ LL |     match *x {
    |           ^^
    |           |
    |           cannot move out of borrowed content
-   |           help: consider removing this dereference operator: `x`
+   |           help: consider removing the `*`: `x`
 LL |     //~^ ERROR
 LL |         Ok(s) | Err(s) => (),
-   |            - move occurs because s has type `std::string::String`, which does not implement the `Copy` trait
+   |            - data moved here
+   |
+note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
+  --> $DIR/move-errors.rs:125:12
+   |
+LL |         Ok(s) | Err(s) => (),
+   |            ^
 
 error: aborting due to 14 previous errors
 
index 7ef155e5f2ebece26ddc962389863f4f1bc7d023..286c71bb2990847078ba45170003511a9958ae17 100644 (file)
@@ -28,7 +28,7 @@ trait BadAnnotation1
 {}
 
 #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"]
-//~^ ERROR there is no parameter C on trait BadAnnotation2
+//~^ ERROR there is no parameter `C` on trait `BadAnnotation2`
 trait BadAnnotation2<A,B>
 {}
 
index 1c5d4d603afc662d6cae88914ec8a29104a74eb9..212eb125f85b386e715b6c59c1b31df7b2f131c0 100644 (file)
@@ -4,9 +4,9 @@ error[E0232]: `#[rustc_on_unimplemented]` requires a value
 LL | #[rustc_on_unimplemented] //~ ERROR `#[rustc_on_unimplemented]` requires a value
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ value required here
    |
-   = note: eg `#[rustc_on_unimplemented = "foo"]`
+   = note: eg `#[rustc_on_unimplemented(message="foo")]`
 
-error[E0230]: there is no parameter C on trait BadAnnotation2
+error[E0230]: there is no parameter `C` on trait `BadAnnotation2`
   --> $DIR/bad-annotation.rs:30:1
    |
 LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"]
@@ -24,7 +24,7 @@ error[E0232]: this attribute must have a valid value
 LL | #[rustc_on_unimplemented(lorem="")]
    |                          ^^^^^^^^ expected value here
    |
-   = note: eg `#[rustc_on_unimplemented = "foo"]`
+   = note: eg `#[rustc_on_unimplemented(message="foo")]`
 
 error[E0232]: this attribute must have a valid value
   --> $DIR/bad-annotation.rs:44:26
@@ -32,7 +32,7 @@ error[E0232]: this attribute must have a valid value
 LL | #[rustc_on_unimplemented(lorem(ipsum(dolor)))]
    |                          ^^^^^^^^^^^^^^^^^^^ expected value here
    |
-   = note: eg `#[rustc_on_unimplemented = "foo"]`
+   = note: eg `#[rustc_on_unimplemented(message="foo")]`
 
 error[E0232]: this attribute must have a valid value
   --> $DIR/bad-annotation.rs:48:39
@@ -40,7 +40,7 @@ error[E0232]: this attribute must have a valid value
 LL | #[rustc_on_unimplemented(message="x", message="y")]
    |                                       ^^^^^^^^^^^ expected value here
    |
-   = note: eg `#[rustc_on_unimplemented = "foo"]`
+   = note: eg `#[rustc_on_unimplemented(message="foo")]`
 
 error[E0232]: this attribute must have a valid value
   --> $DIR/bad-annotation.rs:52:39
@@ -48,7 +48,7 @@ error[E0232]: this attribute must have a valid value
 LL | #[rustc_on_unimplemented(message="x", on(desugared, message="y"))]
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here
    |
-   = note: eg `#[rustc_on_unimplemented = "foo"]`
+   = note: eg `#[rustc_on_unimplemented(message="foo")]`
 
 error[E0232]: empty `on`-clause in `#[rustc_on_unimplemented]`
   --> $DIR/bad-annotation.rs:56:26
@@ -62,7 +62,7 @@ error[E0232]: this attribute must have a valid value
 LL | #[rustc_on_unimplemented(on="x", message="y")]
    |                          ^^^^^^ expected value here
    |
-   = note: eg `#[rustc_on_unimplemented = "foo"]`
+   = note: eg `#[rustc_on_unimplemented(message="foo")]`
 
 error[E0232]: this attribute must have a valid value
   --> $DIR/bad-annotation.rs:67:40
@@ -70,7 +70,7 @@ error[E0232]: this attribute must have a valid value
 LL | #[rustc_on_unimplemented(on(desugared, on(desugared, message="x")), message="y")]
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here
    |
-   = note: eg `#[rustc_on_unimplemented = "foo"]`
+   = note: eg `#[rustc_on_unimplemented(message="foo")]`
 
 error: aborting due to 10 previous errors
 
index c7dbc043cdaee3fa78e23f7525645f50516e5a44..a05a3911aa771144eb177e4b291e274e5b49bc29 100644 (file)
@@ -31,6 +31,9 @@ LL |     f.f.call_mut(())
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
   --> $DIR/borrowck-call-is-borrow-issue-12224.rs:66:13
    |
+LL |     let mut f = move |g: Box<FnMut(isize)>, b: isize| {
+   |         ----- captured outer variable
+...
 LL |         foo(f);
    |             ^ cannot move out of captured variable in an `FnMut` closure
 
diff --git a/src/test/ui/std-uncopyable-atomics.nll.stderr b/src/test/ui/std-uncopyable-atomics.nll.stderr
new file mode 100644 (file)
index 0000000..e6b612f
--- /dev/null
@@ -0,0 +1,39 @@
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/std-uncopyable-atomics.rs:19:13
+   |
+LL |     let x = *&x; //~ ERROR: cannot move out of borrowed content
+   |             ^^^
+   |             |
+   |             cannot move out of borrowed content
+   |             help: consider removing the `*`: `&x`
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/std-uncopyable-atomics.rs:21:13
+   |
+LL |     let x = *&x; //~ ERROR: cannot move out of borrowed content
+   |             ^^^
+   |             |
+   |             cannot move out of borrowed content
+   |             help: consider removing the `*`: `&x`
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/std-uncopyable-atomics.rs:23:13
+   |
+LL |     let x = *&x; //~ ERROR: cannot move out of borrowed content
+   |             ^^^
+   |             |
+   |             cannot move out of borrowed content
+   |             help: consider removing the `*`: `&x`
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/std-uncopyable-atomics.rs:25:13
+   |
+LL |     let x = *&x; //~ ERROR: cannot move out of borrowed content
+   |             ^^^
+   |             |
+   |             cannot move out of borrowed content
+   |             help: consider removing the `*`: `&x`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.rs b/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.rs
new file mode 100644 (file)
index 0000000..dc0186e
--- /dev/null
@@ -0,0 +1,162 @@
+// 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.
+
+#![feature(nll)]
+
+#[derive(Clone)]
+enum Either {
+    One(X),
+    Two(X),
+}
+
+#[derive(Clone)]
+struct X(Y);
+
+#[derive(Clone)]
+struct Y;
+
+
+pub fn main() {
+    let e = Either::One(X(Y));
+    let mut em = Either::One(X(Y));
+
+    let r = &e;
+    let rm = &mut Either::One(X(Y));
+
+    let x = X(Y);
+    let mut xm = X(Y);
+
+    let s = &x;
+    let sm = &mut X(Y);
+
+    let ve = vec![Either::One(X(Y))];
+
+    let vr = &ve;
+    let vrm = &mut vec![Either::One(X(Y))];
+
+    let vx = vec![X(Y)];
+
+    let vs = &vx;
+    let vsm = &mut vec![X(Y)];
+
+    // -------- test for duplicate suggestions --------
+
+    let &(X(_t), X(_u)) = &(x.clone(), x.clone());
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&`
+    //~| SUGGESTION (X(_t), X(_u))
+    if let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&`
+    //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+    while let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&`
+    //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+    match &(e.clone(), e.clone()) {
+        //~^ ERROR cannot move
+        &(Either::One(_t), Either::Two(_u)) => (),
+        //~^ HELP consider removing the `&`
+        //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+        &(Either::Two(_t), Either::One(_u)) => (),
+        //~^ HELP consider removing the `&`
+        //~| SUGGESTION (Either::Two(_t), Either::One(_u))
+        _ => (),
+    }
+    match &(e.clone(), e.clone()) {
+        //~^ ERROR cannot move
+        &(Either::One(_t), Either::Two(_u))
+        //~^ HELP consider removing the `&`
+        //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+        | &(Either::Two(_t), Either::One(_u)) => (),
+        // FIXME: would really like a suggestion here too
+        _ => (),
+    }
+    match &(e.clone(), e.clone()) {
+        //~^ ERROR cannot move
+        &(Either::One(_t), Either::Two(_u)) => (),
+        //~^ HELP consider removing the `&`
+        //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+        &(Either::Two(ref _t), Either::One(ref _u)) => (),
+        _ => (),
+    }
+    match &(e.clone(), e.clone()) {
+        //~^ ERROR cannot move
+        &(Either::One(_t), Either::Two(_u)) => (),
+        //~^ HELP consider removing the `&`
+        //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+        (Either::Two(_t), Either::One(_u)) => (),
+        _ => (),
+    }
+    fn f5(&(X(_t), X(_u)): &(X, X)) { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&`
+    //~| SUGGESTION (X(_t), X(_u))
+
+    let &mut (X(_t), X(_u)) = &mut (xm.clone(), xm.clone());
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&mut`
+    //~| SUGGESTION (X(_t), X(_u))
+    if let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&mut`
+    //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+    while let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&mut`
+    //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+    match &mut (em.clone(), em.clone()) {
+        //~^ ERROR cannot move
+        &mut (Either::One(_t), Either::Two(_u)) => (),
+        //~^ HELP consider removing the `&mut`
+        //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+        &mut (Either::Two(_t), Either::One(_u)) => (),
+        //~^ HELP consider removing the `&mut`
+        //~| SUGGESTION (Either::Two(_t), Either::One(_u))
+        _ => (),
+    }
+    match &mut (em.clone(), em.clone()) {
+        //~^ ERROR cannot move
+        &mut (Either::One(_t), Either::Two(_u))
+        //~^ HELP consider removing the `&mut`
+        //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+        | &mut (Either::Two(_t), Either::One(_u)) => (),
+        // FIXME: would really like a suggestion here too
+        _ => (),
+    }
+    match &mut (em.clone(), em.clone()) {
+        //~^ ERROR cannot move
+        &mut (Either::One(_t), Either::Two(_u)) => (),
+        //~^ HELP consider removing the `&mut`
+        //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+        &mut (Either::Two(ref _t), Either::One(ref _u)) => (),
+        _ => (),
+    }
+    match &mut (em.clone(), em.clone()) {
+        //~^ ERROR cannot move
+        &mut (Either::One(_t), Either::Two(_u)) => (),
+        //~^ HELP consider removing the `&mut`
+        //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+        &mut (Either::Two(ref mut _t), Either::One(ref mut _u)) => (),
+        _ => (),
+    }
+    match &mut (em.clone(), em.clone()) {
+        //~^ ERROR cannot move
+        &mut (Either::One(_t), Either::Two(_u)) => (),
+        //~^ HELP consider removing the `&mut`
+        //~| SUGGESTION (Either::One(_t), Either::Two(_u))
+        (Either::Two(_t), Either::One(_u)) => (),
+        _ => (),
+    }
+    fn f6(&mut (X(_t), X(_u)): &mut (X, X)) { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&mut`
+    //~| SUGGESTION (X(_t), X(_u))
+}
diff --git a/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr b/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr
new file mode 100644 (file)
index 0000000..bb36884
--- /dev/null
@@ -0,0 +1,328 @@
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:51:27
+   |
+LL |     let &(X(_t), X(_u)) = &(x.clone(), x.clone());
+   |         ---------------   ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+   |         |   |      |
+   |         |   |      ...and here
+   |         |   data moved here
+   |         help: consider removing the `&`: `(X(_t), X(_u))`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:51:13
+   |
+LL |     let &(X(_t), X(_u)) = &(x.clone(), x.clone());
+   |             ^^     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:55:50
+   |
+LL |     if let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
+   |            -----------------------------------   ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+   |            |             |                |
+   |            |             |                ...and here
+   |            |             data moved here
+   |            help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:55:26
+   |
+LL |     if let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
+   |                          ^^               ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:59:53
+   |
+LL |     while let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
+   |               -----------------------------------   ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+   |               |             |                |
+   |               |             |                ...and here
+   |               |             data moved here
+   |               help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:59:29
+   |
+LL |     while let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
+   |                             ^^               ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:63:11
+   |
+LL |     match &(e.clone(), e.clone()) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &(Either::One(_t), Either::Two(_u)) => (),
+   |                       --               -- ...and here
+   |                       |
+   |                       data moved here
+...
+LL |         &(Either::Two(_t), Either::One(_u)) => (),
+   |                       -- ...and here   -- ...and here
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:65:23
+   |
+LL |         &(Either::One(_t), Either::Two(_u)) => (),
+   |                       ^^               ^^
+...
+LL |         &(Either::Two(_t), Either::One(_u)) => (),
+   |                       ^^               ^^
+help: consider removing the `&`
+   |
+LL |         (Either::One(_t), Either::Two(_u)) => (),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider removing the `&`
+   |
+LL |         (Either::Two(_t), Either::One(_u)) => (),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:73:11
+   |
+LL |     match &(e.clone(), e.clone()) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &(Either::One(_t), Either::Two(_u))
+   |         -----------------------------------
+   |         |             |                |
+   |         |             |                ...and here
+   |         |             data moved here
+   |         help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:75:23
+   |
+LL |         &(Either::One(_t), Either::Two(_u))
+   |                       ^^               ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:82:11
+   |
+LL |     match &(e.clone(), e.clone()) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &(Either::One(_t), Either::Two(_u)) => (),
+   |         -----------------------------------
+   |         |             |                |
+   |         |             |                ...and here
+   |         |             data moved here
+   |         help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:84:23
+   |
+LL |         &(Either::One(_t), Either::Two(_u)) => (),
+   |                       ^^               ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:90:11
+   |
+LL |     match &(e.clone(), e.clone()) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &(Either::One(_t), Either::Two(_u)) => (),
+   |         -----------------------------------
+   |         |             |                |
+   |         |             |                ...and here
+   |         |             data moved here
+   |         help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:92:23
+   |
+LL |         &(Either::One(_t), Either::Two(_u)) => (),
+   |                       ^^               ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:103:31
+   |
+LL |     let &mut (X(_t), X(_u)) = &mut (xm.clone(), xm.clone());
+   |         -------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+   |         |       |      |
+   |         |       |      ...and here
+   |         |       data moved here
+   |         help: consider removing the `&mut`: `(X(_t), X(_u))`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:103:17
+   |
+LL |     let &mut (X(_t), X(_u)) = &mut (xm.clone(), xm.clone());
+   |                 ^^     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:107:54
+   |
+LL |     if let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
+   |            ---------------------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+   |            |                 |                |
+   |            |                 |                ...and here
+   |            |                 data moved here
+   |            help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:107:30
+   |
+LL |     if let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
+   |                              ^^               ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:111:57
+   |
+LL |     while let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
+   |               ---------------------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+   |               |                 |                |
+   |               |                 |                ...and here
+   |               |                 data moved here
+   |               help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:111:33
+   |
+LL |     while let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
+   |                                 ^^               ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:115:11
+   |
+LL |     match &mut (em.clone(), em.clone()) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut (Either::One(_t), Either::Two(_u)) => (),
+   |                           --               -- ...and here
+   |                           |
+   |                           data moved here
+...
+LL |         &mut (Either::Two(_t), Either::One(_u)) => (),
+   |                           -- ...and here   -- ...and here
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:117:27
+   |
+LL |         &mut (Either::One(_t), Either::Two(_u)) => (),
+   |                           ^^               ^^
+...
+LL |         &mut (Either::Two(_t), Either::One(_u)) => (),
+   |                           ^^               ^^
+help: consider removing the `&mut`
+   |
+LL |         (Either::One(_t), Either::Two(_u)) => (),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider removing the `&mut`
+   |
+LL |         (Either::Two(_t), Either::One(_u)) => (),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:125:11
+   |
+LL |     match &mut (em.clone(), em.clone()) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut (Either::One(_t), Either::Two(_u))
+   |         ---------------------------------------
+   |         |                 |                |
+   |         |                 |                ...and here
+   |         |                 data moved here
+   |         help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:127:27
+   |
+LL |         &mut (Either::One(_t), Either::Two(_u))
+   |                           ^^               ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:134:11
+   |
+LL |     match &mut (em.clone(), em.clone()) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut (Either::One(_t), Either::Two(_u)) => (),
+   |         ---------------------------------------
+   |         |                 |                |
+   |         |                 |                ...and here
+   |         |                 data moved here
+   |         help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:136:27
+   |
+LL |         &mut (Either::One(_t), Either::Two(_u)) => (),
+   |                           ^^               ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:142:11
+   |
+LL |     match &mut (em.clone(), em.clone()) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut (Either::One(_t), Either::Two(_u)) => (),
+   |         ---------------------------------------
+   |         |                 |                |
+   |         |                 |                ...and here
+   |         |                 data moved here
+   |         help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:144:27
+   |
+LL |         &mut (Either::One(_t), Either::Two(_u)) => (),
+   |                           ^^               ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:150:11
+   |
+LL |     match &mut (em.clone(), em.clone()) {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut (Either::One(_t), Either::Two(_u)) => (),
+   |         ---------------------------------------
+   |         |                 |                |
+   |         |                 |                ...and here
+   |         |                 data moved here
+   |         help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:152:27
+   |
+LL |         &mut (Either::One(_t), Either::Two(_u)) => (),
+   |                           ^^               ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:98:11
+   |
+LL |     fn f5(&(X(_t), X(_u)): &(X, X)) { }
+   |           ^^^^--^^^^^--^^
+   |           |   |      |
+   |           |   |      ...and here
+   |           |   data moved here
+   |           cannot move out of borrowed content
+   |           help: consider removing the `&`: `(X(_t), X(_u))`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:98:15
+   |
+LL |     fn f5(&(X(_t), X(_u)): &(X, X)) { }
+   |               ^^     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/duplicate-suggestions.rs:158:11
+   |
+LL |     fn f6(&mut (X(_t), X(_u)): &mut (X, X)) { }
+   |           ^^^^^^^^--^^^^^--^^
+   |           |       |      |
+   |           |       |      ...and here
+   |           |       data moved here
+   |           cannot move out of borrowed content
+   |           help: consider removing the `&mut`: `(X(_t), X(_u))`
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/duplicate-suggestions.rs:158:19
+   |
+LL |     fn f6(&mut (X(_t), X(_u)): &mut (X, X)) { }
+   |                   ^^     ^^
+
+error: aborting due to 17 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.rs b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.rs
new file mode 100644 (file)
index 0000000..8cc847e
--- /dev/null
@@ -0,0 +1,171 @@
+// 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.
+
+#![feature(nll)]
+
+#[derive(Clone)]
+enum Either {
+    One(X),
+    Two(X),
+}
+
+#[derive(Clone)]
+struct X(Y);
+
+#[derive(Clone)]
+struct Y;
+
+fn consume_fn<F: Fn()>(_f: F) { }
+
+fn consume_fnmut<F: FnMut()>(_f: F) { }
+
+pub fn main() { }
+
+fn move_into_fn() {
+    let e = Either::One(X(Y));
+    let mut em = Either::One(X(Y));
+
+    let x = X(Y);
+
+    // -------- move into Fn --------
+
+    consume_fn(|| {
+        let X(_t) = x;
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &x
+        if let Either::One(_t) = e { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &e
+        while let Either::One(_t) = e { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &e
+        match e {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            //~| SUGGESTION &e
+            Either::One(_t)
+            | Either::Two(_t) => (),
+        }
+        match e {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            //~| SUGGESTION &e
+            Either::One(_t) => (),
+            Either::Two(ref _t) => (),
+            // FIXME: should suggest removing `ref` too
+        }
+
+        let X(mut _t) = x;
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &x
+        if let Either::One(mut _t) = em { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &em
+        while let Either::One(mut _t) = em { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &em
+        match em {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            //~| SUGGESTION &em
+            Either::One(mut _t)
+            | Either::Two(mut _t) => (),
+        }
+        match em {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            //~| SUGGESTION &em
+            Either::One(mut _t) => (),
+            Either::Two(ref _t) => (),
+            // FIXME: should suggest removing `ref` too
+        }
+    });
+}
+
+fn move_into_fnmut() {
+    let e = Either::One(X(Y));
+    let mut em = Either::One(X(Y));
+
+    let x = X(Y);
+
+    // -------- move into FnMut --------
+
+    consume_fnmut(|| {
+        let X(_t) = x;
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &x
+        if let Either::One(_t) = e { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &e
+        while let Either::One(_t) = e { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &e
+        match e {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            //~| SUGGESTION &e
+            Either::One(_t)
+            | Either::Two(_t) => (),
+        }
+        match e {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            //~| SUGGESTION &e
+            Either::One(_t) => (),
+            Either::Two(ref _t) => (),
+            // FIXME: should suggest removing `ref` too
+        }
+
+        let X(mut _t) = x;
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &x
+        if let Either::One(mut _t) = em { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &em
+        while let Either::One(mut _t) = em { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &em
+        match em {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            //~| SUGGESTION &em
+            Either::One(mut _t)
+            | Either::Two(mut _t) => (),
+        }
+        match em {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            //~| SUGGESTION &em
+            Either::One(mut _t) => (),
+            Either::Two(ref _t) => (),
+            // FIXME: should suggest removing `ref` too
+        }
+        match em {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            //~| SUGGESTION &em
+            Either::One(mut _t) => (),
+            Either::Two(ref mut _t) => (),
+            // FIXME: should suggest removing `ref` too
+        }
+    });
+}
diff --git a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
new file mode 100644 (file)
index 0000000..228ec5a
--- /dev/null
@@ -0,0 +1,420 @@
+error[E0507]: cannot move out of captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:40:21
+   |
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |         let X(_t) = x;
+   |               --    ^
+   |               |     |
+   |               |     cannot move out of captured variable in an `Fn` closure
+   |               |     help: consider borrowing here: `&x`
+   |               data moved here
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:40:15
+   |
+LL |         let X(_t) = x;
+   |               ^^
+
+error[E0507]: cannot move out of captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:44:34
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |         if let Either::One(_t) = e { }
+   |                            --    ^
+   |                            |     |
+   |                            |     cannot move out of captured variable in an `Fn` closure
+   |                            |     help: consider borrowing here: `&e`
+   |                            data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:44:28
+   |
+LL |         if let Either::One(_t) = e { }
+   |                            ^^
+
+error[E0507]: cannot move out of captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:48:37
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |         while let Either::One(_t) = e { }
+   |                               --    ^
+   |                               |     |
+   |                               |     cannot move out of captured variable in an `Fn` closure
+   |                               |     help: consider borrowing here: `&e`
+   |                               data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:48:31
+   |
+LL |         while let Either::One(_t) = e { }
+   |                               ^^
+
+error[E0507]: cannot move out of captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:52:15
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |         match e {
+   |               ^
+   |               |
+   |               cannot move out of captured variable in an `Fn` closure
+   |               help: consider borrowing here: `&e`
+...
+LL |             Either::One(_t)
+   |                         -- data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:56:25
+   |
+LL |             Either::One(_t)
+   |                         ^^
+
+error[E0507]: cannot move out of captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:59:15
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |         match e {
+   |               ^
+   |               |
+   |               cannot move out of captured variable in an `Fn` closure
+   |               help: consider borrowing here: `&e`
+...
+LL |             Either::One(_t) => (),
+   |                         -- data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:63:25
+   |
+LL |             Either::One(_t) => (),
+   |                         ^^
+
+error[E0507]: cannot move out of captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:68:25
+   |
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |         let X(mut _t) = x;
+   |               ------    ^
+   |               |         |
+   |               |         cannot move out of captured variable in an `Fn` closure
+   |               |         help: consider borrowing here: `&x`
+   |               data moved here
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:68:15
+   |
+LL |         let X(mut _t) = x;
+   |               ^^^^^^
+
+error[E0507]: cannot move out of captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:72:38
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |         if let Either::One(mut _t) = em { }
+   |                            ------    ^^
+   |                            |         |
+   |                            |         cannot move out of captured variable in an `Fn` closure
+   |                            |         help: consider borrowing here: `&em`
+   |                            data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:72:28
+   |
+LL |         if let Either::One(mut _t) = em { }
+   |                            ^^^^^^
+
+error[E0507]: cannot move out of captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:76:41
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |         while let Either::One(mut _t) = em { }
+   |                               ------    ^^
+   |                               |         |
+   |                               |         cannot move out of captured variable in an `Fn` closure
+   |                               |         help: consider borrowing here: `&em`
+   |                               data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:76:31
+   |
+LL |         while let Either::One(mut _t) = em { }
+   |                               ^^^^^^
+
+error[E0507]: cannot move out of captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:80:15
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |         match em {
+   |               ^^
+   |               |
+   |               cannot move out of captured variable in an `Fn` closure
+   |               help: consider borrowing here: `&em`
+...
+LL |             Either::One(mut _t)
+   |                         ------ data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:84:25
+   |
+LL |             Either::One(mut _t)
+   |                         ^^^^^^
+
+error[E0507]: cannot move out of captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:87:15
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |         match em {
+   |               ^^
+   |               |
+   |               cannot move out of captured variable in an `Fn` closure
+   |               help: consider borrowing here: `&em`
+...
+LL |             Either::One(mut _t) => (),
+   |                         ------ data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:91:25
+   |
+LL |             Either::One(mut _t) => (),
+   |                         ^^^^^^
+
+error[E0507]: cannot move out of captured variable in an `FnMut` closure
+  --> $DIR/move-into-closure.rs:107:21
+   |
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |         let X(_t) = x;
+   |               --    ^
+   |               |     |
+   |               |     cannot move out of captured variable in an `FnMut` closure
+   |               |     help: consider borrowing here: `&x`
+   |               data moved here
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:107:15
+   |
+LL |         let X(_t) = x;
+   |               ^^
+
+error[E0507]: cannot move out of captured variable in an `FnMut` closure
+  --> $DIR/move-into-closure.rs:111:34
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |         if let Either::One(_t) = e { }
+   |                            --    ^
+   |                            |     |
+   |                            |     cannot move out of captured variable in an `FnMut` closure
+   |                            |     help: consider borrowing here: `&e`
+   |                            data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:111:28
+   |
+LL |         if let Either::One(_t) = e { }
+   |                            ^^
+
+error[E0507]: cannot move out of captured variable in an `FnMut` closure
+  --> $DIR/move-into-closure.rs:115:37
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |         while let Either::One(_t) = e { }
+   |                               --    ^
+   |                               |     |
+   |                               |     cannot move out of captured variable in an `FnMut` closure
+   |                               |     help: consider borrowing here: `&e`
+   |                               data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:115:31
+   |
+LL |         while let Either::One(_t) = e { }
+   |                               ^^
+
+error[E0507]: cannot move out of captured variable in an `FnMut` closure
+  --> $DIR/move-into-closure.rs:119:15
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |         match e {
+   |               ^
+   |               |
+   |               cannot move out of captured variable in an `FnMut` closure
+   |               help: consider borrowing here: `&e`
+...
+LL |             Either::One(_t)
+   |                         -- data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:123:25
+   |
+LL |             Either::One(_t)
+   |                         ^^
+
+error[E0507]: cannot move out of captured variable in an `FnMut` closure
+  --> $DIR/move-into-closure.rs:126:15
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |         match e {
+   |               ^
+   |               |
+   |               cannot move out of captured variable in an `FnMut` closure
+   |               help: consider borrowing here: `&e`
+...
+LL |             Either::One(_t) => (),
+   |                         -- data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:130:25
+   |
+LL |             Either::One(_t) => (),
+   |                         ^^
+
+error[E0507]: cannot move out of captured variable in an `FnMut` closure
+  --> $DIR/move-into-closure.rs:135:25
+   |
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |         let X(mut _t) = x;
+   |               ------    ^
+   |               |         |
+   |               |         cannot move out of captured variable in an `FnMut` closure
+   |               |         help: consider borrowing here: `&x`
+   |               data moved here
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:135:15
+   |
+LL |         let X(mut _t) = x;
+   |               ^^^^^^
+
+error[E0507]: cannot move out of captured variable in an `FnMut` closure
+  --> $DIR/move-into-closure.rs:139:38
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |         if let Either::One(mut _t) = em { }
+   |                            ------    ^^
+   |                            |         |
+   |                            |         cannot move out of captured variable in an `FnMut` closure
+   |                            |         help: consider borrowing here: `&em`
+   |                            data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:139:28
+   |
+LL |         if let Either::One(mut _t) = em { }
+   |                            ^^^^^^
+
+error[E0507]: cannot move out of captured variable in an `FnMut` closure
+  --> $DIR/move-into-closure.rs:143:41
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |         while let Either::One(mut _t) = em { }
+   |                               ------    ^^
+   |                               |         |
+   |                               |         cannot move out of captured variable in an `FnMut` closure
+   |                               |         help: consider borrowing here: `&em`
+   |                               data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:143:31
+   |
+LL |         while let Either::One(mut _t) = em { }
+   |                               ^^^^^^
+
+error[E0507]: cannot move out of captured variable in an `FnMut` closure
+  --> $DIR/move-into-closure.rs:147:15
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |         match em {
+   |               ^^
+   |               |
+   |               cannot move out of captured variable in an `FnMut` closure
+   |               help: consider borrowing here: `&em`
+...
+LL |             Either::One(mut _t)
+   |                         ------ data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:151:25
+   |
+LL |             Either::One(mut _t)
+   |                         ^^^^^^
+
+error[E0507]: cannot move out of captured variable in an `FnMut` closure
+  --> $DIR/move-into-closure.rs:154:15
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |         match em {
+   |               ^^
+   |               |
+   |               cannot move out of captured variable in an `FnMut` closure
+   |               help: consider borrowing here: `&em`
+...
+LL |             Either::One(mut _t) => (),
+   |                         ------ data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:158:25
+   |
+LL |             Either::One(mut _t) => (),
+   |                         ^^^^^^
+
+error[E0507]: cannot move out of captured variable in an `FnMut` closure
+  --> $DIR/move-into-closure.rs:162:15
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |         match em {
+   |               ^^
+   |               |
+   |               cannot move out of captured variable in an `FnMut` closure
+   |               help: consider borrowing here: `&em`
+...
+LL |             Either::One(mut _t) => (),
+   |                         ------ data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/move-into-closure.rs:166:25
+   |
+LL |             Either::One(mut _t) => (),
+   |                         ^^^^^^
+
+error: aborting due to 21 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/suggestions/dont-suggest-ref/simple.rs b/src/test/ui/suggestions/dont-suggest-ref/simple.rs
new file mode 100644 (file)
index 0000000..474e88c
--- /dev/null
@@ -0,0 +1,376 @@
+// 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.
+
+#![feature(nll)]
+
+#[derive(Clone)]
+enum Either {
+    One(X),
+    Two(X),
+}
+
+#[derive(Clone)]
+struct X(Y);
+
+#[derive(Clone)]
+struct Y;
+
+pub fn main() {
+    let e = Either::One(X(Y));
+    let mut em = Either::One(X(Y));
+
+    let r = &e;
+    let rm = &mut Either::One(X(Y));
+
+    let x = X(Y);
+    let mut xm = X(Y);
+
+    let s = &x;
+    let sm = &mut X(Y);
+
+    let ve = vec![Either::One(X(Y))];
+
+    let vr = &ve;
+    let vrm = &mut vec![Either::One(X(Y))];
+
+    let vx = vec![X(Y)];
+
+    let vs = &vx;
+    let vsm = &mut vec![X(Y)];
+
+    // -------- move from Either/X place --------
+
+    let X(_t) = *s;
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `*`
+    //~| SUGGESTION s
+    if let Either::One(_t) = *r { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `*`
+    //~| SUGGESTION r
+    while let Either::One(_t) = *r { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `*`
+    //~| SUGGESTION r
+    match *r {
+        //~^ ERROR cannot move
+        //~| HELP consider removing the `*`
+        //~| SUGGESTION r
+        Either::One(_t)
+        | Either::Two(_t) => (),
+    }
+    match *r {
+        //~^ ERROR cannot move
+        //~| HELP consider removing the `*`
+        //~| SUGGESTION r
+        Either::One(_t) => (),
+        Either::Two(ref _t) => (),
+        // FIXME: should suggest removing `ref` too
+    }
+
+    let X(_t) = *sm;
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `*`
+    //~| SUGGESTION sm
+    if let Either::One(_t) = *rm { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `*`
+    //~| SUGGESTION rm
+    while let Either::One(_t) = *rm { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `*`
+    //~| SUGGESTION rm
+    match *rm {
+        //~^ ERROR cannot move
+        //~| HELP consider removing the `*`
+        //~| SUGGESTION rm
+        Either::One(_t)
+        | Either::Two(_t) => (),
+    }
+    match *rm {
+        //~^ ERROR cannot move
+        //~| HELP consider removing the `*`
+        //~| SUGGESTION rm
+        Either::One(_t) => (),
+        Either::Two(ref _t) => (),
+        // FIXME: should suggest removing `ref` too
+    }
+    match *rm {
+        //~^ ERROR cannot move
+        //~| HELP consider removing the `*`
+        //~| SUGGESTION rm
+        Either::One(_t) => (),
+        Either::Two(ref mut _t) => (),
+        // FIXME: should suggest removing `ref` too
+    }
+
+    let X(_t) = vs[0];
+    //~^ ERROR cannot move
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &vs[0]
+    if let Either::One(_t) = vr[0] { }
+    //~^ ERROR cannot move
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &vr[0]
+    while let Either::One(_t) = vr[0] { }
+    //~^ ERROR cannot move
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &vr[0]
+    match vr[0] {
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &vr[0]
+        Either::One(_t)
+        | Either::Two(_t) => (),
+    }
+    match vr[0] {
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &vr[0]
+        Either::One(_t) => (),
+        Either::Two(ref _t) => (),
+        // FIXME: should suggest removing `ref` too
+    }
+
+    let X(_t) = vsm[0];
+    //~^ ERROR cannot move
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &vsm[0]
+    if let Either::One(_t) = vrm[0] { }
+    //~^ ERROR cannot move
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &vrm[0]
+    while let Either::One(_t) = vrm[0] { }
+    //~^ ERROR cannot move
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &vrm[0]
+    match vrm[0] {
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &vrm[0]
+        Either::One(_t)
+        | Either::Two(_t) => (),
+    }
+    match vrm[0] {
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &vrm[0]
+        Either::One(_t) => (),
+        Either::Two(ref _t) => (),
+        // FIXME: should suggest removing `ref` too
+    }
+    match vrm[0] {
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        //~| SUGGESTION &vrm[0]
+        Either::One(_t) => (),
+        Either::Two(ref mut _t) => (),
+        // FIXME: should suggest removing `ref` too
+    }
+
+    // -------- move from &Either/&X place --------
+
+    let &X(_t) = s;
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&`
+    //~| SUGGESTION X(_t)
+    if let &Either::One(_t) = r { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&`
+    //~| SUGGESTION Either::One(_t)
+    while let &Either::One(_t) = r { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&`
+    //~| SUGGESTION Either::One(_t)
+    match r {
+        //~^ ERROR cannot move
+        &Either::One(_t)
+        //~^ HELP consider removing the `&`
+        //~| SUGGESTION Either::One(_t)
+        | &Either::Two(_t) => (),
+        // FIXME: would really like a suggestion here too
+    }
+    match r {
+        //~^ ERROR cannot move
+        &Either::One(_t) => (),
+        //~^ HELP consider removing the `&`
+        //~| SUGGESTION Either::One(_t)
+        &Either::Two(ref _t) => (),
+    }
+    match r {
+        //~^ ERROR cannot move
+        &Either::One(_t) => (),
+        //~^ HELP consider removing the `&`
+        //~| SUGGESTION Either::One(_t)
+        Either::Two(_t) => (),
+    }
+    fn f1(&X(_t): &X) { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&`
+    //~| SUGGESTION X(_t)
+
+    let &mut X(_t) = sm;
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&mut`
+    //~| SUGGESTION X(_t)
+    if let &mut Either::One(_t) = rm { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&mut`
+    //~| SUGGESTION Either::One(_t)
+    while let &mut Either::One(_t) = rm { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&mut`
+    //~| SUGGESTION Either::One(_t)
+    match rm {
+        //~^ ERROR cannot move
+        &mut Either::One(_t) => (),
+        //~^ HELP consider removing the `&mut`
+        //~| SUGGESTION Either::One(_t)
+        &mut Either::Two(_t) => (),
+        //~^ HELP consider removing the `&mut`
+        //~| SUGGESTION Either::Two(_t)
+    }
+    match rm {
+        //~^ ERROR cannot move
+        &mut Either::One(_t) => (),
+        //~^ HELP consider removing the `&mut`
+        //~| SUGGESTION Either::One(_t)
+        &mut Either::Two(ref _t) => (),
+    }
+    match rm {
+        //~^ ERROR cannot move
+        &mut Either::One(_t) => (),
+        //~^ HELP consider removing the `&mut`
+        //~| SUGGESTION Either::One(_t)
+        &mut Either::Two(ref mut _t) => (),
+    }
+    match rm {
+        //~^ ERROR cannot move
+        &mut Either::One(_t) => (),
+        //~^ HELP consider removing the `&mut`
+        //~| SUGGESTION Either::One(_t)
+        Either::Two(_t) => (),
+    }
+    fn f2(&mut X(_t): &mut X) { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&mut`
+    //~| SUGGESTION X(_t)
+
+    // -------- move from tuple of &Either/&X --------
+
+    // FIXME: These should have suggestions.
+
+    let (&X(_t),) = (&x.clone(),);
+    //~^ ERROR cannot move
+    if let (&Either::One(_t),) = (&e.clone(),) { }
+    //~^ ERROR cannot move
+    while let (&Either::One(_t),) = (&e.clone(),) { }
+    //~^ ERROR cannot move
+    match (&e.clone(),) {
+        //~^ ERROR cannot move
+        (&Either::One(_t),)
+        | (&Either::Two(_t),) => (),
+    }
+    fn f3((&X(_t),): (&X,)) { }
+    //~^ ERROR cannot move
+
+    let (&mut X(_t),) = (&mut xm.clone(),);
+    //~^ ERROR cannot move
+    if let (&mut Either::One(_t),) = (&mut em.clone(),) { }
+    //~^ ERROR cannot move
+    while let (&mut Either::One(_t),) = (&mut em.clone(),) { }
+    //~^ ERROR cannot move
+    match (&mut em.clone(),) {
+        //~^ ERROR cannot move
+        (&mut Either::One(_t),) => (),
+        (&mut Either::Two(_t),) => (),
+    }
+    fn f4((&mut X(_t),): (&mut X,)) { }
+    //~^ ERROR cannot move
+
+    // -------- move from &Either/&X value --------
+
+    let &X(_t) = &x;
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&`
+    //~| SUGGESTION X(_t)
+    if let &Either::One(_t) = &e { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&`
+    //~| SUGGESTION Either::One(_t)
+    while let &Either::One(_t) = &e { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&`
+    //~| SUGGESTION Either::One(_t)
+    match &e {
+        //~^ ERROR cannot move
+        &Either::One(_t)
+        //~^ HELP consider removing the `&`
+        //~| SUGGESTION Either::One(_t)
+        | &Either::Two(_t) => (),
+        // FIXME: would really like a suggestion here too
+    }
+    match &e {
+        //~^ ERROR cannot move
+        &Either::One(_t) => (),
+        //~^ HELP consider removing the `&`
+        //~| SUGGESTION Either::One(_t)
+        &Either::Two(ref _t) => (),
+    }
+    match &e {
+        //~^ ERROR cannot move
+        &Either::One(_t) => (),
+        //~^ HELP consider removing the `&`
+        //~| SUGGESTION Either::One(_t)
+        Either::Two(_t) => (),
+    }
+
+    let &mut X(_t) = &mut xm;
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&mut`
+    //~| SUGGESTION X(_t)
+    if let &mut Either::One(_t) = &mut em { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&mut`
+    //~| SUGGESTION Either::One(_t)
+    while let &mut Either::One(_t) = &mut em { }
+    //~^ ERROR cannot move
+    //~| HELP consider removing the `&mut`
+    //~| SUGGESTION Either::One(_t)
+    match &mut em {
+        //~^ ERROR cannot move
+        &mut Either::One(_t)
+        //~^ HELP consider removing the `&mut`
+        //~| SUGGESTION Either::One(_t)
+        | &mut Either::Two(_t) => (),
+        // FIXME: would really like a suggestion here too
+    }
+    match &mut em {
+        //~^ ERROR cannot move
+        &mut Either::One(_t) => (),
+        //~^ HELP consider removing the `&mut`
+        //~| SUGGESTION Either::One(_t)
+        &mut Either::Two(ref _t) => (),
+    }
+    match &mut em {
+        //~^ ERROR cannot move
+        &mut Either::One(_t) => (),
+        //~^ HELP consider removing the `&mut`
+        //~| SUGGESTION Either::One(_t)
+        &mut Either::Two(ref mut _t) => (),
+    }
+    match &mut em {
+        //~^ ERROR cannot move
+        &mut Either::One(_t) => (),
+        //~^ HELP consider removing the `&mut`
+        //~| SUGGESTION Either::One(_t)
+        Either::Two(_t) => (),
+    }
+}
diff --git a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr
new file mode 100644 (file)
index 0000000..d7a32db
--- /dev/null
@@ -0,0 +1,998 @@
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:50:17
+   |
+LL |     let X(_t) = *s;
+   |           --    ^^
+   |           |     |
+   |           |     cannot move out of borrowed content
+   |           |     help: consider removing the `*`: `s`
+   |           data moved here
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:50:11
+   |
+LL |     let X(_t) = *s;
+   |           ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:54:30
+   |
+LL |     if let Either::One(_t) = *r { }
+   |                        --    ^^
+   |                        |     |
+   |                        |     cannot move out of borrowed content
+   |                        |     help: consider removing the `*`: `r`
+   |                        data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:54:24
+   |
+LL |     if let Either::One(_t) = *r { }
+   |                        ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:58:33
+   |
+LL |     while let Either::One(_t) = *r { }
+   |                           --    ^^
+   |                           |     |
+   |                           |     cannot move out of borrowed content
+   |                           |     help: consider removing the `*`: `r`
+   |                           data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:58:27
+   |
+LL |     while let Either::One(_t) = *r { }
+   |                           ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:62:11
+   |
+LL |     match *r {
+   |           ^^
+   |           |
+   |           cannot move out of borrowed content
+   |           help: consider removing the `*`: `r`
+...
+LL |         Either::One(_t)
+   |                     -- data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:66:21
+   |
+LL |         Either::One(_t)
+   |                     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:69:11
+   |
+LL |     match *r {
+   |           ^^
+   |           |
+   |           cannot move out of borrowed content
+   |           help: consider removing the `*`: `r`
+...
+LL |         Either::One(_t) => (),
+   |                     -- data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:73:21
+   |
+LL |         Either::One(_t) => (),
+   |                     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:78:17
+   |
+LL |     let X(_t) = *sm;
+   |           --    ^^^
+   |           |     |
+   |           |     cannot move out of borrowed content
+   |           |     help: consider removing the `*`: `sm`
+   |           data moved here
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:78:11
+   |
+LL |     let X(_t) = *sm;
+   |           ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:82:30
+   |
+LL |     if let Either::One(_t) = *rm { }
+   |                        --    ^^^
+   |                        |     |
+   |                        |     cannot move out of borrowed content
+   |                        |     help: consider removing the `*`: `rm`
+   |                        data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:82:24
+   |
+LL |     if let Either::One(_t) = *rm { }
+   |                        ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:86:33
+   |
+LL |     while let Either::One(_t) = *rm { }
+   |                           --    ^^^
+   |                           |     |
+   |                           |     cannot move out of borrowed content
+   |                           |     help: consider removing the `*`: `rm`
+   |                           data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:86:27
+   |
+LL |     while let Either::One(_t) = *rm { }
+   |                           ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:90:11
+   |
+LL |     match *rm {
+   |           ^^^
+   |           |
+   |           cannot move out of borrowed content
+   |           help: consider removing the `*`: `rm`
+...
+LL |         Either::One(_t)
+   |                     -- data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:94:21
+   |
+LL |         Either::One(_t)
+   |                     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:97:11
+   |
+LL |     match *rm {
+   |           ^^^
+   |           |
+   |           cannot move out of borrowed content
+   |           help: consider removing the `*`: `rm`
+...
+LL |         Either::One(_t) => (),
+   |                     -- data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:101:21
+   |
+LL |         Either::One(_t) => (),
+   |                     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:105:11
+   |
+LL |     match *rm {
+   |           ^^^
+   |           |
+   |           cannot move out of borrowed content
+   |           help: consider removing the `*`: `rm`
+...
+LL |         Either::One(_t) => (),
+   |                     -- data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:109:21
+   |
+LL |         Either::One(_t) => (),
+   |                     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:114:17
+   |
+LL |     let X(_t) = vs[0];
+   |           --    ^^^^^
+   |           |     |
+   |           |     cannot move out of borrowed content
+   |           |     help: consider borrowing here: `&vs[0]`
+   |           data moved here
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:114:11
+   |
+LL |     let X(_t) = vs[0];
+   |           ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:118:30
+   |
+LL |     if let Either::One(_t) = vr[0] { }
+   |                        --    ^^^^^
+   |                        |     |
+   |                        |     cannot move out of borrowed content
+   |                        |     help: consider borrowing here: `&vr[0]`
+   |                        data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:118:24
+   |
+LL |     if let Either::One(_t) = vr[0] { }
+   |                        ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:122:33
+   |
+LL |     while let Either::One(_t) = vr[0] { }
+   |                           --    ^^^^^
+   |                           |     |
+   |                           |     cannot move out of borrowed content
+   |                           |     help: consider borrowing here: `&vr[0]`
+   |                           data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:122:27
+   |
+LL |     while let Either::One(_t) = vr[0] { }
+   |                           ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:126:11
+   |
+LL |     match vr[0] {
+   |           ^^^^^
+   |           |
+   |           cannot move out of borrowed content
+   |           help: consider borrowing here: `&vr[0]`
+...
+LL |         Either::One(_t)
+   |                     -- data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:130:21
+   |
+LL |         Either::One(_t)
+   |                     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:133:11
+   |
+LL |     match vr[0] {
+   |           ^^^^^
+   |           |
+   |           cannot move out of borrowed content
+   |           help: consider borrowing here: `&vr[0]`
+...
+LL |         Either::One(_t) => (),
+   |                     -- data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:137:21
+   |
+LL |         Either::One(_t) => (),
+   |                     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:142:17
+   |
+LL |     let X(_t) = vsm[0];
+   |           --    ^^^^^^
+   |           |     |
+   |           |     cannot move out of borrowed content
+   |           |     help: consider borrowing here: `&vsm[0]`
+   |           data moved here
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:142:11
+   |
+LL |     let X(_t) = vsm[0];
+   |           ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:146:30
+   |
+LL |     if let Either::One(_t) = vrm[0] { }
+   |                        --    ^^^^^^
+   |                        |     |
+   |                        |     cannot move out of borrowed content
+   |                        |     help: consider borrowing here: `&vrm[0]`
+   |                        data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:146:24
+   |
+LL |     if let Either::One(_t) = vrm[0] { }
+   |                        ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:150:33
+   |
+LL |     while let Either::One(_t) = vrm[0] { }
+   |                           --    ^^^^^^
+   |                           |     |
+   |                           |     cannot move out of borrowed content
+   |                           |     help: consider borrowing here: `&vrm[0]`
+   |                           data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:150:27
+   |
+LL |     while let Either::One(_t) = vrm[0] { }
+   |                           ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:154:11
+   |
+LL |     match vrm[0] {
+   |           ^^^^^^
+   |           |
+   |           cannot move out of borrowed content
+   |           help: consider borrowing here: `&vrm[0]`
+...
+LL |         Either::One(_t)
+   |                     -- data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:158:21
+   |
+LL |         Either::One(_t)
+   |                     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:161:11
+   |
+LL |     match vrm[0] {
+   |           ^^^^^^
+   |           |
+   |           cannot move out of borrowed content
+   |           help: consider borrowing here: `&vrm[0]`
+...
+LL |         Either::One(_t) => (),
+   |                     -- data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:165:21
+   |
+LL |         Either::One(_t) => (),
+   |                     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:169:11
+   |
+LL |     match vrm[0] {
+   |           ^^^^^^
+   |           |
+   |           cannot move out of borrowed content
+   |           help: consider borrowing here: `&vrm[0]`
+...
+LL |         Either::One(_t) => (),
+   |                     -- data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:173:21
+   |
+LL |         Either::One(_t) => (),
+   |                     ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:180:18
+   |
+LL |     let &X(_t) = s;
+   |         ------   ^ cannot move out of borrowed content
+   |         |  |
+   |         |  data moved here
+   |         help: consider removing the `&`: `X(_t)`
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:180:12
+   |
+LL |     let &X(_t) = s;
+   |            ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:184:31
+   |
+LL |     if let &Either::One(_t) = r { }
+   |            ----------------   ^ cannot move out of borrowed content
+   |            |            |
+   |            |            data moved here
+   |            help: consider removing the `&`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:184:25
+   |
+LL |     if let &Either::One(_t) = r { }
+   |                         ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:188:34
+   |
+LL |     while let &Either::One(_t) = r { }
+   |               ----------------   ^ cannot move out of borrowed content
+   |               |            |
+   |               |            data moved here
+   |               help: consider removing the `&`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:188:28
+   |
+LL |     while let &Either::One(_t) = r { }
+   |                            ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:192:11
+   |
+LL |     match r {
+   |           ^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &Either::One(_t)
+   |         ----------------
+   |         |            |
+   |         |            data moved here
+   |         help: consider removing the `&`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:194:22
+   |
+LL |         &Either::One(_t)
+   |                      ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:200:11
+   |
+LL |     match r {
+   |           ^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &Either::One(_t) => (),
+   |         ----------------
+   |         |            |
+   |         |            data moved here
+   |         help: consider removing the `&`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:202:22
+   |
+LL |         &Either::One(_t) => (),
+   |                      ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:207:11
+   |
+LL |     match r {
+   |           ^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &Either::One(_t) => (),
+   |         ----------------
+   |         |            |
+   |         |            data moved here
+   |         help: consider removing the `&`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:209:22
+   |
+LL |         &Either::One(_t) => (),
+   |                      ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:219:22
+   |
+LL |     let &mut X(_t) = sm;
+   |         ----------   ^^ cannot move out of borrowed content
+   |         |      |
+   |         |      data moved here
+   |         help: consider removing the `&mut`: `X(_t)`
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:219:16
+   |
+LL |     let &mut X(_t) = sm;
+   |                ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:223:35
+   |
+LL |     if let &mut Either::One(_t) = rm { }
+   |            --------------------   ^^ cannot move out of borrowed content
+   |            |                |
+   |            |                data moved here
+   |            help: consider removing the `&mut`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:223:29
+   |
+LL |     if let &mut Either::One(_t) = rm { }
+   |                             ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:227:38
+   |
+LL |     while let &mut Either::One(_t) = rm { }
+   |               --------------------   ^^ cannot move out of borrowed content
+   |               |                |
+   |               |                data moved here
+   |               help: consider removing the `&mut`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:227:32
+   |
+LL |     while let &mut Either::One(_t) = rm { }
+   |                                ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:231:11
+   |
+LL |     match rm {
+   |           ^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t) => (),
+   |                          -- data moved here
+...
+LL |         &mut Either::Two(_t) => (),
+   |                          -- ...and here
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/simple.rs:233:26
+   |
+LL |         &mut Either::One(_t) => (),
+   |                          ^^
+...
+LL |         &mut Either::Two(_t) => (),
+   |                          ^^
+help: consider removing the `&mut`
+   |
+LL |         Either::One(_t) => (),
+   |         ^^^^^^^^^^^^^^^
+help: consider removing the `&mut`
+   |
+LL |         Either::Two(_t) => (),
+   |         ^^^^^^^^^^^^^^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:240:11
+   |
+LL |     match rm {
+   |           ^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t) => (),
+   |         --------------------
+   |         |                |
+   |         |                data moved here
+   |         help: consider removing the `&mut`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:242:26
+   |
+LL |         &mut Either::One(_t) => (),
+   |                          ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:247:11
+   |
+LL |     match rm {
+   |           ^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t) => (),
+   |         --------------------
+   |         |                |
+   |         |                data moved here
+   |         help: consider removing the `&mut`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:249:26
+   |
+LL |         &mut Either::One(_t) => (),
+   |                          ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:254:11
+   |
+LL |     match rm {
+   |           ^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t) => (),
+   |         --------------------
+   |         |                |
+   |         |                data moved here
+   |         help: consider removing the `&mut`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:256:26
+   |
+LL |         &mut Either::One(_t) => (),
+   |                          ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:270:21
+   |
+LL |     let (&X(_t),) = (&x.clone(),);
+   |             --      ^^^^^^^^^^^^^ cannot move out of borrowed content
+   |             |
+   |             data moved here
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:270:13
+   |
+LL |     let (&X(_t),) = (&x.clone(),);
+   |             ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:272:34
+   |
+LL |     if let (&Either::One(_t),) = (&e.clone(),) { }
+   |                          --      ^^^^^^^^^^^^^ cannot move out of borrowed content
+   |                          |
+   |                          data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:272:26
+   |
+LL |     if let (&Either::One(_t),) = (&e.clone(),) { }
+   |                          ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:274:37
+   |
+LL |     while let (&Either::One(_t),) = (&e.clone(),) { }
+   |                             --      ^^^^^^^^^^^^^ cannot move out of borrowed content
+   |                             |
+   |                             data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:274:29
+   |
+LL |     while let (&Either::One(_t),) = (&e.clone(),) { }
+   |                             ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:276:11
+   |
+LL |     match (&e.clone(),) {
+   |           ^^^^^^^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         (&Either::One(_t),)
+   |                       -- data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:278:23
+   |
+LL |         (&Either::One(_t),)
+   |                       ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:284:25
+   |
+LL |     let (&mut X(_t),) = (&mut xm.clone(),);
+   |                 --      ^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+   |                 |
+   |                 data moved here
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:284:17
+   |
+LL |     let (&mut X(_t),) = (&mut xm.clone(),);
+   |                 ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:286:38
+   |
+LL |     if let (&mut Either::One(_t),) = (&mut em.clone(),) { }
+   |                              --      ^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+   |                              |
+   |                              data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:286:30
+   |
+LL |     if let (&mut Either::One(_t),) = (&mut em.clone(),) { }
+   |                              ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:288:41
+   |
+LL |     while let (&mut Either::One(_t),) = (&mut em.clone(),) { }
+   |                                 --      ^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+   |                                 |
+   |                                 data moved here
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:288:33
+   |
+LL |     while let (&mut Either::One(_t),) = (&mut em.clone(),) { }
+   |                                 ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:290:11
+   |
+LL |     match (&mut em.clone(),) {
+   |           ^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         (&mut Either::One(_t),) => (),
+   |                           -- data moved here
+LL |         (&mut Either::Two(_t),) => (),
+   |                           -- ...and here
+   |
+note: move occurs because these variables have types that don't implement the `Copy` trait
+  --> $DIR/simple.rs:292:27
+   |
+LL |         (&mut Either::One(_t),) => (),
+   |                           ^^
+LL |         (&mut Either::Two(_t),) => (),
+   |                           ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:300:18
+   |
+LL |     let &X(_t) = &x;
+   |         ------   ^^ cannot move out of borrowed content
+   |         |  |
+   |         |  data moved here
+   |         help: consider removing the `&`: `X(_t)`
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:300:12
+   |
+LL |     let &X(_t) = &x;
+   |            ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:304:31
+   |
+LL |     if let &Either::One(_t) = &e { }
+   |            ----------------   ^^ cannot move out of borrowed content
+   |            |            |
+   |            |            data moved here
+   |            help: consider removing the `&`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:304:25
+   |
+LL |     if let &Either::One(_t) = &e { }
+   |                         ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:308:34
+   |
+LL |     while let &Either::One(_t) = &e { }
+   |               ----------------   ^^ cannot move out of borrowed content
+   |               |            |
+   |               |            data moved here
+   |               help: consider removing the `&`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:308:28
+   |
+LL |     while let &Either::One(_t) = &e { }
+   |                            ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:312:11
+   |
+LL |     match &e {
+   |           ^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &Either::One(_t)
+   |         ----------------
+   |         |            |
+   |         |            data moved here
+   |         help: consider removing the `&`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:314:22
+   |
+LL |         &Either::One(_t)
+   |                      ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:320:11
+   |
+LL |     match &e {
+   |           ^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &Either::One(_t) => (),
+   |         ----------------
+   |         |            |
+   |         |            data moved here
+   |         help: consider removing the `&`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:322:22
+   |
+LL |         &Either::One(_t) => (),
+   |                      ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:327:11
+   |
+LL |     match &e {
+   |           ^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &Either::One(_t) => (),
+   |         ----------------
+   |         |            |
+   |         |            data moved here
+   |         help: consider removing the `&`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:329:22
+   |
+LL |         &Either::One(_t) => (),
+   |                      ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:335:22
+   |
+LL |     let &mut X(_t) = &mut xm;
+   |         ----------   ^^^^^^^ cannot move out of borrowed content
+   |         |      |
+   |         |      data moved here
+   |         help: consider removing the `&mut`: `X(_t)`
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:335:16
+   |
+LL |     let &mut X(_t) = &mut xm;
+   |                ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:339:35
+   |
+LL |     if let &mut Either::One(_t) = &mut em { }
+   |            --------------------   ^^^^^^^ cannot move out of borrowed content
+   |            |                |
+   |            |                data moved here
+   |            help: consider removing the `&mut`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:339:29
+   |
+LL |     if let &mut Either::One(_t) = &mut em { }
+   |                             ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:343:38
+   |
+LL |     while let &mut Either::One(_t) = &mut em { }
+   |               --------------------   ^^^^^^^ cannot move out of borrowed content
+   |               |                |
+   |               |                data moved here
+   |               help: consider removing the `&mut`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:343:32
+   |
+LL |     while let &mut Either::One(_t) = &mut em { }
+   |                                ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:347:11
+   |
+LL |     match &mut em {
+   |           ^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t)
+   |         --------------------
+   |         |                |
+   |         |                data moved here
+   |         help: consider removing the `&mut`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:349:26
+   |
+LL |         &mut Either::One(_t)
+   |                          ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:355:11
+   |
+LL |     match &mut em {
+   |           ^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t) => (),
+   |         --------------------
+   |         |                |
+   |         |                data moved here
+   |         help: consider removing the `&mut`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:357:26
+   |
+LL |         &mut Either::One(_t) => (),
+   |                          ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:362:11
+   |
+LL |     match &mut em {
+   |           ^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t) => (),
+   |         --------------------
+   |         |                |
+   |         |                data moved here
+   |         help: consider removing the `&mut`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:364:26
+   |
+LL |         &mut Either::One(_t) => (),
+   |                          ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:369:11
+   |
+LL |     match &mut em {
+   |           ^^^^^^^ cannot move out of borrowed content
+LL |         //~^ ERROR cannot move
+LL |         &mut Either::One(_t) => (),
+   |         --------------------
+   |         |                |
+   |         |                data moved here
+   |         help: consider removing the `&mut`: `Either::One(_t)`
+   |
+note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:371:26
+   |
+LL |         &mut Either::One(_t) => (),
+   |                          ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:214:11
+   |
+LL |     fn f1(&X(_t): &X) { }
+   |           ^^^--^
+   |           |  |
+   |           |  data moved here
+   |           cannot move out of borrowed content
+   |           help: consider removing the `&`: `X(_t)`
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:214:14
+   |
+LL |     fn f1(&X(_t): &X) { }
+   |              ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:261:11
+   |
+LL |     fn f2(&mut X(_t): &mut X) { }
+   |           ^^^^^^^--^
+   |           |      |
+   |           |      data moved here
+   |           cannot move out of borrowed content
+   |           help: consider removing the `&mut`: `X(_t)`
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:261:18
+   |
+LL |     fn f2(&mut X(_t): &mut X) { }
+   |                  ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:281:11
+   |
+LL |     fn f3((&X(_t),): (&X,)) { }
+   |           ^^^^--^^^
+   |           |   |
+   |           |   data moved here
+   |           cannot move out of borrowed content
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:281:15
+   |
+LL |     fn f3((&X(_t),): (&X,)) { }
+   |               ^^
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/simple.rs:295:11
+   |
+LL |     fn f4((&mut X(_t),): (&mut X,)) { }
+   |           ^^^^^^^^--^^^
+   |           |       |
+   |           |       data moved here
+   |           cannot move out of borrowed content
+   |
+note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+  --> $DIR/simple.rs:295:19
+   |
+LL |     fn f4((&mut X(_t),): (&mut X,)) { }
+   |                   ^^
+
+error: aborting due to 60 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
index e74c66c27b13671dcc9a79116d4101462daad565..4baa54e34c75532750ffba07c939ae627e9639c8 100644 (file)
@@ -1,24 +1,32 @@
 error[E0507]: cannot move out of captured variable in an `Fn` closure
   --> $DIR/unboxed-closure-illegal-move.rs:25:31
    |
+LL |         let x = Box::new(0);
+   |             - captured outer variable
 LL |         let f = to_fn(|| drop(x)); //~ ERROR cannot move
    |                               ^ cannot move out of captured variable in an `Fn` closure
 
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
   --> $DIR/unboxed-closure-illegal-move.rs:29:35
    |
+LL |         let x = Box::new(0);
+   |             - captured outer variable
 LL |         let f = to_fn_mut(|| drop(x)); //~ ERROR cannot move
    |                                   ^ cannot move out of captured variable in an `FnMut` closure
 
 error[E0507]: cannot move out of captured variable in an `Fn` closure
   --> $DIR/unboxed-closure-illegal-move.rs:38:36
    |
+LL |         let x = Box::new(0);
+   |             - captured outer variable
 LL |         let f = to_fn(move || drop(x)); //~ ERROR cannot move
    |                                    ^ cannot move out of captured variable in an `Fn` closure
 
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
   --> $DIR/unboxed-closure-illegal-move.rs:42:40
    |
+LL |         let x = Box::new(0);
+   |             - captured outer variable
 LL |         let f = to_fn_mut(move || drop(x)); //~ ERROR cannot move
    |                                        ^ cannot move out of captured variable in an `FnMut` closure
 
diff --git a/src/test/ui/unrestricted-attribute-tokens.rs b/src/test/ui/unrestricted-attribute-tokens.rs
new file mode 100644 (file)
index 0000000..2971b50
--- /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-pass
+
+#![feature(custom_attribute, unrestricted_attribute_tokens)]
+
+#[my_attr(a b c d)]
+fn main() {}
index fd8fb54503a6ff85fde21499942d040608360f02..ee1345c7f9411caf31d14c0cd2577d721a2c75a5 100644 (file)
@@ -189,6 +189,7 @@ struct Builder {
     clippy_release: String,
     rustfmt_release: String,
     llvm_tools_release: String,
+    lldb_release: String,
 
     input: PathBuf,
     output: PathBuf,
@@ -203,6 +204,7 @@ struct Builder {
     clippy_version: Option<String>,
     rustfmt_version: Option<String>,
     llvm_tools_version: Option<String>,
+    lldb_version: Option<String>,
 
     rust_git_commit_hash: Option<String>,
     cargo_git_commit_hash: Option<String>,
@@ -210,6 +212,7 @@ struct Builder {
     clippy_git_commit_hash: Option<String>,
     rustfmt_git_commit_hash: Option<String>,
     llvm_tools_git_commit_hash: Option<String>,
+    lldb_git_commit_hash: Option<String>,
 }
 
 fn main() {
@@ -223,6 +226,7 @@ fn main() {
     let clippy_release = args.next().unwrap();
     let rustfmt_release = args.next().unwrap();
     let llvm_tools_release = args.next().unwrap();
+    let lldb_release = args.next().unwrap();
     let s3_address = args.next().unwrap();
     let mut passphrase = String::new();
     t!(io::stdin().read_to_string(&mut passphrase));
@@ -234,6 +238,7 @@ fn main() {
         clippy_release,
         rustfmt_release,
         llvm_tools_release,
+        lldb_release,
 
         input,
         output,
@@ -248,6 +253,7 @@ fn main() {
         clippy_version: None,
         rustfmt_version: None,
         llvm_tools_version: None,
+        lldb_version: None,
 
         rust_git_commit_hash: None,
         cargo_git_commit_hash: None,
@@ -255,6 +261,7 @@ fn main() {
         clippy_git_commit_hash: None,
         rustfmt_git_commit_hash: None,
         llvm_tools_git_commit_hash: None,
+        lldb_git_commit_hash: None,
     }.build();
 }
 
@@ -266,6 +273,7 @@ fn build(&mut self) {
         self.clippy_version = self.version("clippy", "x86_64-unknown-linux-gnu");
         self.rustfmt_version = self.version("rustfmt", "x86_64-unknown-linux-gnu");
         self.llvm_tools_version = self.version("llvm-tools", "x86_64-unknown-linux-gnu");
+        self.lldb_version = self.version("lldb", "x86_64-unknown-linux-gnu");
 
         self.rust_git_commit_hash = self.git_commit_hash("rust", "x86_64-unknown-linux-gnu");
         self.cargo_git_commit_hash = self.git_commit_hash("cargo", "x86_64-unknown-linux-gnu");
@@ -274,6 +282,7 @@ fn build(&mut self) {
         self.rustfmt_git_commit_hash = self.git_commit_hash("rustfmt", "x86_64-unknown-linux-gnu");
         self.llvm_tools_git_commit_hash = self.git_commit_hash("llvm-tools",
                                                                "x86_64-unknown-linux-gnu");
+        self.lldb_git_commit_hash = self.git_commit_hash("lldb", "x86_64-unknown-linux-gnu");
 
         self.digest_and_sign();
         let manifest = self.build_manifest();
@@ -312,11 +321,13 @@ fn build_manifest(&mut self) -> Manifest {
         self.package("rustfmt-preview", &mut manifest.pkg, HOSTS);
         self.package("rust-analysis", &mut manifest.pkg, TARGETS);
         self.package("llvm-tools-preview", &mut manifest.pkg, TARGETS);
+        self.package("lldb-preview", &mut manifest.pkg, TARGETS);
 
         let clippy_present = manifest.pkg.contains_key("clippy-preview");
         let rls_present = manifest.pkg.contains_key("rls-preview");
         let rustfmt_present = manifest.pkg.contains_key("rustfmt-preview");
         let llvm_tools_present = manifest.pkg.contains_key("llvm-tools-preview");
+        let lldb_present = manifest.pkg.contains_key("lldb-preview");
 
         if rls_present {
             manifest.renames.insert("rls".to_owned(), Rename { to: "rls-preview".to_owned() });
@@ -383,6 +394,12 @@ fn build_manifest(&mut self) -> Manifest {
                     target: host.to_string(),
                 });
             }
+            if lldb_present {
+                extensions.push(Component {
+                    pkg: "lldb-preview".to_string(),
+                    target: host.to_string(),
+                });
+            }
             extensions.push(Component {
                 pkg: "rust-analysis".to_string(),
                 target: host.to_string(),
@@ -496,6 +513,8 @@ fn filename(&self, component: &str, target: &str) -> String {
             format!("rustfmt-{}-{}.tar.gz", self.rustfmt_release, target)
         } else if component == "llvm-tools" || component == "llvm-tools-preview" {
             format!("llvm-tools-{}-{}.tar.gz", self.llvm_tools_release, target)
+        } else if component == "lldb" || component == "lldb-preview" {
+            format!("lldb-{}-{}.tar.gz", self.lldb_release, target)
         } else {
             format!("{}-{}-{}.tar.gz", component, self.rust_release, target)
         }
@@ -512,6 +531,8 @@ fn cached_version(&self, component: &str) -> &Option<String> {
             &self.rustfmt_version
         } else if component == "llvm-tools" || component == "llvm-tools-preview" {
             &self.llvm_tools_version
+        } else if component == "lldb" || component == "lldb-preview" {
+            &self.lldb_version
         } else {
             &self.rust_version
         }
@@ -528,6 +549,8 @@ fn cached_git_commit_hash(&self, component: &str) -> &Option<String> {
             &self.rustfmt_git_commit_hash
         } else if component == "llvm-tools" || component == "llvm-tools-preview" {
             &self.llvm_tools_git_commit_hash
+        } else if component == "lldb" || component == "lldb-preview" {
+            &self.lldb_git_commit_hash
         } else {
             &self.rust_git_commit_hash
         }
index b42488270ed29d73445d6c81d303b6a7476f6bb1..6a7672ef5344c1bb570610f2574250fbee932355 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b42488270ed29d73445d6c81d303b6a7476f6bb1
+Subproject commit 6a7672ef5344c1bb570610f2574250fbee932355
diff --git a/src/tools/clang b/src/tools/clang
new file mode 160000 (submodule)
index 0000000..2a284a7
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 2a284a70e26997273c296afe06586ffdf3a142fd
index 99a087bea59c8f808b5485c6113edf9ce774e94a..bac76afb5a7885de19bfd9e6191fe8e2a29bd74d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 99a087bea59c8f808b5485c6113edf9ce774e94a
+Subproject commit bac76afb5a7885de19bfd9e6191fe8e2a29bd74d
index 201a661726e9179940849bc4dca2126aeca410c6..58220ba992c7a28b7e40637c4a0807b10827b5fc 100644 (file)
@@ -82,7 +82,7 @@ pub fn extract_rendered(output: &str, proc_res: &ProcRes) -> String {
                     Err(error) => {
                         proc_res.fatal(Some(&format!(
                             "failed to decode compiler output as json: \
-                             `{}`\noutput: {}\nline: {}",
+                             `{}`\nline: {}\noutput: {}",
                             error, line, output
                         )));
                     }
@@ -114,7 +114,7 @@ fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) ->
             Err(error) => {
                 proc_res.fatal(Some(&format!(
                     "failed to decode compiler output as json: \
-                     `{}`\noutput: {}\nline: {}",
+                     `{}`\nline: {}\noutput: {}",
                     error, line, output
                 )));
             }
diff --git a/src/tools/lldb b/src/tools/lldb
new file mode 160000 (submodule)
index 0000000..3dbe998
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 3dbe998969d457c5cef245f61b48bdaed0f5c059
index 89414e44dc94844888e59c08bc31dcccb1792800..27dec6cae3a8132d8a073aad6775425c85095c99 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 89414e44dc94844888e59c08bc31dcccb1792800
+Subproject commit 27dec6cae3a8132d8a073aad6775425c85095c99
index 85254c6abb599f5de090e35608ebb3dfddf5813d..f2107f92debd2d915bcc01779f698bb3d9996d02 100644 (file)
@@ -68,12 +68,14 @@ fn filter_dirs(path: &Path) -> bool {
         "src/vendor",
         "src/rt/hoedown",
         "src/tools/cargo",
+        "src/tools/clang",
         "src/tools/rls",
         "src/tools/clippy",
         "src/tools/rust-installer",
         "src/tools/rustfmt",
         "src/tools/miri",
         "src/tools/lld",
+        "src/tools/lldb",
         "src/librustc/mir/interpret",
         "src/librustc_mir/interpret",
         "src/target",