[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
- 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
# 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
- 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
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 &&
# 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
"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)",
"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)",
"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)",
"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)",
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)",
]
"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)",
"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)",
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"
[[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)",
]
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)",
]
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)",
[[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)",
"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)",
]
"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)",
]
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"
[[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]]
[[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)",
"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]]
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)",
]
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)",
]
"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"
"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"
"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"
"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"
"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"
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)
dist::Rustfmt,
dist::Clippy,
dist::LlvmTools,
+ dist::Lldb,
dist::Extended,
dist::HashSign
),
pub llvm_link_jobs: Option<u32>,
pub lld_enabled: bool,
+ pub lldb_enabled: bool,
pub llvm_tools_enabled: bool,
// rust codegen options
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>,
}
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();
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.
# 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 configured target, so there's a bit of special handling for that here.
sections = {}
cur_section = None
sections[None] = []
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())
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),
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 {
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));
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)))
+ }
+}
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;
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.
///
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
.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);
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
//
// 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++");
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());
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:
|
= 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`
+```
/// # 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 {
/// # 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 {
///
/// [`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) }
/// [`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>,
}
}
-#[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>,
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>
}
}
-#[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>
}
}
-#[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> {}
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
+#[allow_internal_unstable]
macro_rules! writeln {
($dst:expr) => (
write!($dst, "\n")
($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)*))
);
}
--- /dev/null
+// 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()
+}
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;
--- /dev/null
+// 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)*
+ }
+}
+++ /dev/null
-// 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()
-}
pub mod borrowck;
pub mod expr_use_visitor;
pub mod cstore;
- pub mod dataflow;
pub mod dead;
pub mod dependency_format;
pub mod entry;
+++ /dev/null
-// 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 }
-}
/// 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;
/// 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:
///
/// (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)]
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 {
/// 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
binding_mode: ty::BindingMode::BindByValue(_),
opt_ty_info: _,
opt_match_place: _,
+ pat_span: _,
}))) => true,
// FIXME: might be able to thread the distinction between
binding_mode: ty::BindingMode::BindByValue(_),
opt_ty_info: _,
opt_match_place: _,
+ pat_span: _,
}))) => true,
Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf)) => true,
/// 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:
///
/// ```
/// 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 {
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,
}
}
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");
/// [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,
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 {
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
}
}
+ 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)),
}
}
}
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
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);
}
}
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);
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| {
&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)
}
}
}
/// 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),
}
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 |
"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 |
FnPointerCandidate |
BuiltinObjectCandidate |
BuiltinUnsizeCandidate |
- BuiltinCandidate { .. } => {
+ BuiltinCandidate { has_nested: true } => {
match victim.candidate {
ParamCandidate(ref cand) => {
// Prefer these to a global where-clause bound
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) => {
/// 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.
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,
}
dfcx_loans,
move_data,
all_loans,
- param_env,
movable_generator,
};
let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id);
use_kind,
&lp,
the_move,
- moved_lp,
- self.param_env);
+ moved_lp);
false
});
}
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 )
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,
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) {
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={:?}",
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
// 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.
}
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;
use rustc::hir;
use rustc::hir::intravisit::{self, Visitor};
+use dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom};
+
pub mod check_loans;
pub mod gather_loans;
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"),
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();
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",
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;
/// 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> {
/// 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)]
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 {
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) {
--- /dev/null
+// 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 }
+}
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;
pub mod graphviz;
+mod dataflow;
+
pub use borrowck::provide;
// 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
{
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)
}
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)),
// 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>,
},
// 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
}
fn append_to_grouped_errors(
&self,
grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
+ original_path: Place<'tcx>,
error: MoveError<'tcx>,
) {
match error {
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,
}
grouped_errors.push(GroupedMoveError::OtherIllegalMove {
span: stmt_source_info.span,
+ original_path,
kind,
});
}
&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>>,
statement_span: Span,
) {
debug!(
- "append_to_grouped_errors(match_place={:?}, match_span={:?})",
+ "append_binding_error(match_place={:?}, match_span={:?})",
match_place, match_span
);
// 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() {
} 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,
});
_ => 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,
}
}
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],
});
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 => {
// 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();
}
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
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",
+ );
}
}
}
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) => {
));
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;
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()
}) => 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;
}
};
+ 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...
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!(),
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>(
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,
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
}
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={:?})",
// 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());
binding_mode,
opt_ty_info,
opt_match_place: Some((Some(place.clone()), span)),
+ pat_span: span,
})))
};
self.var_indices.insert(var, LocalsForNode::One(local));
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> {
}
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() {
}
}
-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();
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;
}
};
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)
}
}
#![feature(try_trait)]
#![feature(unicode_internals)]
#![feature(step_trait)]
+#![feature(slice_concat_ext)]
#![recursion_limit="256"]
/// 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
}
--- /dev/null
+// 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,
+ })
+}
("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),
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);
+ }
}
}
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.
[dependencies]
pulldown-cmark = { version = "0.1.2", default-features = false }
-minifier = "0.0.14"
+minifier = "0.0.19"
tempfile = "3"
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;
}
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;
}
}
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) }
}
// 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,
}
}
/// [`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:
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;
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
}
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;
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
}
#[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;
// 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,
// 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();
}
}
impl Lit {
- fn tokens(&self) -> TokenStream {
+ crate fn tokens(&self) -> TokenStream {
TokenTree::Token(self.span, self.node.token()).into()
}
}
);
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
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)))
}) {
}
}
- 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");
}
}
}
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> {
};
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;
})
}
- 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()),
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)
})
}
if !lines.is_empty() && lines[0].chars().all(|c| c == '*') {
i += 1;
}
+
while i < j && lines[i].trim().is_empty() {
i += 1;
}
.all(|c| c == '*') {
j -= 1;
}
+
while j > i && lines[j - 1].trim().is_empty() {
j -= 1;
}
+
lines[i..j].to_vec()
}
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) {
}
// 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();
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() {
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) {
"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();
// 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);
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.
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,
}
}
}
+
+ 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 {
_ => 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();
}
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 {
}
/// 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));
}
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
}
sr.emit_fatal_errors();
FatalError.raise();
}
+
sr
}
+ #[inline]
fn ch_is(&self, c: char) -> bool {
self.ch == Some(c)
}
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[..])
}
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[..])
}
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[..])
}
};
}
}
+
Ok(())
}
}
}
+ #[inline]
fn nextch_is(&self, c: char) -> bool {
self.nextch() == Some(c)
}
None
}
+ #[inline]
fn nextnextch_is(&self, c: char) -> bool {
self.nextnextch() == Some(c)
}
if !ident_start(self.ch) {
return None;
}
+
let start = self.pos;
self.bump();
+
while ident_continue(self.ch) {
self.bump();
}
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('_') {
/// 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
}
}
} 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"));
}
}
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
first_source_char: char,
ascii_only: bool,
delim: char)
- -> bool {
+ -> bool
+ {
match first_source_char {
'\\' => {
// '\X' for some X must be a character constant:
"overlong unicode escape (must have at most 6 hex digits)");
valid = false;
}
+
loop {
match self.ch {
Some('}') => {
}
self.bump();
}
+
valid
}
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,
('b', Some('r'), Some('#')) => (false, false),
_ => (true, false),
};
+
if is_ident_start {
let raw_start = self.pos;
if is_raw_ident {
let start = self.pos;
self.bump();
+
while ident_continue(self.ch) {
self.bump();
}
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)
}));
}
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('\'') {
break;
}
}
+
self.fatal_span_verbose(start_with_quote, pos,
String::from("character literal may only contain one codepoint")).raise();
}
} 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' => {
_ => 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;
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 {
};
self.bump();
let suffix = self.scan_optional_raw_name();
+
Ok(token::Literal(token::Str_(id), suffix))
}
'r' => {
}
self.bump();
}
+
self.bump();
let id = if valid {
self.name_from_to(content_start_bpos, content_end_bpos)
Symbol::intern("??")
};
let suffix = self.scan_optional_raw_name();
+
Ok(token::Literal(token::StrRaw(id, hash_count), suffix))
}
'-' => {
c);
unicode_chars::check_for_substitution(self, c, &mut err);
self.fatal_errs.push(err);
+
Err(())
}
}
val.push(self.ch.unwrap());
self.bump();
}
+
if self.ch_is('\n') {
self.bump();
}
+
val
}
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)
}
true,
'"');
}
+
let id = if valid {
self.name_from(start)
} else {
Symbol::intern("??")
};
self.bump();
+
token::ByteStr(id)
}
}
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')
}
// 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))
}
if let token::CloseDelim(..) = self.token {
return TokenStream::concat(tts);
}
+
match self.parse_token_tree() {
Ok(tree) => tts.push(tree),
Err(mut e) => {
for &(_, sp) in &self.open_braces {
err.span_help(sp, "did you mean to close this delimiter?");
}
+
Err(err)
},
token::OpenDelim(delim) => {
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() })
}
}
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", ' '),
///
/// 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
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
//
// 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);
/// 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)]
#![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
#[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() {}
#[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
--- /dev/null
+// 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 {}
--- /dev/null
+// 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 {}
// 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 {}
#[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()
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
--- /dev/null
+// 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";
+ };
+}
--- /dev/null
+// 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() {
+}
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() {
}
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`
-fn main ( ) { let y : u32 = "z" ; let x : u32 = "y" ; }
+fn main ( ) { let y : u32 = "z" ; { let x : u32 = "y" ; } }
--- /dev/null
+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`.
| ^^^^^^^^
| |
| 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
--- /dev/null
+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`.
--> $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
--- /dev/null
+// 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() {}
--> $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
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
| ^^
| |
| cannot move out of borrowed content
- | help: consider removing this dereference operator: `y`
+ | help: consider removing the `*`: `y`
error: aborting due to previous error
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
| ^^
| |
| 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
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
| ^^^
| |
| 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
| ^^
| |
| cannot move out of borrowed content
- | help: consider using a reference instead: `&*x`
+ | help: consider removing the `*`: `x`
error: aborting due to previous error
| ^--
| ||
| |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
| ^--
| ||
| |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
| ^--
| ||
| |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
| ^--
| ||
| |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
--- /dev/null
+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`.
| ^^^^^^^^^^^^^^^^^^^^^^^^^ 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
| -- ^^^^^^^^^^^^^^^^^^^^^^^ 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
| ^^^^^--^
| | |
| | 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
| ^^^^^^^^^^^^^^^^^^^^^^^^^ 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
| -- ^^^^^^^^^^^^^^^^^^^^^^^ 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
| ^^^^^--^
| | |
| | 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
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
| -- ^^^^^^^^^^^^^^^^^^^^ 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
| ^^--^
| | |
| | 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
| - 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
| ^^^^
| |
| 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
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
| ^^^^^^
| |
| 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
| ^^^ 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
| ^^^^^^
| |
| 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
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
| ^^^^^^
| |
| 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
| ^^^^^-^
| | |
| | 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
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
| ^^^^ 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
| ^
| |
| 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
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
| - ^ 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
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
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
--- /dev/null
+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`.
--- /dev/null
+// 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;
+ }
+}
--- /dev/null
+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
+
| -- 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
| -- 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
--- /dev/null
+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`.
| ^^^^^^^^^^
| |
| 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
| ^^^^^^^^^^
| |
| 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
| ^^^^^^^^^^
| |
| 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
| ^^^^^^^^^^^^
| |
| 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
= 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
| ^^^^^^
| |
| 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
| - - ^^^^
| | | |
| | | 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
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
--- /dev/null
+// 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
+}
--- /dev/null
+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
+
// 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() { }
-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`.
// 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.
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
| ^^^^^^^^^
= 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
| ^^^^^^^
| ^^^^^
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
| ^^^^^^^^^^^^^^^^^^^^^^^
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
| ^^^^^^^^^^^^
| |
| 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
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
| ^^
| |
| 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
| ^^
| |
| 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
| ^^
| |
| 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
| ^^^^^^
| |
| 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
| ^^^^^^
| |
| 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
| ^^^^^^
| |
| 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
| ^^
| |
| 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
| ^^
| |
| 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
| ^^
| |
| 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
--- /dev/null
+// 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]
+ }
+}
--- /dev/null
+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`.
| ^^
| |
| 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
| ^^^^
| |
| 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
| ^^^
| |
| 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
| ^^
| |
| 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
| ^^^^^^^^^^^^^^^^^^^^^^
| |
| 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
| - ^^
| | |
| | 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
| - ^ 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
| ^^^^
| |
| 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
| ^ 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
| ^ 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
| ^ 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
| ^ 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
| ^^
| |
| 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
{}
#[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>
{}
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}>`"]
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
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
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
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
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
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
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
--- /dev/null
+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`.
--- /dev/null
+// 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))
+}
--- /dev/null
+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`.
--- /dev/null
+// 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
+ }
+ });
+}
--- /dev/null
+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`.
--- /dev/null
+// 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) => (),
+ }
+}
--- /dev/null
+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`.
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
--- /dev/null
+// 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() {}
clippy_release: String,
rustfmt_release: String,
llvm_tools_release: String,
+ lldb_release: String,
input: PathBuf,
output: PathBuf,
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>,
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() {
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));
clippy_release,
rustfmt_release,
llvm_tools_release,
+ lldb_release,
input,
output,
clippy_version: None,
rustfmt_version: None,
llvm_tools_version: None,
+ lldb_version: None,
rust_git_commit_hash: None,
cargo_git_commit_hash: None,
clippy_git_commit_hash: None,
rustfmt_git_commit_hash: None,
llvm_tools_git_commit_hash: None,
+ lldb_git_commit_hash: None,
}.build();
}
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");
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();
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() });
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(),
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)
}
&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
}
&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
}
-Subproject commit b42488270ed29d73445d6c81d303b6a7476f6bb1
+Subproject commit 6a7672ef5344c1bb570610f2574250fbee932355
--- /dev/null
+Subproject commit 2a284a70e26997273c296afe06586ffdf3a142fd
-Subproject commit 99a087bea59c8f808b5485c6113edf9ce774e94a
+Subproject commit bac76afb5a7885de19bfd9e6191fe8e2a29bd74d
Err(error) => {
proc_res.fatal(Some(&format!(
"failed to decode compiler output as json: \
- `{}`\noutput: {}\nline: {}",
+ `{}`\nline: {}\noutput: {}",
error, line, output
)));
}
Err(error) => {
proc_res.fatal(Some(&format!(
"failed to decode compiler output as json: \
- `{}`\noutput: {}\nline: {}",
+ `{}`\nline: {}\noutput: {}",
error, line, output
)));
}
--- /dev/null
+Subproject commit 3dbe998969d457c5cef245f61b48bdaed0f5c059
-Subproject commit 89414e44dc94844888e59c08bc31dcccb1792800
+Subproject commit 27dec6cae3a8132d8a073aad6775425c85095c99
"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",