jobs:
- job: Linux
+ timeoutInMinutes: 600
pool:
vmImage: ubuntu-16.04
steps:
IMAGE: mingw-check
- job: macOS
+ timeoutInMinutes: 600
pool:
vmImage: macos-10.13
steps:
- - checkout: self
- fetchDepth: 2
- template: steps/run.yml
strategy:
matrix:
- job: Windows
+ timeoutInMinutes: 600
pool:
vmImage: 'vs2017-win2016'
steps:
.project
.settings/
.valgrindrc
-.vscode/
+.vscode
.favorites.json
/*-*-*-*/
/*-*-*/
#
Aaron Todd <github@opprobrio.us>
-Aaron Power <theaaronepower@gmail.com>
+Aaron Power <theaaronepower@gmail.com> Erin Power <xampprocky@gmail.com>
Abhishek Chanda <abhishek.becs@gmail.com> Abhishek Chanda <abhishek@cloudscaling.com>
Adolfo Ochagavía <aochagavia92@gmail.com>
Adrien Tétar <adri-from-59@hotmail.fr>
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "autocfg"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "backtrace"
-version = "0.3.11"
+version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
+ "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"backtrace-sys 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "compiler_builtins 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-std-workspace-core 1.0.0",
]
[[package]]
[[package]]
name = "cargo"
-version = "0.37.0"
+version = "0.38.0"
dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "crates-io 0.25.0",
+ "crates-io 0.26.0",
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"curl 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "im-rc 12.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "im-rc 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
"shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strip-ansi-escapes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tar 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "cfg-if"
-version = "0.1.6"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "compiler_builtins 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-std-workspace-core 1.0.0",
+]
[[package]]
name = "chalk-engine"
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-workspace-hack 1.0.0",
- "rustc_tools_util 0.1.1",
+ "rustc_tools_util 0.2.0",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.0.212"
dependencies = [
"cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "if_chain 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "crates-io"
-version = "0.25.0"
+version = "0.26.0"
dependencies = [
"curl 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "if_chain"
-version = "0.1.3"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
[[package]]
name = "im-rc"
-version = "12.3.0"
+version = "13.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sized-chunks 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (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.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rls"
version = "1.36.0"
dependencies = [
- "cargo 0.37.0",
+ "cargo 0.38.0",
"cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy_lints 0.0.212",
"crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.0.0"
dependencies = [
"arena 0.0.0",
- "backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"chalk-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
version = "407.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ena 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
version = "407.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-ap-arena 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-ap-rustc_data_structures 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-ap-serialize 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
name = "rustc_data_structures"
version = "0.0.0"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"graphviz 0.0.0",
"jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_cratesio_shim 0.0.0",
"rustc_data_structures 0.0.0",
"serialize 0.0.0",
+ "syntax_pos 0.0.0",
]
[[package]]
name = "rustc_tools_util"
version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc_tools_util"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+version = "0.2.0"
[[package]]
name = "rustc_traits"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "sized-chunks"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "slab"
version = "0.4.2"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.0.0"
dependencies = [
"alloc 0.0.0",
- "backtrace-sys 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"core 0.0.0",
"panic_unwind 0.0.0",
"profiler_builtins 0.0.0",
"rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_asan 0.0.0",
"rustc_lsan 0.0.0",
"rustc_msan 0.0.0",
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "strip-ansi-escapes"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "strsim"
version = "0.7.0"
version = "0.0.0"
dependencies = [
"arena 0.0.0",
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_data_structures 0.0.0",
"rustc_macros 0.1.0",
"scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
version = "3.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "utf8parse"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "vcpkg"
version = "0.2.6"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "vte"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "wait-timeout"
version = "0.1.5"
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
-"checksum backtrace 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "18b65ea1161bfb2dd6da6fade5edd4dbd08fba85012123dd333d2fd1b90b2782"
+"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
+"checksum backtrace 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)" = "1c50b4cb6d852a8567d98bb11c03f91ccec4dfbd88778bc1b92789c624081283"
"checksum backtrace-sys 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "6ea90dd7b012b3d1a2cb6bec16670a0db2c95d4e931e84f4047e0460c1b34c8d"
"checksum bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1efcc46c18245a69c38fcc5cc650f16d3a59d034f3106e9ed63748f695730a"
"checksum bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4440d5cb623bb7390ae27fec0bb6c61111969860f8e3ae198bfa0663645e67cf"
"checksum bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010"
"checksum cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "585784cac9b05c93a53b17a0b24a5cdd1dfdda5256f030e089b549d2390cc720"
"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83"
-"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
+"checksum cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "89431bba4e6b7092fb5fcd00a6f6ca596c55cc26b2f1e6dcdd08a1f4933f66b2"
"checksum chalk-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17ec698a6f053a23bfbe646d9f2fde4b02abc19125595270a99e6f44ae0bdd1a"
"checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e"
"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
"checksum http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fe67e3678f2827030e89cc4b9e7ecd16d52f132c0b940ab5005f88e821500f6a"
"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
-"checksum if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4bac95d9aa0624e7b78187d6fb8ab012b41d9f6f54b1bcb61e61c4845f8357ec"
+"checksum if_chain 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c3360c7b59e5ffa2653671fb74b4741a5d343c03f331c0a4aeda42b5c2b0ec7d"
"checksum ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8dc57fa12805f367736a38541ac1a9fc6a52812a0ca959b1d4d4b640a89eb002"
-"checksum im-rc 12.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9460397452f537fd51808056ff209f4c4c4c9d20d42ae952f517708726284972"
+"checksum im-rc 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0197597d095c0d11107975d3175173f810ee572c2501ff4de64f4f3f119806"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053"
"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450"
"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
"checksum signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f272d1b7586bec132ed427f532dd418d8beca1ca7f2caf7df35569b1415a4b4"
"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
+"checksum sized-chunks 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2a2eb3fe454976eefb479f78f9b394d34d661b647c6326a3a6e66f68bb12c26"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db"
"checksum socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7"
"checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423"
"checksum string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eea1eee654ef80933142157fdad9dd8bc43cf7c74e999e369263496f04ff4da"
"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
+"checksum strip-ansi-escapes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d63676e2abafa709460982ddc02a3bb586b6d15a49b75c212e06edd3933acee"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum strum 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c3a2071519ab6a48f465808c4c1ffdd00dfc8e93111d02b4fc5abab177676e"
"checksum strum_macros 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8baacebd7b7c9b864d83a6ba7a246232983e277b86fa5cdec77f565715a4b136"
"checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea"
"checksum utf-8 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1262dfab4c30d5cb7c07026be00ee343a6cf5027fdc0104a9160f354e5db75c"
"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
+"checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
"checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+"checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf"
"checksum wait-timeout 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b9f3bf741a801531993db6478b95682117471f76916f5e690dd8d45395b09349"
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
[Visual Studio Build Tools]: https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019
-At last check (cmake 3.14.3 and msvc 16.0.3) using the 2019 tools fails to
-build the in-tree LLVM build with a CMake error, so use 2017 instead by
-including the “MSVC v141 – VS 2017 C++ x64/x86 build tools (v14.16)” component.
+(If you're installing cmake yourself, be careful that “C++ CMake tools for
+Windows” doesn't get included under “Individual components”.)
With these dependencies installed, you can build the compiler in a `cmd.exe`
shell with:
by manually calling the appropriate vcvars file before running the bootstrap.
```batch
-> CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat"
+> CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars64.bat"
> python x.py build
```
produce a warning if their returning type is unused.
- [The methods `checked_pow`, `saturating_pow`, `wrapping_pow`, and
`overflowing_pow` are now available for all numeric types.][57873] These are
- equivalvent to methods such as `wrapping_add` for the `pow` operation.
+ equivalent to methods such as `wrapping_add` for the `pow` operation.
Stabilized APIs
DEPLOY: 1
- CI_JOB_NAME: dist-i686-mingw
MSYS_BITS: 32
- RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools
+ RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler
SCRIPT: python x.py dist
MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
- CI_JOB_NAME: dist-x86_64-mingw
MSYS_BITS: 64
SCRIPT: python x.py dist
- RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools
+ RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler
MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
MINGW_DIR: mingw64
pub enum Kind {
Build,
Check,
+ Clippy,
+ Fix,
Test,
Bench,
Dist,
tool::Miri,
native::Lld
),
- Kind::Check => describe!(
+ Kind::Check | Kind::Clippy | Kind::Fix => describe!(
check::Std,
check::Test,
check::Rustc,
let (kind, paths) = match build.config.cmd {
Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
Subcommand::Check { ref paths } => (Kind::Check, &paths[..]),
+ Subcommand::Clippy { ref paths } => (Kind::Clippy, &paths[..]),
+ Subcommand::Fix { ref paths } => (Kind::Fix, &paths[..]),
Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]),
Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
};
let libstd_stamp = match cmd {
- "check" => check::libstd_stamp(self, cmp, target),
+ "check" | "clippy" | "fix" => check::libstd_stamp(self, cmp, target),
_ => compile::libstd_stamp(self, cmp, target),
};
let libtest_stamp = match cmd {
- "check" => check::libtest_stamp(self, cmp, target),
+ "check" | "clippy" | "fix" => check::libtest_stamp(self, cmp, target),
_ => compile::libstd_stamp(self, cmp, target),
};
let librustc_stamp = match cmd {
- "check" => check::librustc_stamp(self, cmp, target),
+ "check" | "clippy" | "fix" => check::librustc_stamp(self, cmp, target),
_ => compile::librustc_stamp(self, cmp, target),
};
assert_eq!(target, compiler.host);
}
- // Set a flag for `check` so that certain build scripts can do less work
- // (e.g., not building/requiring LLVM).
- if cmd == "check" {
+ // Set a flag for `check`/`clippy`/`fix`, so that certain build
+ // scripts can do less work (e.g. not building/requiring LLVM).
+ if cmd == "check" || cmd == "clippy" || cmd == "fix" {
cargo.env("RUST_CHECK", "1");
}
extra_args.push_str(&s);
}
+ if cmd == "clippy" {
+ extra_args.push_str("-Zforce-unstable-if-unmarked -Zunstable-options \
+ --json-rendered=termcolor");
+ }
+
if !extra_args.is_empty() {
cargo.env(
"RUSTFLAGS",
if let Some(ref error_format) = self.config.rustc_error_format {
cargo.env("RUSTC_ERROR_FORMAT", error_format);
}
- if cmd != "build" && cmd != "check" && cmd != "rustc" && want_rustdoc {
+ if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc {
cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler));
}
use crate::Build;
// The version number
-pub const CFG_RELEASE_NUM: &str = "1.36.0";
+pub const CFG_RELEASE_NUM: &str = "1.37.0";
pub struct GitInfo {
inner: Option<Info>,
-//! Implementation of compiling the compiler and standard library, in "check" mode.
+//! Implementation of compiling the compiler and standard library, in "check"-based modes.
use crate::compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, rustc_cargo_env,
add_to_sysroot};
-use crate::builder::{RunConfig, Builder, ShouldRun, Step};
+use crate::builder::{RunConfig, Builder, Kind, ShouldRun, Step};
use crate::tool::{prepare_tool_cargo, SourceType};
use crate::{Compiler, Mode};
use crate::cache::{INTERNER, Interned};
pub target: Interned<String>,
}
+fn args(kind: Kind) -> Vec<String> {
+ match kind {
+ Kind::Clippy => vec!["--".to_owned(), "--cap-lints".to_owned(), "warn".to_owned()],
+ _ => Vec::new()
+ }
+}
+
+fn cargo_subcommand(kind: Kind) -> &'static str {
+ match kind {
+ Kind::Check => "check",
+ Kind::Clippy => "clippy",
+ Kind::Fix => "fix",
+ _ => unreachable!()
+ }
+}
+
impl Step for Std {
type Output = ();
const DEFAULT: bool = true;
let target = self.target;
let compiler = builder.compiler(0, builder.config.build);
- let mut cargo = builder.cargo(compiler, Mode::Std, target, "check");
+ let mut cargo = builder.cargo(compiler, Mode::Std, target, cargo_subcommand(builder.kind));
std_cargo(builder, &compiler, target, &mut cargo);
let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage));
builder.info(&format!("Checking std artifacts ({} -> {})", &compiler.host, target));
run_cargo(builder,
&mut cargo,
+ args(builder.kind),
&libstd_stamp(builder, compiler, target),
true);
builder.ensure(Test { target });
- let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "check");
+ let mut cargo = builder.cargo(compiler, Mode::Rustc, target,
+ cargo_subcommand(builder.kind));
rustc_cargo(builder, &mut cargo);
let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage));
builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target));
run_cargo(builder,
&mut cargo,
+ args(builder.kind),
&librustc_stamp(builder, compiler, target),
true);
builder.ensure(Rustc { target });
- let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "check");
+ let mut cargo = builder.cargo(compiler, Mode::Codegen, target,
+ cargo_subcommand(builder.kind));
cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml"));
rustc_cargo_env(builder, &mut cargo);
let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage));
run_cargo(builder,
&mut cargo,
+ args(builder.kind),
&codegen_backend_stamp(builder, compiler, target, backend),
true);
}
builder.ensure(Std { target });
- let mut cargo = builder.cargo(compiler, Mode::Test, target, "check");
+ let mut cargo = builder.cargo(compiler, Mode::Test, target, cargo_subcommand(builder.kind));
test_cargo(builder, &compiler, target, &mut cargo);
let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage));
builder.info(&format!("Checking test artifacts ({} -> {})", &compiler.host, target));
run_cargo(builder,
&mut cargo,
+ args(builder.kind),
&libtest_stamp(builder, compiler, target),
true);
compiler,
Mode::ToolRustc,
target,
- "check",
+ cargo_subcommand(builder.kind),
"src/tools/rustdoc",
SourceType::InTree,
&[]);
println!("Checking rustdoc artifacts ({} -> {})", &compiler.host, target);
run_cargo(builder,
&mut cargo,
+ args(builder.kind),
&rustdoc_stamp(builder, compiler, target),
true);
&compiler.host, target));
run_cargo(builder,
&mut cargo,
+ vec![],
&libstd_stamp(builder, compiler, target),
false);
&compiler.host, target));
run_cargo(builder,
&mut cargo,
+ vec![],
&libtest_stamp(builder, compiler, target),
false);
compiler.stage, &compiler.host, target));
run_cargo(builder,
&mut cargo,
+ vec![],
&librustc_stamp(builder, compiler, target),
false);
let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage));
let files = run_cargo(builder,
cargo.arg("--features").arg(features),
+ vec![],
&tmp_stamp,
false);
if builder.config.dry_run {
pub fn run_cargo(builder: &Builder<'_>,
cargo: &mut Command,
+ tail_args: Vec<String>,
stamp: &Path,
is_check: bool)
-> Vec<PathBuf>
// files we need to probe for later.
let mut deps = Vec::new();
let mut toplevel = Vec::new();
- let ok = stream_cargo(builder, cargo, &mut |msg| {
+ let ok = stream_cargo(builder, cargo, tail_args, &mut |msg| {
let (filenames, crate_types) = match msg {
CargoMessage::CompilerArtifact {
filenames,
},
..
} => (filenames, crate_types),
+ CargoMessage::CompilerMessage { message } => {
+ eprintln!("{}", message.rendered);
+ return;
+ }
_ => return,
};
for filename in filenames {
pub fn stream_cargo(
builder: &Builder<'_>,
cargo: &mut Command,
+ tail_args: Vec<String>,
cb: &mut dyn FnMut(CargoMessage<'_>),
) -> bool {
if builder.config.dry_run {
cargo.arg("--message-format").arg("json")
.stdout(Stdio::piped());
+ for arg in tail_args {
+ cargo.arg(arg);
+ }
+
builder.verbose(&format!("running: {:?}", cargo));
let mut child = match cargo.spawn() {
Ok(child) => child,
},
BuildScriptExecuted {
package_id: Cow<'a, str>,
+ },
+ CompilerMessage {
+ message: ClippyMessage<'a>
}
}
+
+#[derive(Deserialize)]
+pub struct ClippyMessage<'a> {
+ rendered: Cow<'a, str>,
+}
Check {
paths: Vec<PathBuf>,
},
+ Clippy {
+ paths: Vec<PathBuf>,
+ },
+ Fix {
+ paths: Vec<PathBuf>,
+ },
Doc {
paths: Vec<PathBuf>,
},
Subcommands:
build Compile either the compiler or libraries
check Compile either the compiler or libraries, using cargo check
+ clippy Run clippy
+ fix Run cargo fix
test Build and run some test suites
bench Build and run some benchmarks
doc Build documentation
let subcommand = args.iter().find(|&s| {
(s == "build")
|| (s == "check")
+ || (s == "clippy")
+ || (s == "fix")
|| (s == "test")
|| (s == "bench")
|| (s == "doc")
the compiler.",
);
}
+ "clippy" => {
+ subcommand_help.push_str(
+ "\n
+Arguments:
+ This subcommand accepts a number of paths to directories to the crates
+ and/or artifacts to run clippy against. For example:
+
+ ./x.py clippy src/libcore
+ ./x.py clippy src/libcore src/libproc_macro",
+ );
+ }
+ "fix" => {
+ subcommand_help.push_str(
+ "\n
+Arguments:
+ This subcommand accepts a number of paths to directories to the crates
+ and/or artifacts to run `cargo fix` against. For example:
+
+ ./x.py fix src/libcore
+ ./x.py fix src/libcore src/libproc_macro",
+ );
+ }
"test" => {
subcommand_help.push_str(
"\n
let cmd = match subcommand.as_str() {
"build" => Subcommand::Build { paths },
"check" => Subcommand::Check { paths },
+ "clippy" => Subcommand::Clippy { paths },
+ "fix" => Subcommand::Fix { paths },
"test" => Subcommand::Test {
paths,
bless: matches.opt_present("bless"),
cfg.define("LLVM_BUILD_32_BITS", "ON");
}
+ let mut enabled_llvm_projects = Vec::new();
+
+ if util::forcing_clang_based_tests() {
+ enabled_llvm_projects.push("clang");
+ enabled_llvm_projects.push("compiler-rt");
+ }
+
if want_lldb {
- cfg.define("LLVM_ENABLE_PROJECTS", "clang;lldb");
+ enabled_llvm_projects.push("clang");
+ enabled_llvm_projects.push("lldb");
// For the time being, disable code signing.
cfg.define("LLDB_CODESIGN_IDENTITY", "");
cfg.define("LLDB_NO_DEBUGSERVER", "ON");
cfg.define("LLVM_ENABLE_LIBXML2", "OFF");
}
+ if enabled_llvm_projects.len() > 0 {
+ enabled_llvm_projects.sort();
+ enabled_llvm_projects.dedup();
+ cfg.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects.join(";"));
+ }
+
if let Some(num_linkers) = builder.config.llvm_link_jobs {
if num_linkers > 0 {
cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string());
}
}
- if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") {
- match &var.to_string_lossy().to_lowercase()[..] {
- "1" | "yes" | "on" => {
- assert!(builder.config.lldb_enabled,
- "RUSTBUILD_FORCE_CLANG_BASED_TESTS needs Clang/LLDB to \
- be built.");
- let clang_exe = builder.llvm_out(target).join("bin").join("clang");
- cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
- }
- "0" | "no" | "off" => {
- // Nothing to do.
- }
- other => {
- // Let's make sure typos don't get unnoticed
- panic!("Unrecognized option '{}' set in \
- RUSTBUILD_FORCE_CLANG_BASED_TESTS", other);
- }
- }
+ if util::forcing_clang_based_tests() {
+ let clang_exe = builder.llvm_out(target).join("bin").join("clang");
+ cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
}
// Get paths from cmd args
let _folder = builder.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target));
let mut duplicates = Vec::new();
- let is_expected = compile::stream_cargo(builder, &mut cargo, &mut |msg| {
+ let is_expected = compile::stream_cargo(builder, &mut cargo, vec![], &mut |msg| {
// Only care about big things like the RLS/Cargo for now
match tool {
| "rls"
}
}
}
+
+pub fn forcing_clang_based_tests() -> bool {
+ if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") {
+ match &var.to_string_lossy().to_lowercase()[..] {
+ "1" | "yes" | "on" => true,
+ "0" | "no" | "off" => false,
+ other => {
+ // Let's make sure typos don't go unnoticed
+ panic!("Unrecognized option '{}' set in \
+ RUSTBUILD_FORCE_CLANG_BASED_TESTS", other)
+ }
+ }
+ } else {
+ false
+ }
+}
CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc \
CC_sparc64_unknown_linux_gnu=sparc64-linux-gnu-gcc \
CC_x86_64_unknown_redox=x86_64-unknown-redox-gcc \
- CC_armebv7r_none_eabi=arm-none-eabi-gcc \
CC_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc \
AR_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-ar \
CXX_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-g++
check_dispatch $1 beta nomicon src/doc/nomicon
check_dispatch $1 beta reference src/doc/reference
check_dispatch $1 beta rust-by-example src/doc/rust-by-example
- # Temporarily disabled until
- # https://github.com/rust-lang/rust/issues/60459 is fixed.
- # check_dispatch $1 beta edition-guide src/doc/edition-guide
+ check_dispatch $1 beta edition-guide src/doc/edition-guide
check_dispatch $1 beta rls src/tools/rls
check_dispatch $1 beta rustfmt src/tools/rustfmt
check_dispatch $1 beta clippy-driver src/tools/clippy
Some example code that triggers this lint:
```rust
+#[allow(dead_code)]
type SendVec<T: Send> = Vec<T>;
```
This will produce:
```text
-warning: type alias is never used: `SendVec`
- --> src/main.rs:1:1
+warning: bounds on generic parameters are not enforced in type aliases
+ --> src/lib.rs:2:17
|
-1 | type SendVec<T: Send> = Vec<T>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+2 | type SendVec<T: Send> = Vec<T>;
+ | ^^^^
|
+ = note: #[warn(type_alias_bounds)] on by default
+ = help: the bound will not be checked when the type alias is used, and should be removed
```
## tyvar-behind-raw-pointer
Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere.
One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will
-not eagerly inline it as a module unless you add `#[doc(inline)}`.
+not eagerly inline it as a module unless you add `#[doc(inline)]`.
## `#[doc(hidden)]`
#[stable(feature = "box_slice_clone", since = "1.3.0")]
impl Clone for Box<str> {
fn clone(&self) -> Self {
- let len = self.len();
- let buf = RawVec::with_capacity(len);
+ // this makes a copy of the data
+ let buf: Box<[u8]> = self.as_bytes().into();
unsafe {
- ptr::copy_nonoverlapping(self.as_ptr(), buf.ptr(), len);
- from_boxed_utf8_unchecked(buf.into_box())
+ from_boxed_utf8_unchecked(buf)
}
}
}
/// println!("{:?}", boxed_slice);
/// ```
fn from(slice: &[T]) -> Box<[T]> {
- let mut boxed = unsafe { RawVec::with_capacity(slice.len()).into_box() };
- boxed.copy_from_slice(slice);
- boxed
+ let len = slice.len();
+ let buf = RawVec::with_capacity(len);
+ unsafe {
+ ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len);
+ buf.into_box()
+ }
}
}
}
}
+/// `FnBox` is deprecated and will be removed.
+/// `Box<dyn FnOnce()>` can be called directly, since Rust 1.35.0.
+///
/// `FnBox` is a version of the `FnOnce` intended for use with boxed
-/// closure objects. The idea is that where one would normally store a
-/// `Box<dyn FnOnce()>` in a data structure, you should use
+/// closure objects. The idea was that where one would normally store a
+/// `Box<dyn FnOnce()>` in a data structure, you whould use
/// `Box<dyn FnBox()>`. The two traits behave essentially the same, except
-/// that a `FnBox` closure can only be called if it is boxed. (Note
-/// that `FnBox` may be deprecated in the future if `Box<dyn FnOnce()>`
-/// closures become directly usable.)
+/// that a `FnBox` closure can only be called if it is boxed.
///
/// # Examples
///
///
/// ```
/// #![feature(fnbox)]
+/// #![allow(deprecated)]
///
/// use std::boxed::FnBox;
/// use std::collections::HashMap;
/// }
/// }
/// ```
+///
+/// In Rust 1.35.0 or later, use `FnOnce`, `FnMut`, or `Fn` instead:
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// fn make_map() -> HashMap<i32, Box<dyn FnOnce() -> i32>> {
+/// let mut map: HashMap<i32, Box<dyn FnOnce() -> i32>> = HashMap::new();
+/// map.insert(1, Box::new(|| 22));
+/// map.insert(2, Box::new(|| 44));
+/// map
+/// }
+///
+/// fn main() {
+/// let mut map = make_map();
+/// for i in &[1, 2] {
+/// let f = map.remove(&i).unwrap();
+/// assert_eq!(f(), i * 22);
+/// }
+/// }
+/// ```
#[rustc_paren_sugar]
-#[unstable(feature = "fnbox",
- reason = "will be deprecated if and when `Box<FnOnce>` becomes usable", issue = "28796")]
+#[unstable(feature = "fnbox", issue = "28796")]
+#[rustc_deprecated(reason = "use `FnOnce`, `FnMut`, or `Fn` instead", since = "1.37.0")]
pub trait FnBox<A>: FnOnce<A> {
/// Performs the call operation.
fn call_box(self: Box<Self>, args: A) -> Self::Output;
}
-#[unstable(feature = "fnbox",
- reason = "will be deprecated if and when `Box<FnOnce>` becomes usable", issue = "28796")]
+#[unstable(feature = "fnbox", issue = "28796")]
+#[rustc_deprecated(reason = "use `FnOnce`, `FnMut`, or `Fn` instead", since = "1.37.0")]
+#[allow(deprecated, deprecated_in_future)]
impl<A, F> FnBox<A> for F
where F: FnOnce<A>
{
impl<T> RawVec<T, Global> {
/// Converts the entire buffer into `Box<[T]>`.
///
- /// While it is not *strictly* Undefined Behavior to call
- /// this procedure while some of the RawVec is uninitialized,
- /// it certainly makes it trivial to trigger it.
- ///
/// Note that this will correctly reconstitute any `cap` changes
/// that may have been performed. (see description of type for details)
+ ///
+ /// # Undefined Behavior
+ ///
+ /// All elements of `RawVec<T, Global>` must be initialized. Notice that
+ /// the rules around uninitialized boxed values are not finalized yet,
+ /// but until they are, it is advisable to avoid them.
pub unsafe fn into_box(self) -> Box<[T]> {
// NOTE: not calling `cap()` here, actually using the real `cap` field!
let slice = slice::from_raw_parts_mut(self.ptr(), self.cap);
}
}
+
+#[test]
+fn test_stable_push_pop() {
+ // Test that, if we reserved enough space, adding and removing elements does not
+ // invalidate references into the vector (such as `v0`). This test also
+ // runs in Miri, which would detect such problems.
+ let mut v = Vec::with_capacity(10);
+ v.push(13);
+
+ // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
+ let v0 = unsafe { &*(&v[0] as *const _) };
+
+ // Now do a bunch of things and occasionally use `v0` again to assert it is still valid.
+ v.push(1);
+ v.push(2);
+ v.insert(1, 1);
+ assert_eq!(*v0, 13);
+ v.remove(1);
+ v.pop().unwrap();
+ assert_eq!(*v0, 13);
+}
self
}
+ /// Returns a raw pointer to the vector's buffer.
+ ///
+ /// The caller must ensure that the vector outlives the pointer this
+ /// function returns, or else it will end up pointing to garbage.
+ /// Modifying the vector may cause its buffer to be reallocated,
+ /// which would also make any pointers to it invalid.
+ ///
+ /// The caller must also ensure that the memory the pointer (non-transitively) points to
+ /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
+ /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = vec![1, 2, 4];
+ /// let x_ptr = x.as_ptr();
+ ///
+ /// unsafe {
+ /// for i in 0..x.len() {
+ /// assert_eq!(*x_ptr.add(i), 1 << i);
+ /// }
+ /// }
+ /// ```
+ ///
+ /// [`as_mut_ptr`]: #method.as_mut_ptr
+ #[stable(feature = "vec_as_ptr", since = "1.37.0")]
+ #[inline]
+ pub fn as_ptr(&self) -> *const T {
+ // We shadow the slice method of the same name to avoid going through
+ // `deref`, which creates an intermediate reference.
+ let ptr = self.buf.ptr();
+ unsafe { assume(!ptr.is_null()); }
+ ptr
+ }
+
+ /// Returns an unsafe mutable pointer to the vector's buffer.
+ ///
+ /// The caller must ensure that the vector outlives the pointer this
+ /// function returns, or else it will end up pointing to garbage.
+ /// Modifying the vector may cause its buffer to be reallocated,
+ /// which would also make any pointers to it invalid.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// // Allocate vector big enough for 4 elements.
+ /// let size = 4;
+ /// let mut x: Vec<i32> = Vec::with_capacity(size);
+ /// let x_ptr = x.as_mut_ptr();
+ ///
+ /// // Initialize elements via raw pointer writes, then set length.
+ /// unsafe {
+ /// for i in 0..size {
+ /// *x_ptr.add(i) = i as i32;
+ /// }
+ /// x.set_len(size);
+ /// }
+ /// assert_eq!(&*x, &[0,1,2,3]);
+ /// ```
+ #[stable(feature = "vec_as_ptr", since = "1.37.0")]
+ #[inline]
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ // We shadow the slice method of the same name to avoid going through
+ // `deref_mut`, which creates an intermediate reference.
+ let ptr = self.buf.ptr();
+ unsafe { assume(!ptr.is_null()); }
+ ptr
+ }
+
/// Forces the length of the vector to `new_len`.
///
/// This is a low-level operation that maintains none of the normal
fn deref(&self) -> &[T] {
unsafe {
- let p = self.buf.ptr();
- assume(!p.is_null());
- slice::from_raw_parts(p, self.len)
+ slice::from_raw_parts(self.as_ptr(), self.len)
}
}
}
impl<T> ops::DerefMut for Vec<T> {
fn deref_mut(&mut self) -> &mut [T] {
unsafe {
- let ptr = self.buf.ptr();
- assume(!ptr.is_null());
- slice::from_raw_parts_mut(ptr, self.len)
+ slice::from_raw_parts_mut(self.as_mut_ptr(), self.len)
}
}
}
fn into_iter(mut self) -> IntoIter<T> {
unsafe {
let begin = self.as_mut_ptr();
- assume(!begin.is_null());
let end = if mem::size_of::<T>() == 0 {
arith_offset(begin as *const i8, self.len() as isize) as *const T
} else {
//! mutate it.
//!
//! Shareable mutable containers exist to permit mutability in a controlled manner, even in the
-//! presence of aliasing. Both `Cell<T>` and `RefCell<T>` allows to do this in a single threaded
+//! presence of aliasing. Both `Cell<T>` and `RefCell<T>` allow doing this in a single-threaded
//! way. However, neither `Cell<T>` nor `RefCell<T>` are thread safe (they do not implement
//! `Sync`). If you need to do aliasing and mutation between multiple threads it is possible to
//! use [`Mutex`](../../std/sync/struct.Mutex.html),
/// task.
///
/// When using a future, you generally won't call `poll` directly, but instead
-/// `await!` the value.
+/// `.await` the value.
#[doc(spotlight)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[stable(feature = "futures_api", since = "1.36.0")]
//! call `next()` on your iterator, until it reaches `None`. Let's go over that
//! next.
//!
+//! Also note that `Iterator` provides a default implementation of methods such as `nth` and `fold`
+//! which call `next` internally. However, it is also possible to write a custom implementation of
+//! methods like `nth` and `fold` if an iterator can compute them more efficiently without calling
+//! `next`.
+//!
//! # for Loops and IntoIterator
//!
//! Rust's `for` loop syntax is actually sugar for iterators. Here's a basic
/// Creates an iterator that skips the first `n` elements.
///
/// After they have been consumed, the rest of the elements are yielded.
+ /// Rather than overriding this method directly, instead override the `nth` method.
///
/// # Examples
///
/// * Iterators that dynamically terminate.
///
/// If the determination that the code is unreachable proves incorrect, the
-/// program immediately terminates with a [`panic!`]. The function [`unreachable_unchecked`],
-/// which belongs to the [`std::hint`] module, informs the compiler to
-/// optimize the code out of the release version entirely.
+/// program immediately terminates with a [`panic!`].
+///
+/// The unsafe counterpart of this macro is the [`unreachable_unchecked`] function, which
+/// will cause undefined behavior if the code is reached.
///
/// [`panic!`]: ../std/macro.panic.html
/// [`unreachable_unchecked`]: ../std/hint/fn.unreachable_unchecked.html
/// out.write(vec![1, 2, 3]);
/// }
///
-/// let mut v: MaybeUninit<Vec<i32>> = MaybeUninit::uninit();
+/// let mut v = MaybeUninit::uninit();
/// unsafe { make_vec(v.as_mut_ptr()); }
/// // Now we know `v` is initialized! This also makes sure the vector gets
/// // properly dropped.
/// optimizations, potentially resulting in a larger size:
///
/// ```rust
-/// # use std::mem::{MaybeUninit, size_of, align_of};
+/// # use std::mem::{MaybeUninit, size_of};
/// assert_eq!(size_of::<Option<bool>>(), 1);
/// assert_eq!(size_of::<Option<MaybeUninit<bool>>>(), 2);
/// ```
#[unstable(feature = "reverse_bits", issue = "48763")]
#[rustc_const_unstable(feature = "const_int_conversion")]
#[inline]
+ #[must_use]
pub const fn reverse_bits(self) -> Self {
(self as $UnsignedT).reverse_bits() as Self
}
```"),
#[unstable(feature = "reverse_bits", issue = "48763")]
#[inline]
+ #[must_use]
pub const fn reverse_bits(self) -> Self {
intrinsics::bitreverse(self as $ActualT) as Self
}
/// ```
#[unstable(feature = "reverse_bits", issue = "48763")]
#[inline]
+ #[must_use]
pub const fn reverse_bits(self) -> Self {
Wrapping(self.0.reverse_bits())
}
/// [`Waker`]: struct.Waker.html
/// [`RawWaker`]: struct.RawWaker.html
#[rustc_promotable]
- #[cfg_attr(stage0, unstable(feature = "futures_api_const_fn_ptr", issue = "50547"))]
- #[cfg_attr(not(stage0), stable(feature = "futures_api", since = "1.36.0"))]
+ #[stable(feature = "futures_api", since = "1.36.0")]
// `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else
// without first consulting with T-Lang.
//
// FIXME: remove whenever we have a stable way to accept fn pointers from const fn
// (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062)
- #[cfg_attr(not(stage0), rustc_allow_const_fn_ptr)]
+ #[rustc_allow_const_fn_ptr]
pub const fn new(
clone: unsafe fn(*const ()) -> RawWaker,
wake: unsafe fn(*const ()),
cfg.flag("-fomit-frame-pointer");
cfg.flag("-ffreestanding");
cfg.define("VISIBILITY_HIDDEN", None);
- cfg.define("COMPILER_RT_HAS_UNAME", Some("1"));
+ if !target.contains("windows") {
+ cfg.define("COMPILER_RT_HAS_UNAME", Some("1"));
+ } else {
+ profile_sources.push("WindowsMMap.c");
+ }
}
// Assume that the Unixes we are building this for have fnctl() available
```
"##,
+E0284: r##"
+This error occurs when the compiler is unable to unambiguously infer the
+return type of a function or method which is generic on return type, such
+as the `collect` method for `Iterator`s.
+
+For example:
+
+```compile_fail,E0284
+fn foo() -> Result<bool, ()> {
+ let results = [Ok(true), Ok(false), Err(())].iter().cloned();
+ let v: Vec<bool> = results.collect()?;
+ // Do things with v...
+ Ok(true)
+}
+```
+
+Here we have an iterator `results` over `Result<bool, ()>`.
+Hence, `results.collect()` can return any type implementing
+`FromIterator<Result<bool, ()>>`. On the other hand, the
+`?` operator can accept any type implementing `Try`.
+
+The author of this code probably wants `collect()` to return a
+`Result<Vec<bool>, ()>`, but the compiler can't be sure
+that there isn't another type `T` implementing both `Try` and
+`FromIterator<Result<bool, ()>>` in scope such that
+`T::Ok == Vec<bool>`. Hence, this code is ambiguous and an error
+is returned.
+
+To resolve this error, use a concrete type for the intermediate expression:
+
+```
+fn foo() -> Result<bool, ()> {
+ let results = [Ok(true), Ok(false), Err(())].iter().cloned();
+ let v = {
+ let temp: Result<Vec<bool>, ()> = results.collect();
+ temp?
+ };
+ // Do things with v...
+ Ok(true)
+}
+```
+
+Note that the type of `v` can now be inferred from the type of `temp`.
+"##,
+
E0308: r##"
This error occurs when the compiler was unable to infer the concrete type of a
variable. It can occur for several cases, the most common of which is a
E0278, // requirement is not satisfied
E0279, // requirement is not satisfied
E0280, // requirement is not satisfied
- E0284, // cannot resolve type
// E0285, // overflow evaluation builtin bounds
// E0296, // replaced with a generic attribute input check
// E0300, // unexpanded macro
TyAlias,
ForeignTy,
TraitAlias,
- AssociatedTy,
+ AssocTy,
/// `existential type Foo: Bar;`
- AssociatedExistential,
+ AssocExistential,
TyParam,
// Value namespace
/// Refers to the struct or enum variant's constructor.
Ctor(CtorOf, CtorKind),
Method,
- AssociatedConst,
+ AssocConst,
// Macro namespace
Macro(MacroKind),
DefKind::Existential => "existential type",
DefKind::TyAlias => "type alias",
DefKind::TraitAlias => "trait alias",
- DefKind::AssociatedTy => "associated type",
- DefKind::AssociatedExistential => "associated existential type",
+ DefKind::AssocTy => "associated type",
+ DefKind::AssocExistential => "associated existential type",
DefKind::Union => "union",
DefKind::Trait => "trait",
DefKind::ForeignTy => "foreign type",
DefKind::Method => "method",
DefKind::Const => "constant",
- DefKind::AssociatedConst => "associated constant",
+ DefKind::AssocConst => "associated constant",
DefKind::TyParam => "type parameter",
DefKind::ConstParam => "const parameter",
DefKind::Macro(macro_kind) => macro_kind.descr(),
/// An English article for the def.
pub fn article(&self) -> &'static str {
match *self {
- DefKind::AssociatedTy
- | DefKind::AssociatedConst
- | DefKind::AssociatedExistential
+ DefKind::AssocTy
+ | DefKind::AssocConst
+ | DefKind::AssocExistential
| DefKind::Enum
| DefKind::Existential => "an",
DefKind::Macro(macro_kind) => macro_kind.article(),
fn visit_vis(&mut self, vis: &'v Visibility) {
walk_vis(self, vis)
}
- fn visit_associated_item_kind(&mut self, kind: &'v AssociatedItemKind) {
+ fn visit_associated_item_kind(&mut self, kind: &'v AssocItemKind) {
walk_associated_item_kind(self, kind);
}
fn visit_defaultness(&mut self, defaultness: &'v Defaultness) {
}
}
-pub fn walk_associated_item_kind<'v, V: Visitor<'v>>(_: &mut V, _: &'v AssociatedItemKind) {
+pub fn walk_associated_item_kind<'v, V: Visitor<'v>>(_: &mut V, _: &'v AssocItemKind) {
// No visitable content here: this fn exists so you can call it if
// the right thing to do, should content be added in the future,
// would be to walk it.
let unstable_span = self.sess.source_map().mark_span_with_reason(
CompilerDesugaringKind::Async,
span,
- Some(vec![
- Symbol::intern("gen_future"),
- ].into()),
+ Some(vec![sym::gen_future].into()),
);
let gen_future = self.expr_std_path(
unstable_span, &[sym::future, sym::from_generator], None, ThinVec::new());
index: this.def_key(def_id).parent.expect("missing parent"),
};
let type_def_id = match partial_res.base_res() {
- Res::Def(DefKind::AssociatedTy, def_id) if i + 2 == proj_start => {
+ Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
Some(parent_def_id(self, def_id))
}
Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
if i + 1 == proj_start => ParenthesizedGenericArgs::Ok,
// `a::b::Trait(Args)::TraitItem`
Res::Def(DefKind::Method, _)
- | Res::Def(DefKind::AssociatedConst, _)
- | Res::Def(DefKind::AssociatedTy, _)
+ | Res::Def(DefKind::AssocConst, _)
+ | Res::Def(DefKind::AssocTy, _)
if i + 2 == proj_start =>
{
ParenthesizedGenericArgs::Ok
ident: match f.ident {
Some(ident) => ident,
// FIXME(jseyfried): positional field hygiene
- None => Ident::new(Symbol::intern(&index.to_string()), f.span),
+ None => Ident::new(sym::integer(index), f.span),
},
vis: self.lower_visibility(&f.vis, None),
ty: self.lower_ty(&f.ty, ImplTraitContext::disallowed()),
fn lower_trait_item_ref(&mut self, i: &TraitItem) -> hir::TraitItemRef {
let (kind, has_default) = match i.node {
TraitItemKind::Const(_, ref default) => {
- (hir::AssociatedItemKind::Const, default.is_some())
+ (hir::AssocItemKind::Const, default.is_some())
}
TraitItemKind::Type(_, ref default) => {
- (hir::AssociatedItemKind::Type, default.is_some())
+ (hir::AssocItemKind::Type, default.is_some())
}
TraitItemKind::Method(ref sig, ref default) => (
- hir::AssociatedItemKind::Method {
+ hir::AssocItemKind::Method {
has_self: sig.decl.has_self(),
},
default.is_some(),
vis: self.lower_visibility(&i.vis, Some(i.id)),
defaultness: self.lower_defaultness(i.defaultness, true /* [1] */),
kind: match i.node {
- ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
- ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
- ImplItemKind::Existential(..) => hir::AssociatedItemKind::Existential,
- ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
+ ImplItemKind::Const(..) => hir::AssocItemKind::Const,
+ ImplItemKind::Type(..) => hir::AssocItemKind::Type,
+ ImplItemKind::Existential(..) => hir::AssocItemKind::Existential,
+ ImplItemKind::Method(ref sig, _) => hir::AssocItemKind::Method {
has_self: sig.decl.has_self(),
},
ImplItemKind::Macro(..) => unimplemented!(),
let unstable_span = this.sess.source_map().mark_span_with_reason(
CompilerDesugaringKind::TryBlock,
body.span,
- Some(vec![
- Symbol::intern("try_trait"),
- ].into()),
+ Some(vec![sym::try_trait].into()),
);
let mut block = this.lower_block(body, true).into_inner();
let tail = block.expr.take().map_or_else(
use syntax::ast::*;
use syntax::ext::hygiene::Mark;
use syntax::visit;
-use syntax::symbol::kw;
-use syntax::symbol::Symbol;
+use syntax::symbol::{kw, sym};
use syntax::parse::token::{self, Token};
use syntax_pos::Span;
_: &'a Generics, _: NodeId, _: Span) {
for (index, field) in data.fields().iter().enumerate() {
let name = field.ident.map(|ident| ident.name)
- .unwrap_or_else(|| Symbol::intern(&index.to_string()));
+ .unwrap_or_else(|| sym::integer(index));
let def = self.create_def(field.id,
DefPathData::ValueNs(name.as_interned_str()),
field.span);
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::{IndexVec};
use rustc_data_structures::stable_hasher::StableHasher;
-use serialize::{Encodable, Decodable, Encoder, Decoder};
use crate::session::CrateDisambiguator;
use std::borrow::Borrow;
use std::fmt::Write;
/// Internally the DefPathTable holds a tree of DefKeys, where each DefKey
/// stores the DefIndex of its parent.
/// There is one DefPathTable for each crate.
-#[derive(Clone, Default)]
+#[derive(Clone, Default, RustcDecodable, RustcEncodable)]
pub struct DefPathTable {
index_to_key: Vec<DefKey>,
def_path_hashes: Vec<DefPathHash>,
}
impl DefPathTable {
-
fn allocate(&mut self,
key: DefKey,
def_path_hash: DefPathHash)
}
}
-
-impl Encodable for DefPathTable {
- fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
- // Index to key
- self.index_to_key.encode(s)?;
-
- // DefPath hashes
- self.def_path_hashes.encode(s)?;
-
- Ok(())
- }
-}
-
-impl Decodable for DefPathTable {
- fn decode<D: Decoder>(d: &mut D) -> Result<DefPathTable, D::Error> {
- Ok(DefPathTable {
- index_to_key: Decodable::decode(d)?,
- def_path_hashes : Decodable::decode(d)?,
- })
- }
-}
-
/// The definition table containing node definitions.
/// It holds the `DefPathTable` for local `DefId`s/`DefPath`s and it also stores a
/// mapping from `NodeId`s to local `DefId`s.
}
Node::TraitItem(item) => {
match item.node {
- TraitItemKind::Const(..) => DefKind::AssociatedConst,
+ TraitItemKind::Const(..) => DefKind::AssocConst,
TraitItemKind::Method(..) => DefKind::Method,
- TraitItemKind::Type(..) => DefKind::AssociatedTy,
+ TraitItemKind::Type(..) => DefKind::AssocTy,
}
}
Node::ImplItem(item) => {
match item.node {
- ImplItemKind::Const(..) => DefKind::AssociatedConst,
+ ImplItemKind::Const(..) => DefKind::AssocConst,
ImplItemKind::Method(..) => DefKind::Method,
- ImplItemKind::Type(..) => DefKind::AssociatedTy,
- ImplItemKind::Existential(..) => DefKind::AssociatedExistential,
+ ImplItemKind::Type(..) => DefKind::AssocTy,
+ ImplItemKind::Existential(..) => DefKind::AssocExistential,
}
}
Node::Variant(_) => DefKind::Variant,
pub id: TraitItemId,
#[stable_hasher(project(name))]
pub ident: Ident,
- pub kind: AssociatedItemKind,
+ pub kind: AssocItemKind,
pub span: Span,
pub defaultness: Defaultness,
}
pub id: ImplItemId,
#[stable_hasher(project(name))]
pub ident: Ident,
- pub kind: AssociatedItemKind,
+ pub kind: AssocItemKind,
pub span: Span,
pub vis: Visibility,
pub defaultness: Defaultness,
}
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable)]
-pub enum AssociatedItemKind {
+pub enum AssocItemKind {
Const,
Method { has_self: bool },
Type,
type Region = !;
type Type = !;
type DynExistential = !;
+ type Const = !;
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx> {
self.tcx
Err(NonTrivialPath)
}
+ fn print_const(
+ self,
+ _ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<Self::Const, Self::Error> {
+ Err(NonTrivialPath)
+ }
+
fn path_crate(
self,
cnum: CrateNum,
ConstValue::Param(_) |
ConstValue::Scalar(_) |
- ConstValue::Slice(..) |
+ ConstValue::Slice { .. } |
ConstValue::ByRef(..) |
ConstValue::Unevaluated(..) => {}
}
/// # Examples
///
/// ```rust,ignore (no context or def id available)
- /// if cx.match_def_path(def_id, &["core", "option", "Option"]) {
+ /// if cx.match_def_path(def_id, &[sym::core, sym::option, sym::Option]) {
/// // The given `def_id` is that of an `Option` type
/// }
/// ```
- pub fn match_def_path(&self, def_id: DefId, path: &[&str]) -> bool {
+ pub fn match_def_path(&self, def_id: DefId, path: &[Symbol]) -> bool {
let names = self.get_def_path(def_id);
- names.len() == path.len() && names.into_iter().zip(path.iter()).all(|(a, &b)| *a == *b)
+ names.len() == path.len() && names.into_iter().zip(path.iter()).all(|(a, &b)| a == b)
}
- /// Gets the absolute path of `def_id` as a vector of `&str`.
+ /// Gets the absolute path of `def_id` as a vector of `Symbol`.
///
/// # Examples
///
/// ```rust,ignore (no context or def id available)
/// let def_path = cx.get_def_path(def_id);
- /// if let &["core", "option", "Option"] = &def_path[..] {
+ /// if let &[sym::core, sym::option, sym::Option] = &def_path[..] {
/// // The given `def_id` is that of an `Option` type
/// }
/// ```
- pub fn get_def_path(&self, def_id: DefId) -> Vec<LocalInternedString> {
+ pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
pub struct AbsolutePathPrinter<'a, 'tcx> {
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
impl<'tcx> Printer<'tcx, 'tcx> for AbsolutePathPrinter<'_, 'tcx> {
type Error = !;
- type Path = Vec<LocalInternedString>;
+ type Path = Vec<Symbol>;
type Region = ();
type Type = ();
type DynExistential = ();
+ type Const = ();
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
self.tcx
fn print_dyn_existential(
self,
_predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
- ) -> Result<Self::DynExistential, Self::Error> {
+ ) -> Result<Self::DynExistential, Self::Error> {
+ Ok(())
+ }
+
+ fn print_const(
+ self,
+ _ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<Self::Const, Self::Error> {
Ok(())
}
fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
- Ok(vec![self.tcx.original_crate_name(cnum).as_str()])
+ Ok(vec![self.tcx.original_crate_name(cnum)])
}
fn path_qualified(
self,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
- ) -> Result<Self::Path, Self::Error> {
+ ) -> Result<Self::Path, Self::Error> {
if trait_ref.is_none() {
if let ty::Adt(def, substs) = self_ty.sty {
return self.print_def_path(def.did, substs);
// This shouldn't ever be needed, but just in case:
Ok(vec![match trait_ref {
- Some(trait_ref) => LocalInternedString::intern(&format!("{:?}", trait_ref)),
- None => LocalInternedString::intern(&format!("<{}>", self_ty)),
+ Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)),
+ None => Symbol::intern(&format!("<{}>", self_ty)),
}])
}
_disambiguated_data: &DisambiguatedDefPathData,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
- ) -> Result<Self::Path, Self::Error> {
+ ) -> Result<Self::Path, Self::Error> {
let mut path = print_prefix(self)?;
// This shouldn't ever be needed, but just in case:
path.push(match trait_ref {
Some(trait_ref) => {
- LocalInternedString::intern(&format!("<impl {} for {}>", trait_ref,
+ Symbol::intern(&format!("<impl {} for {}>", trait_ref,
self_ty))
},
- None => LocalInternedString::intern(&format!("<impl {}>", self_ty)),
+ None => Symbol::intern(&format!("<impl {}>", self_ty)),
});
Ok(path)
self,
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
disambiguated_data: &DisambiguatedDefPathData,
- ) -> Result<Self::Path, Self::Error> {
+ ) -> Result<Self::Path, Self::Error> {
let mut path = print_prefix(self)?;
// Skip `::{{constructor}}` on tuple/unit structs.
_ => {}
}
- path.push(disambiguated_data.data.as_interned_str().as_str());
+ path.push(disambiguated_data.data.as_interned_str().as_symbol());
Ok(path)
}
self,
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
_args: &[Kind<'tcx>],
- ) -> Result<Self::Path, Self::Error> {
+ ) -> Result<Self::Path, Self::Error> {
print_prefix(self)
}
}
use errors::Applicability;
use rustc_data_structures::fx::FxHashMap;
use syntax::ast::Ident;
+use syntax::symbol::{sym, Symbol};
declare_lint! {
pub DEFAULT_HASH_TYPES,
}
pub struct DefaultHashTypes {
- map: FxHashMap<String, String>,
+ map: FxHashMap<Symbol, Symbol>,
}
impl DefaultHashTypes {
+ // we are allowed to use `HashMap` and `HashSet` as identifiers for implementing the lint itself
+ #[allow(internal)]
pub fn new() -> Self {
let mut map = FxHashMap::default();
- map.insert("HashMap".to_string(), "FxHashMap".to_string());
- map.insert("HashSet".to_string(), "FxHashSet".to_string());
+ map.insert(sym::HashMap, sym::FxHashMap);
+ map.insert(sym::HashSet, sym::FxHashSet);
Self { map }
}
}
impl EarlyLintPass for DefaultHashTypes {
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
- let ident_string = ident.to_string();
- if let Some(replace) = self.map.get(&ident_string) {
+ if let Some(replace) = self.map.get(&ident.name) {
let msg = format!(
"Prefer {} over {}, it has better performance",
- replace, ident_string
+ replace, ident
);
let mut db = cx.struct_span_lint(DEFAULT_HASH_TYPES, ident.span, &msg);
db.span_suggestion(
}
fn lint_ty_kind_usage(cx: &LateContext<'_, '_>, segment: &PathSegment) -> bool {
- if segment.ident.as_str() == "TyKind" {
+ if segment.ident.name == sym::TyKind {
if let Some(res) = segment.res {
if let Some(did) = res.opt_def_id() {
- return cx.match_def_path(did, &["rustc", "ty", "sty", "TyKind"]);
+ return cx.match_def_path(did, TYKIND_PATH);
}
}
}
false
}
+const TYKIND_PATH: &[Symbol] = &[sym::rustc, sym::ty, sym::sty, sym::TyKind];
+const TY_PATH: &[Symbol] = &[sym::rustc, sym::ty, sym::Ty];
+const TYCTXT_PATH: &[Symbol] = &[sym::rustc, sym::ty, sym::context, sym::TyCtxt];
+
fn is_ty_or_ty_ctxt(cx: &LateContext<'_, '_>, ty: &Ty) -> Option<String> {
match &ty.node {
TyKind::Path(qpath) => {
if let QPath::Resolved(_, path) = qpath {
let did = path.res.opt_def_id()?;
- if cx.match_def_path(did, &["rustc", "ty", "Ty"]) {
+ if cx.match_def_path(did, TY_PATH) {
return Some(format!("Ty{}", gen_args(path.segments.last().unwrap())));
- } else if cx.match_def_path(did, &["rustc", "ty", "context", "TyCtxt"]) {
+ } else if cx.match_def_path(did, TYCTXT_PATH) {
return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap())));
}
}
let store = self.sess.lint_store.borrow();
let sess = self.sess;
let bad_attr = |span| {
- struct_span_err!(sess, span, E0452, "malformed lint attribute")
+ struct_span_err!(sess, span, E0452, "malformed lint attribute input")
};
for attr in attrs {
let level = match Level::from_symbol(attr.name_or_empty()) {
}
reason = Some(rationale);
} else {
- let mut err = bad_attr(name_value.span);
- err.help("reason must be a string literal");
- err.emit();
+ bad_attr(name_value.span)
+ .span_label(name_value.span, "reason must be a string literal")
+ .emit();
}
} else {
- let mut err = bad_attr(item.span);
- err.emit();
+ bad_attr(item.span)
+ .span_label(item.span, "bad attribute argument")
+ .emit();
}
},
ast::MetaItemKind::List(_) => {
- let mut err = bad_attr(item.span);
- err.emit();
+ bad_attr(item.span)
+ .span_label(item.span, "bad attribute argument")
+ .emit();
}
}
}
let meta_item = match li.meta_item() {
Some(meta_item) if meta_item.is_word() => meta_item,
_ => {
- let mut err = bad_attr(li.span());
+ let sp = li.span();
+ let mut err = bad_attr(sp);
+ let mut add_label = true;
if let Some(item) = li.meta_item() {
if let ast::MetaItemKind::NameValue(_) = item.node {
if item.path == sym::reason {
- err.help("reason in lint attribute must come last");
+ err.span_label(sp, "reason in lint attribute must come last");
+ add_label = false;
}
}
}
+ if add_label {
+ err.span_label(sp, "bad attribute argument");
+ }
err.emit();
continue;
}
Also `cfg_attr(cargo-clippy)` won't be necessary anymore",
name
);
- let mut err = lint::struct_lint_level(
+ lint::struct_lint_level(
self.sess,
lint,
lvl,
src,
Some(li.span().into()),
&msg,
- );
- err.span_suggestion(
+ ).span_suggestion(
li.span(),
"change it to",
new_lint_name.to_string(),
fn handle_res(&mut self, res: Res) {
match res {
Res::Def(DefKind::Const, _)
- | Res::Def(DefKind::AssociatedConst, _)
+ | Res::Def(DefKind::AssocConst, _)
| Res::Def(DefKind::TyAlias, _) => {
self.check_def_id(res.def_id());
}
| Res::Def(DefKind::Ctor(..), _)
| Res::Def(DefKind::Union, _)
| Res::Def(DefKind::TyAlias, _)
- | Res::Def(DefKind::AssociatedTy, _)
+ | Res::Def(DefKind::AssocTy, _)
| Res::SelfTy(..) => {
debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat);
delegate.matched_pat(pat, &cmt_pat, match_mode);
pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
attrs.iter().find_map(|attr| Some(match attr {
_ if attr.check_name(sym::lang) => (attr.value_str()?, attr.span),
- _ if attr.check_name(sym::panic_handler) => (Symbol::intern("panic_impl"), attr.span),
- _ if attr.check_name(sym::alloc_error_handler) => (Symbol::intern("oom"), attr.span),
+ _ if attr.check_name(sym::panic_handler) => (sym::panic_impl, attr.span),
+ _ if attr.check_name(sym::alloc_error_handler) => (sym::oom, attr.span),
_ => return None,
}))
}
Res::Def(DefKind::Ctor(..), _)
| Res::Def(DefKind::Const, _)
| Res::Def(DefKind::ConstParam, _)
- | Res::Def(DefKind::AssociatedConst, _)
+ | Res::Def(DefKind::AssocConst, _)
| Res::Def(DefKind::Fn, _)
| Res::Def(DefKind::Method, _)
| Res::SelfCtor(..) => {
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
let subpat_ty = self.pat_ty_adjusted(&subpat)?; // see (*2)
- let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string())));
+ let interior = InteriorField(FieldIndex(i, sym::integer(i)));
let subcmt = Rc::new(
self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior));
self.cat_pattern_(subcmt, &subpat, op)?;
};
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
let subpat_ty = self.pat_ty_adjusted(&subpat)?; // see (*2)
- let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string())));
+ let interior = InteriorField(FieldIndex(i, sym::integer(i)));
let subcmt = Rc::new(
self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior));
self.cat_pattern_(subcmt, &subpat, op)?;
// If this path leads to a constant, then we need to
// recurse into the constant to continue finding
// items that are reachable.
- Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssociatedConst, _) => {
+ Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
self.worklist.push(hir_id);
}
// The lifetime was defined on node that doesn't own a body,
// which in practice can only mean a trait or an impl, that
// is the parent of a method, and that is enforced below.
- assert_eq!(Some(param_owner_id), self.root_parent,
- "free_scope: {:?} not recognized by the \
- region scope tree for {:?} / {:?}",
- param_owner,
- self.root_parent.map(|id| tcx.hir().local_def_id_from_hir_id(id)),
- self.root_body.map(|hir_id| DefId::local(hir_id.owner)));
+ if Some(param_owner_id) != self.root_parent {
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ &format!("free_scope: {:?} not recognized by the \
+ region scope tree for {:?} / {:?}",
+ param_owner,
+ self.root_parent.map(|id| tcx.hir().local_def_id_from_hir_id(id)),
+ self.root_body.map(|hir_id| DefId::local(hir_id.owner))));
+ }
// The trait/impl lifetime is in scope for the method's body.
self.root_body.unwrap().local_id
}
};
let type_def_id = match res {
- Res::Def(DefKind::AssociatedTy, def_id)
+ Res::Def(DefKind::AssocTy, def_id)
if depth == 1 => Some(parent_def_id(self, def_id)),
Res::Def(DefKind::Variant, def_id)
if depth == 0 => Some(parent_def_id(self, def_id)),
};
let has_self = match assoc_item_kind {
- Some(hir::AssociatedItemKind::Method { has_self }) => has_self,
+ Some(hir::AssocItemKind::Method { has_self }) => has_self,
_ => false,
};
reason: Some(Symbol::intern(reason)),
issue: 27812,
},
- feature: Symbol::intern("rustc_private"),
+ feature: sym::rustc_private,
rustc_depr: None,
const_stability: None,
promotable: false,
// Check if `def_id` is a trait method.
match self.def_kind(def_id) {
Some(DefKind::Method) |
- Some(DefKind::AssociatedTy) |
- Some(DefKind::AssociatedConst) => {
+ Some(DefKind::AssocTy) |
+ Some(DefKind::AssocConst) => {
if let ty::TraitContainer(trait_def_id) = self.associated_item(def_id).container {
// Trait methods do not declare visibility (even
// for visibility info in cstore). Use containing
// FIXME: only remove `libc` when `stdbuild` is active.
// FIXME: remove special casing for `test`.
remaining_lib_features.remove(&Symbol::intern("libc"));
- remaining_lib_features.remove(&Symbol::intern("test"));
+ remaining_lib_features.remove(&sym::test);
let check_features =
|remaining_lib_features: &mut FxHashMap<_, _>, defined_features: &[_]| {
use crate::ty::layout::{Size, Align};
use syntax::ast::Mutability;
-use std::iter;
+use std::{iter, fmt::{self, Display}};
use crate::mir;
use std::ops::{Deref, DerefMut};
use rustc_data_structures::sorted_map::SortedMap;
MaybeDead,
}
+/// Used by `check_in_alloc` to indicate context of check
+#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
+pub enum CheckInAllocMsg {
+ MemoryAccessTest,
+ NullPointerTest,
+ PointerArithmeticTest,
+ InboundsTest,
+}
+
+impl Display for CheckInAllocMsg {
+ /// When this is printed as an error the context looks like this
+ /// "{test name} failed: pointer must be in-bounds at offset..."
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", match *self {
+ CheckInAllocMsg::MemoryAccessTest => "Memory access",
+ CheckInAllocMsg::NullPointerTest => "Null pointer test",
+ CheckInAllocMsg::PointerArithmeticTest => "Pointer arithmetic",
+ CheckInAllocMsg::InboundsTest => "Inbounds test",
+ })
+ }
+}
+
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub struct Allocation<Tag=(),Extra=()> {
/// The actual bytes of the allocation.
fn check_bounds_ptr(
&self,
ptr: Pointer<Tag>,
+ msg: CheckInAllocMsg,
) -> EvalResult<'tcx> {
let allocation_size = self.bytes.len() as u64;
- ptr.check_in_alloc(Size::from_bytes(allocation_size), InboundsCheck::Live)
+ ptr.check_in_alloc(Size::from_bytes(allocation_size), msg)
}
/// Checks if the memory range beginning at `ptr` and of size `Size` is "in-bounds".
cx: &impl HasDataLayout,
ptr: Pointer<Tag>,
size: Size,
+ msg: CheckInAllocMsg,
) -> EvalResult<'tcx> {
// if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
- self.check_bounds_ptr(ptr.offset(size, cx)?)
+ self.check_bounds_ptr(ptr.offset(size, cx)?, msg)
}
}
ptr: Pointer<Tag>,
size: Size,
check_defined_and_ptr: bool,
+ msg: CheckInAllocMsg,
) -> EvalResult<'tcx, &[u8]>
{
- self.check_bounds(cx, ptr, size)?;
+ self.check_bounds(cx, ptr, size, msg)?;
if check_defined_and_ptr {
self.check_defined(ptr, size)?;
size: Size,
) -> EvalResult<'tcx, &[u8]>
{
- self.get_bytes_internal(cx, ptr, size, true)
+ self.get_bytes_internal(cx, ptr, size, true, CheckInAllocMsg::MemoryAccessTest)
}
/// It is the caller's responsibility to handle undefined and pointer bytes.
size: Size,
) -> EvalResult<'tcx, &[u8]>
{
- self.get_bytes_internal(cx, ptr, size, false)
+ self.get_bytes_internal(cx, ptr, size, false, CheckInAllocMsg::MemoryAccessTest)
}
/// Just calling this already marks everything as defined and removes relocations,
) -> EvalResult<'tcx, &mut [u8]>
{
assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`");
- self.check_bounds(cx, ptr, size)?;
+ self.check_bounds(cx, ptr, size, CheckInAllocMsg::MemoryAccessTest)?;
self.mark_definedness(ptr, size, true)?;
self.clear_relocations(cx, ptr, size)?;
use rustc_target::spec::abi::Abi;
use rustc_macros::HashStable;
-use super::{RawConst, Pointer, InboundsCheck, ScalarMaybeUndef};
+use super::{RawConst, Pointer, CheckInAllocMsg, ScalarMaybeUndef};
use backtrace::Backtrace;
}
pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
-pub type ConstEvalResult<'tcx> = Result<ty::Const<'tcx>, ErrorHandled>;
+pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct ConstEvalErr<'tcx> {
InvalidDiscriminant(ScalarMaybeUndef),
PointerOutOfBounds {
ptr: Pointer,
- check: InboundsCheck,
+ msg: CheckInAllocMsg,
allocation_size: Size,
},
InvalidNullPointerUsage,
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::InterpError::*;
match *self {
- PointerOutOfBounds { ptr, check, allocation_size } => {
- write!(f, "Pointer must be in-bounds{} at offset {}, but is outside bounds of \
- allocation {} which has size {}",
- match check {
- InboundsCheck::Live => " and live",
- InboundsCheck::MaybeDead => "",
- },
- ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
+ PointerOutOfBounds { ptr, msg, allocation_size } => {
+ write!(f, "{} failed: pointer must be in-bounds at offset {}, \
+ but is outside bounds of allocation {} which has size {}",
+ msg, ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
},
ValidationFailure(ref err) => {
write!(f, "type validation failed: {}", err)
pub use self::allocation::{
InboundsCheck, Allocation, AllocationExtra,
- Relocations, UndefMask,
+ Relocations, UndefMask, CheckInAllocMsg,
};
pub use self::pointer::{Pointer, PointerArithmetic};
+use std::fmt;
+
use crate::mir;
use crate::ty::layout::{self, HasDataLayout, Size};
use rustc_macros::HashStable;
use super::{
- AllocId, EvalResult, InboundsCheck,
+ AllocId, EvalResult, CheckInAllocMsg
};
////////////////////////////////////////////////////////////////////////////////
///
/// Pointer is also generic over the `Tag` associated with each pointer,
/// which is used to do provenance tracking during execution.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd,
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd,
RustcEncodable, RustcDecodable, Hash, HashStable)]
pub struct Pointer<Tag=(),Id=AllocId> {
pub alloc_id: Id,
static_assert_size!(Pointer, 16);
+impl<Tag: fmt::Debug, Id: fmt::Debug> fmt::Debug for Pointer<Tag, Id> {
+ default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:?}.{:#x}[{:?}]", self.alloc_id, self.offset.bytes(), self.tag)
+ }
+}
+// Specialization for no tag
+impl<Id: fmt::Debug> fmt::Debug for Pointer<(), Id> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:?}.{:#x}", self.alloc_id, self.offset.bytes())
+ }
+}
+
/// Produces a `Pointer` which points to the beginning of the Allocation
impl From<AllocId> for Pointer {
#[inline(always)]
pub fn check_in_alloc(
self,
allocation_size: Size,
- check: InboundsCheck,
+ msg: CheckInAllocMsg,
) -> EvalResult<'tcx, ()> {
if self.offset > allocation_size {
err!(PointerOutOfBounds {
ptr: self.erase_tag(),
- check,
+ msg,
allocation_size,
})
} else {
/// Not using the enum `Value` to encode that this must not be `Undef`.
Scalar(Scalar),
- /// Used only for slices and strings (`&[T]`, `&str`, `*const [T]`, `*mut str`, `Box<str>`,
- /// etc.).
- ///
- /// Empty slices don't necessarily have an address backed by an `AllocId`, thus we also need to
- /// enable integer pointers. The `Scalar` type covers exactly those two cases. While we could
- /// create dummy-`AllocId`s, the additional code effort for the conversions doesn't seem worth
- /// it.
- Slice(Scalar, u64),
+ /// Used only for `&[u8]` and `&str`
+ Slice {
+ data: &'tcx Allocation,
+ start: usize,
+ end: usize,
+ },
/// An allocation together with a pointer into the allocation.
/// Invariant: the pointer's `AllocId` resolves to the allocation.
}
#[cfg(target_arch = "x86_64")]
-static_assert_size!(ConstValue<'_>, 40);
+static_assert_size!(ConstValue<'_>, 32);
impl<'tcx> ConstValue<'tcx> {
#[inline]
ConstValue::Placeholder(_) |
ConstValue::ByRef(..) |
ConstValue::Unevaluated(..) |
- ConstValue::Slice(..) => None,
+ ConstValue::Slice { .. } => None,
ConstValue::Scalar(val) => Some(val),
}
}
pub fn try_to_ptr(&self) -> Option<Pointer> {
self.try_to_scalar()?.to_ptr().ok()
}
-
- #[inline]
- pub fn new_slice(
- val: Scalar,
- len: u64,
- ) -> Self {
- ConstValue::Slice(val, len)
- }
}
/// A `Scalar` represents an immediate, primitive value existing outside of a
/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
/// of a simple value or a pointer into another `Allocation`
-#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd,
+#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd,
RustcEncodable, RustcDecodable, Hash, HashStable)]
pub enum Scalar<Tag=(), Id=AllocId> {
/// The raw bytes of a simple value.
#[cfg(target_arch = "x86_64")]
static_assert_size!(Scalar, 24);
+impl<Tag: fmt::Debug, Id: fmt::Debug> fmt::Debug for Scalar<Tag, Id> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Scalar::Ptr(ptr) =>
+ write!(f, "{:?}", ptr),
+ &Scalar::Bits { bits, size } => {
+ if size == 0 {
+ assert_eq!(bits, 0, "ZST value must be 0");
+ write!(f, "<ZST>")
+ } else {
+ assert_eq!(truncate(bits, Size::from_bytes(size as u64)), bits,
+ "Scalar value {:#x} exceeds size of {} bytes", bits, size);
+ // Format as hex number wide enough to fit any value of the given `size`.
+ // So bits=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
+ write!(f, "0x{:>0width$x}", bits, width=(size*2) as usize)
+ }
+ }
+ }
+ }
+}
+
impl<Tag> fmt::Display for Scalar<Tag> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
}
}
-#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
+#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
pub enum ScalarMaybeUndef<Tag=(), Id=AllocId> {
Scalar(Scalar<Tag, Id>),
Undef,
}
}
+impl<Tag: fmt::Debug, Id: fmt::Debug> fmt::Debug for ScalarMaybeUndef<Tag, Id> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ ScalarMaybeUndef::Undef => write!(f, "Undef"),
+ ScalarMaybeUndef::Scalar(s) => write!(f, "{:?}", s),
+ }
+ }
+}
+
impl<Tag> fmt::Display for ScalarMaybeUndef<Tag> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
use crate::hir::{self, InlineAsm as HirInlineAsm};
use crate::mir::interpret::{ConstValue, InterpError, Scalar};
use crate::mir::visit::MirVisitable;
-use rustc_apfloat::ieee::{Double, Single};
-use rustc_apfloat::Float;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::graph::dominators::{dominators, Dominators};
use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
use crate::rustc_serialize::{self as serialize};
use smallvec::SmallVec;
use std::borrow::Cow;
-use std::fmt::{self, Debug, Formatter, Write};
+use std::fmt::{self, Debug, Formatter, Write, Display};
use std::iter::FusedIterator;
use std::ops::{Index, IndexMut};
use std::slice;
use std::vec::IntoIter;
use std::{iter, mem, option, u32};
-use syntax::ast::{self, Name};
+use syntax::ast::Name;
use syntax::symbol::{InternedString, Symbol};
use syntax_pos::{Span, DUMMY_SP};
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
switch_ty,
..
} => {
- let size = ty::tls::with(|tcx| {
+ ty::tls::with(|tcx| {
let param_env = ty::ParamEnv::empty();
let switch_ty = tcx.lift_to_global(&switch_ty).unwrap();
- tcx.layout_of(param_env.and(switch_ty)).unwrap().size
- });
- values
- .iter()
- .map(|&u| {
- let mut s = String::new();
- let c = ty::Const {
- val: ConstValue::Scalar(
- Scalar::Bits {
- bits: u,
- size: size.bytes() as u8,
- }.into(),
- ),
- ty: switch_ty,
- };
- fmt_const_val(&mut s, c).unwrap();
- s.into()
- }).chain(iter::once("otherwise".into()))
- .collect()
+ let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
+ values
+ .iter()
+ .map(|&u| {
+ tcx.mk_const(ty::Const {
+ val: ConstValue::Scalar(
+ Scalar::Bits {
+ bits: u,
+ size: size.bytes() as u8,
+ }.into(),
+ ),
+ ty: switch_ty,
+ }).to_string().into()
+ }).chain(iter::once("otherwise".into()))
+ .collect()
+ })
}
Call {
destination: Some(_),
span,
ty,
user_ty: None,
- literal: tcx.mk_const(
- ty::Const::zero_sized(ty),
- ),
+ literal: ty::Const::zero_sized(tcx, ty),
})
}
impl<'tcx> Debug for Constant<'tcx> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
- write!(fmt, "const ")?;
- fmt_const_val(fmt, *self.literal)
- }
-}
-/// Write a `ConstValue` in a way closer to the original source code than the `Debug` output.
-pub fn fmt_const_val(f: &mut impl Write, const_val: ty::Const<'_>) -> fmt::Result {
- use crate::ty::TyKind::*;
- let value = const_val.val;
- let ty = const_val.ty;
- // print some primitives
- if let ConstValue::Scalar(Scalar::Bits { bits, .. }) = value {
- match ty.sty {
- Bool if bits == 0 => return write!(f, "false"),
- Bool if bits == 1 => return write!(f, "true"),
- Float(ast::FloatTy::F32) => return write!(f, "{}f32", Single::from_bits(bits)),
- Float(ast::FloatTy::F64) => return write!(f, "{}f64", Double::from_bits(bits)),
- Uint(ui) => return write!(f, "{:?}{}", bits, ui),
- Int(i) => {
- let bit_width = ty::tls::with(|tcx| {
- let ty = tcx.lift_to_global(&ty).unwrap();
- tcx.layout_of(ty::ParamEnv::empty().and(ty))
- .unwrap()
- .size
- .bits()
- });
- let shift = 128 - bit_width;
- return write!(f, "{:?}{}", ((bits as i128) << shift) >> shift, i);
- }
- Char => return write!(f, "{:?}", ::std::char::from_u32(bits as u32).unwrap()),
- _ => {}
- }
+ write!(fmt, "{}", self)
}
- // print function definitions
- if let FnDef(did, _) = ty.sty {
- return write!(f, "{}", def_path_str(did));
- }
- // print string literals
- if let ConstValue::Slice(ptr, len) = value {
- if let Scalar::Ptr(ptr) = ptr {
- if let Ref(_, &ty::TyS { sty: Str, .. }, _) = ty.sty {
- return ty::tls::with(|tcx| {
- let alloc = tcx.alloc_map.lock().get(ptr.alloc_id);
- if let Some(interpret::AllocKind::Memory(alloc)) = alloc {
- assert_eq!(len as usize as u64, len);
- let slice =
- &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)];
- let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
- write!(f, "{:?}", s)
- } else {
- write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len)
- }
- });
- }
- }
- }
- // just raw dump everything else
- write!(f, "{:?} : {}", value, ty)
}
-fn def_path_str(def_id: DefId) -> String {
- ty::tls::with(|tcx| tcx.def_path_str(def_id))
+impl<'tcx> Display for Constant<'tcx> {
+ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ write!(fmt, "const ")?;
+ write!(fmt, "{}", self.literal)
+ }
}
impl<'tcx> graph::DirectedGraph for Mir<'tcx> {
query associated_item_def_ids(_: DefId) -> &'tcx [DefId] {}
/// Maps from a trait item to the trait item "descriptor".
- query associated_item(_: DefId) -> ty::AssociatedItem {}
+ query associated_item(_: DefId) -> ty::AssocItem {}
query impl_trait_ref(_: DefId) -> Option<ty::TraitRef<'tcx>> {}
query impl_polarity(_: DefId) -> hir::ImplPolarity {}
use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
use syntax::parse::token;
use syntax::parse;
-use syntax::symbol::Symbol;
+use syntax::symbol::{sym, Symbol};
use syntax::feature_gate::UnstableFeatures;
use errors::emitter::HumanReadableErrorType;
}
#[derive(Clone, PartialEq, Hash)]
-pub enum PgoGenerate {
+pub enum SwitchWithOptPath {
Enabled(Option<PathBuf>),
Disabled,
}
-impl PgoGenerate {
+impl SwitchWithOptPath {
pub fn enabled(&self) -> bool {
match *self {
- PgoGenerate::Enabled(_) => true,
- PgoGenerate::Disabled => false,
+ SwitchWithOptPath::Enabled(_) => true,
+ SwitchWithOptPath::Disabled => false,
}
}
}
pub const parse_linker_plugin_lto: Option<&str> =
Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
or the path to the linker plugin");
- pub const parse_pgo_generate: Option<&str> =
+ pub const parse_switch_with_opt_path: Option<&str> =
Some("an optional path to the profiling data output directory");
pub const parse_merge_functions: Option<&str> =
Some("one of: `disabled`, `trampolines`, or `aliases`");
#[allow(dead_code)]
mod $mod_set {
- use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, PgoGenerate};
+ use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath};
use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
use std::path::PathBuf;
use std::str::FromStr;
true
}
- fn parse_pgo_generate(slot: &mut PgoGenerate, v: Option<&str>) -> bool {
+ fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
*slot = match v {
- None => PgoGenerate::Enabled(None),
- Some(path) => PgoGenerate::Enabled(Some(PathBuf::from(path))),
+ None => SwitchWithOptPath::Enabled(None),
+ Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
};
true
}
"extra arguments to prepend to the linker invocation (space separated)"),
profile: bool = (false, parse_bool, [TRACKED],
"insert profiling code"),
- pgo_gen: PgoGenerate = (PgoGenerate::Disabled, parse_pgo_generate, [TRACKED],
+ pgo_gen: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
+ parse_switch_with_opt_path, [TRACKED],
"Generate PGO profile data, to a given file, or to the default location if it's empty."),
- pgo_use: String = (String::new(), parse_string, [TRACKED],
+ pgo_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
"Use PGO profile data from the given profile file."),
disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
"Disable the instrumentation pre-inliner, useful for profiling / PGO."),
"don't interleave execution of lints; allows benchmarking individual lints"),
crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
"inject the given attribute in the crate"),
- self_profile: bool = (false, parse_bool, [UNTRACKED],
+ self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
+ parse_switch_with_opt_path, [UNTRACKED],
"run the self profiler and output the raw event data"),
self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
"specifies which kinds of events get recorded by the self profiler"),
Some(Symbol::intern(vendor)),
));
if sess.target.target.options.has_elf_tls {
- ret.insert((Symbol::intern("target_thread_local"), None));
+ ret.insert((sym::target_thread_local, None));
}
for &i in &[8, 16, 32, 64, 128] {
if i >= min_atomic_width && i <= max_atomic_width {
let s = i.to_string();
ret.insert((
- Symbol::intern("target_has_atomic"),
+ sym::target_has_atomic,
Some(Symbol::intern(&s)),
));
if &s == wordsz {
ret.insert((
- Symbol::intern("target_has_atomic"),
+ sym::target_has_atomic,
Some(Symbol::intern("ptr")),
));
}
}
}
if atomic_cas {
- ret.insert((Symbol::intern("target_has_atomic"), Some(Symbol::intern("cas"))));
+ ret.insert((sym::target_has_atomic, Some(Symbol::intern("cas"))));
}
if sess.opts.debug_assertions {
ret.insert((Symbol::intern("debug_assertions"), None));
}
if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
- ret.insert((Symbol::intern("proc_macro"), None));
+ ret.insert((sym::proc_macro, None));
}
ret
}
let default_cfg = default_configuration(sess);
// If the user wants a test runner, then add the test cfg
if sess.opts.test {
- user_cfg.insert((Symbol::intern("test"), None));
+ user_cfg.insert((sym::test, None));
}
user_cfg.extend(default_cfg.iter().cloned());
user_cfg
}
}
- if debugging_opts.pgo_gen.enabled() && !debugging_opts.pgo_use.is_empty() {
+ if debugging_opts.pgo_gen.enabled() && debugging_opts.pgo_use.is_some() {
early_error(
error_format,
"options `-Z pgo-gen` and `-Z pgo-use` are exclusive",
use std::path::PathBuf;
use std::collections::hash_map::DefaultHasher;
use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
- Passes, Sanitizer, LtoCli, LinkerPluginLto, PgoGenerate};
+ Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath};
use syntax::feature_gate::UnstableFeatures;
use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
use syntax::edition::Edition;
impl_dep_tracking_hash_via_hash!(TargetTriple);
impl_dep_tracking_hash_via_hash!(Edition);
impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
- impl_dep_tracking_hash_via_hash!(PgoGenerate);
+ impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
impl_dep_tracking_hash_for_sortable_vec_of!(String);
impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
build_session_options_and_crate_config,
to_crate_config
};
- use crate::session::config::{LtoCli, LinkerPluginLto, PgoGenerate, ExternEntry};
+ use crate::session::config::{LtoCli, LinkerPluginLto, SwitchWithOptPath, ExternEntry};
use crate::session::build_session;
use crate::session::search_paths::SearchPath;
use std::collections::{BTreeMap, BTreeSet};
use std::path::PathBuf;
use super::{Externs, OutputType, OutputTypes};
use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel};
- use syntax::symbol::Symbol;
+ use syntax::symbol::sym;
use syntax::edition::{Edition, DEFAULT_EDITION};
use syntax;
use super::Options;
let (sessopts, cfg) = build_session_options_and_crate_config(matches);
let sess = build_session(sessopts, None, registry);
let cfg = build_configuration(&sess, to_crate_config(cfg));
- assert!(cfg.contains(&(Symbol::intern("test"), None)));
+ assert!(cfg.contains(&(sym::test, None)));
});
}
// another --cfg test
#[test]
fn test_switch_implies_cfg_test_unless_cfg_test() {
- use syntax::symbol::sym;
syntax::with_default_globals(|| {
let matches = &match optgroups().parse(&["--test".to_string(),
"--cfg=test".to_string()]) {
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
opts = reference.clone();
- opts.debugging_opts.pgo_gen = PgoGenerate::Enabled(None);
+ opts.debugging_opts.pgo_gen = SwitchWithOptPath::Enabled(None);
assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
opts = reference.clone();
- opts.debugging_opts.pgo_use = String::from("abc");
+ opts.debugging_opts.pgo_use = Some(PathBuf::from("abc"));
assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
opts = reference.clone();
use crate::lint::builtin::BuiltinLintDiagnostics;
use crate::middle::allocator::AllocatorKind;
use crate::middle::dependency_format;
-use crate::session::config::OutputType;
+use crate::session::config::{OutputType, SwitchWithOptPath};
use crate::session::search_paths::{PathKind, SearchPath};
use crate::util::nodemap::{FxHashMap, FxHashSet};
use crate::util::common::{duration_to_secs_str, ErrorReported};
driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
) -> Session {
let self_profiler =
- if sopts.debugging_opts.self_profile {
- let profiler = SelfProfiler::new(&sopts.debugging_opts.self_profile_events);
+ if let SwitchWithOptPath::Enabled(ref d) = sopts.debugging_opts.self_profile {
+ let directory = if let Some(ref directory) = d {
+ directory
+ } else {
+ std::path::Path::new(".")
+ };
+
+ let profiler = SelfProfiler::new(
+ directory,
+ sopts.crate_name.as_ref().map(|s| &s[..]),
+ &sopts.debugging_opts.self_profile_events
+ );
match profiler {
Ok(profiler) => {
crate::ty::query::QueryName::register_with_profiler(&profiler);
sess.err("Linker plugin based LTO is not supported together with \
`-C prefer-dynamic` when targeting MSVC");
}
+
+ // Make sure that any given profiling data actually exists so LLVM can't
+ // decide to silently skip PGO.
+ if let Some(ref path) = sess.opts.debugging_opts.pgo_use {
+ if !path.exists() {
+ sess.err(&format!("File `{}` passed to `-Zpgo-use` does not exist.",
+ path.display()));
+ }
+ }
}
/// Hash value constructed out of all the `-C metadata` arguments passed to the
tcx.arena.alloc_from_iter(
supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
let trait_methods = tcx.associated_items(trait_ref.def_id())
- .filter(|item| item.kind == ty::AssociatedKind::Method);
+ .filter(|item| item.kind == ty::AssocKind::Method);
// Now list each method's DefId and InternalSubsts (for within its trait).
// If the method can never be called from this object, produce None.
Method(ast::Name, MethodViolationCode),
/// Associated const.
- AssociatedConst(ast::Name),
+ AssocConst(ast::Name),
}
impl ObjectSafetyViolation {
format!("method `{}` has generic type parameters", name).into(),
ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver) =>
format!("method `{}`'s receiver cannot be dispatched on", name).into(),
- ObjectSafetyViolation::AssociatedConst(name) =>
+ ObjectSafetyViolation::AssocConst(name) =>
format!("the trait cannot contain associated consts like `{}`", name).into(),
}
}
{
// Check methods for violations.
let mut violations: Vec<_> = self.associated_items(trait_def_id)
- .filter(|item| item.kind == ty::AssociatedKind::Method)
+ .filter(|item| item.kind == ty::AssocKind::Method)
.filter_map(|item|
self.object_safety_violation_for_method(trait_def_id, &item)
.map(|code| ObjectSafetyViolation::Method(item.ident.name, code))
}
violations.extend(self.associated_items(trait_def_id)
- .filter(|item| item.kind == ty::AssociatedKind::Const)
- .map(|item| ObjectSafetyViolation::AssociatedConst(item.ident.name)));
+ .filter(|item| item.kind == ty::AssocKind::Const)
+ .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name)));
debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
trait_def_id,
/// Returns `Some(_)` if this method makes the containing trait not object safe.
fn object_safety_violation_for_method(self,
trait_def_id: DefId,
- method: &ty::AssociatedItem)
+ method: &ty::AssocItem)
-> Option<MethodViolationCode>
{
debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method);
/// otherwise ensure that they cannot be used when `Self=Trait`.
pub fn is_vtable_safe_method(self,
trait_def_id: DefId,
- method: &ty::AssociatedItem)
+ method: &ty::AssocItem)
-> bool
{
debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
/// `Self:Sized`.
fn virtual_call_violation_for_method(self,
trait_def_id: DefId,
- method: &ty::AssociatedItem)
+ method: &ty::AssocItem)
-> Option<MethodViolationCode>
{
// The method's first parameter must be named `self`
self.associated_items(super_trait_ref.def_id())
.map(move |item| (super_trait_ref, item))
})
- .filter(|(_, item)| item.kind == ty::AssociatedKind::Type)
+ .filter(|(_, item)| item.kind == ty::AssocKind::Type)
.collect::<Vec<_>>();
// existential predicates need to be in a specific order
#[allow(dead_code)]
fn receiver_is_dispatchable(
self,
- method: &ty::AssociatedItem,
+ method: &ty::AssocItem,
receiver_ty: Ty<'tcx>,
) -> bool {
debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
Ok(result)
}
- fn verify(&self,
- tcx: TyCtxt<'a, 'gcx, 'tcx>,
- trait_def_id: DefId,
- span: Span)
- -> Result<(), ErrorReported>
- {
+ fn verify(
+ &self,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ trait_def_id: DefId,
+ span: Span,
+ ) -> Result<(), ErrorReported> {
let name = tcx.item_name(trait_def_id);
let generics = tcx.generics_of(trait_def_id);
let parser = Parser::new(&self.0, None, vec![], false);
result
}
- pub fn format(&self,
- tcx: TyCtxt<'a, 'gcx, 'tcx>,
- trait_ref: ty::TraitRef<'tcx>,
- options: &FxHashMap<String, String>)
- -> String
- {
+ pub fn format(
+ &self,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ trait_ref: ty::TraitRef<'tcx>,
+ options: &FxHashMap<String, String>,
+ ) -> String {
let name = tcx.item_name(trait_ref.def_id);
let trait_str = tcx.def_path_str(trait_ref.def_id);
let generics = tcx.generics_of(trait_ref.def_id);
where T : TypeFoldable<'tcx>
{
debug!("normalize_with_depth(depth={}, value={:?})", depth, value);
- let mut normalizer = AssociatedTypeNormalizer::new(selcx, param_env, cause, depth);
+ let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth);
let result = normalizer.fold(value);
debug!("normalize_with_depth: depth={} result={:?} with {} obligations",
depth, result, normalizer.obligations.len());
}
}
-struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> {
+struct AssocTypeNormalizer<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> {
selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
depth: usize,
}
-impl<'a, 'b, 'gcx, 'tcx> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> {
+impl<'a, 'b, 'gcx, 'tcx> AssocTypeNormalizer<'a, 'b, 'gcx, 'tcx> {
fn new(selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
depth: usize)
- -> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx>
+ -> AssocTypeNormalizer<'a, 'b, 'gcx, 'tcx>
{
- AssociatedTypeNormalizer {
+ AssocTypeNormalizer {
selcx,
param_env,
cause,
}
}
-impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> {
+impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssocTypeNormalizer<'a, 'b, 'gcx, 'tcx> {
fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'tcx> {
self.selcx.tcx()
}
self.cause.clone(),
self.depth,
&mut self.obligations);
- debug!("AssociatedTypeNormalizer: depth={} normalized {:?} to {:?}, \
+ debug!("AssocTypeNormalizer: depth={} normalized {:?} to {:?}, \
now with {} obligations",
self.depth, ty, normalized_ty, self.obligations.len());
normalized_ty
};
if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
let substs = tcx.lift_to_global(&substs).unwrap();
- let evaluated = tcx.mk_const(evaluated);
let evaluated = evaluated.subst(tcx, substs);
return evaluated;
}
promoted: None
};
if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
- return tcx.mk_const(evaluated);
+ return evaluated;
}
}
}
projected_obligations);
let result = if projected_ty.has_projections() {
- let mut normalizer = AssociatedTypeNormalizer::new(selcx,
+ let mut normalizer = AssocTypeNormalizer::new(selcx,
param_env,
cause,
depth+1);
};
}
let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node);
- let ty = if let ty::AssociatedKind::Existential = assoc_ty.item.kind {
+ let ty = if let ty::AssocKind::Existential = assoc_ty.item.kind {
let item_substs = InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id);
tcx.mk_opaque(assoc_ty.item.def_id, item_substs)
} else {
selcx: &SelectionContext<'cx, 'gcx, 'tcx>,
impl_def_id: DefId,
assoc_ty_def_id: DefId)
- -> specialization_graph::NodeItem<ty::AssociatedItem>
+ -> specialization_graph::NodeItem<ty::AssocItem>
{
let tcx = selcx.tcx();
let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident;
// cycle error if the specialization graph is currently being built.
let impl_node = specialization_graph::Node::Impl(impl_def_id);
for item in impl_node.items(tcx) {
- if item.kind == ty::AssociatedKind::Type &&
+ if item.kind == ty::AssocKind::Type &&
tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id) {
return specialization_graph::NodeItem {
node: specialization_graph::Node::Impl(impl_def_id),
if let Some(assoc_item) = trait_def
.ancestors(tcx, impl_def_id)
- .defs(tcx, assoc_ty_name, ty::AssociatedKind::Type, trait_def_id)
+ .defs(tcx, assoc_ty_name, ty::AssocKind::Type, trait_def_id)
.next() {
assoc_item
} else {
};
if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
let substs = tcx.lift_to_global(&substs).unwrap();
- let evaluated = tcx.mk_const(evaluated);
let evaluated = evaluated.subst(tcx, substs);
return evaluated;
}
promoted: None,
};
if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
- return tcx.mk_const(evaluated);
+ return evaluated;
}
}
}
pub fn find_associated_item<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
- item: &ty::AssociatedItem,
+ item: &ty::AssocItem,
substs: SubstsRef<'tcx>,
impl_data: &super::VtableImplData<'tcx, ()>,
) -> (DefId, SubstsRef<'tcx>) {
pub fn items(
&self,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
- ) -> ty::AssociatedItemsIterator<'a, 'gcx, 'tcx> {
+ ) -> ty::AssocItemsIterator<'a, 'gcx, 'tcx> {
tcx.associated_items(self.def_id())
}
self,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
trait_item_name: Ident,
- trait_item_kind: ty::AssociatedKind,
+ trait_item_kind: ty::AssocKind,
trait_def_id: DefId,
- ) -> impl Iterator<Item = NodeItem<ty::AssociatedItem>> + Captures<'gcx> + Captures<'tcx> + 'a {
+ ) -> impl Iterator<Item = NodeItem<ty::AssocItem>> + Captures<'gcx> + Captures<'tcx> + 'a {
self.flat_map(move |node| {
- use crate::ty::AssociatedKind::*;
+ use crate::ty::AssocKind::*;
node.items(tcx).filter(move |impl_item| match (trait_item_kind, impl_item.kind) {
| (Const, Const)
| (Method, Method)
// Count number of methods and add them to the total offset.
// Skip over associated types and constants.
for trait_item in self.associated_items(trait_ref.def_id()) {
- if trait_item.kind == ty::AssociatedKind::Method {
+ if trait_item.kind == ty::AssocKind::Method {
entries += 1;
}
}
for trait_item in self.associated_items(object.upcast_trait_ref.def_id()) {
if trait_item.def_id == method_def_id {
// The item with the ID we were given really ought to be a method.
- assert_eq!(trait_item.kind, ty::AssociatedKind::Method);
+ assert_eq!(trait_item.kind, ty::AssocKind::Method);
return entries;
}
- if trait_item.kind == ty::AssociatedKind::Method {
+ if trait_item.kind == ty::AssocKind::Method {
entries += 1;
}
}
hir::MutMutable => tcx.lang_items().deref_mut_trait()
};
let method_def_id = tcx.associated_items(trait_def_id.unwrap())
- .find(|m| m.kind == ty::AssociatedKind::Method).unwrap().def_id;
+ .find(|m| m.kind == ty::AssocKind::Method).unwrap().def_id;
(method_def_id, tcx.mk_substs_trait(source, &[]))
}
}
use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault};
use crate::middle::stability;
use crate::mir::{self, Mir, interpret, ProjectionKind};
-use crate::mir::interpret::{ConstValue, Allocation};
+use crate::mir::interpret::{ConstValue, Allocation, Scalar};
use crate::ty::subst::{Kind, InternalSubsts, SubstsRef, Subst};
use crate::ty::ReprOptions;
use crate::traits;
};
CommonConsts {
- err: mk_const(ty::Const::zero_sized(types.err)),
+ err: mk_const(ty::Const {
+ val: ConstValue::Scalar(Scalar::Bits { bits: 0, size: 0 }),
+ ty: types.err,
+ }),
}
}
}
// this is the impl for `&'a InternalSubsts<'a>`
nop_list_lift!{Kind<'a> => Kind<'tcx>}
-impl<'a, 'tcx> Lift<'tcx> for &'a mir::interpret::Allocation {
- type Lifted = &'tcx mir::interpret::Allocation;
- fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
- assert!(tcx.global_arenas.const_allocs.in_arena(*self as *const _));
- Some(unsafe { mem::transmute(*self) })
- }
-}
-
pub mod tls {
use super::{GlobalCtxt, TyCtxt, ptr_eq};
#[inline]
pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
- self.mk_ty(Array(ty, self.mk_const(
- ty::Const::from_usize(self.global_tcx(), n)
- )))
+ self.mk_ty(Array(ty, ty::Const::from_usize(self.global_tcx(), n)))
}
#[inline]
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
let flags = FlagComputation::for_const(c);
debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags);
- flags.intersects(self.flags) || c.super_visit_with(self)
+ flags.intersects(self.flags)
}
}
fn resolve_associated_item<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- trait_item: &ty::AssociatedItem,
+ trait_item: &ty::AssocItem,
param_env: ty::ParamEnv<'tcx>,
trait_id: DefId,
rcvr_substs: SubstsRef<'tcx>,
substs);
let fn_once = tcx.lang_items().fn_once_trait().unwrap();
let call_once = tcx.associated_items(fn_once)
- .find(|it| it.kind == ty::AssociatedKind::Method)
+ .find(|it| it.kind == ty::AssocKind::Method)
.unwrap().def_id;
let def = ty::InstanceDef::ClosureOnceShim { call_once };
#![allow(usage_of_ty_tykind)]
pub use self::Variance::*;
-pub use self::AssociatedItemContainer::*;
+pub use self::AssocItemContainer::*;
pub use self::BorrowKind::*;
pub use self::IntVarValue::*;
pub use self::fold::TypeFoldable;
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
-pub enum AssociatedItemContainer {
+pub enum AssocItemContainer {
TraitContainer(DefId),
ImplContainer(DefId),
}
-impl AssociatedItemContainer {
+impl AssocItemContainer {
/// Asserts that this is the `DefId` of an associated item declared
/// in a trait, and returns the trait `DefId`.
pub fn assert_trait(&self) -> DefId {
}
#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
-pub struct AssociatedItem {
+pub struct AssocItem {
pub def_id: DefId,
#[stable_hasher(project(name))]
pub ident: Ident,
- pub kind: AssociatedKind,
+ pub kind: AssocKind,
pub vis: Visibility,
pub defaultness: hir::Defaultness,
- pub container: AssociatedItemContainer,
+ pub container: AssocItemContainer,
/// Whether this is a method with an explicit self
/// as its first argument, allowing method calls.
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, RustcEncodable, RustcDecodable, HashStable)]
-pub enum AssociatedKind {
+pub enum AssocKind {
Const,
Method,
Existential,
Type
}
-impl AssociatedItem {
+impl AssocItem {
pub fn def_kind(&self) -> DefKind {
match self.kind {
- AssociatedKind::Const => DefKind::AssociatedConst,
- AssociatedKind::Method => DefKind::Method,
- AssociatedKind::Type => DefKind::AssociatedTy,
- AssociatedKind::Existential => DefKind::AssociatedExistential,
+ AssocKind::Const => DefKind::AssocConst,
+ AssocKind::Method => DefKind::Method,
+ AssocKind::Type => DefKind::AssocTy,
+ AssocKind::Existential => DefKind::AssocExistential,
}
}
/// for !
pub fn relevant_for_never<'tcx>(&self) -> bool {
match self.kind {
- AssociatedKind::Existential |
- AssociatedKind::Const |
- AssociatedKind::Type => true,
+ AssocKind::Existential |
+ AssocKind::Const |
+ AssocKind::Type => true,
// FIXME(canndrew): Be more thorough here, check if any argument is uninhabited.
- AssociatedKind::Method => !self.method_has_self_argument,
+ AssocKind::Method => !self.method_has_self_argument,
}
}
pub fn signature<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
match self.kind {
- ty::AssociatedKind::Method => {
+ ty::AssocKind::Method => {
// We skip the binder here because the binder would deanonymize all
// late-bound regions, and we don't want method signatures to show up
// `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
// regions just fine, showing `fn(&MyType)`.
tcx.fn_sig(self.def_id).skip_binder().to_string()
}
- ty::AssociatedKind::Type => format!("type {};", self.ident),
- ty::AssociatedKind::Existential => format!("existential type {};", self.ident),
- ty::AssociatedKind::Const => {
+ ty::AssocKind::Type => format!("type {};", self.ident),
+ ty::AssocKind::Existential => format!("existential type {};", self.ident),
+ ty::AssocKind::Const => {
format!("const {}: {:?};", self.ident, tcx.type_of(self.def_id))
}
}
Res::Def(DefKind::Variant, vid) => self.variant_with_id(vid),
Res::Def(DefKind::Ctor(..), cid) => self.variant_with_ctor_id(cid),
Res::Def(DefKind::Struct, _) | Res::Def(DefKind::Union, _) |
- Res::Def(DefKind::TyAlias, _) | Res::Def(DefKind::AssociatedTy, _) | Res::SelfTy(..) |
+ Res::Def(DefKind::TyAlias, _) | Res::Def(DefKind::AssocTy, _) | Res::SelfTy(..) |
Res::SelfCtor(..) => self.non_enum_variant(),
_ => bug!("unexpected res {:?} in variant_of_res", res)
}
}
}
- pub fn provided_trait_methods(self, id: DefId) -> Vec<AssociatedItem> {
+ pub fn provided_trait_methods(self, id: DefId) -> Vec<AssocItem> {
self.associated_items(id)
- .filter(|item| item.kind == AssociatedKind::Method && item.defaultness.has_value())
+ .filter(|item| item.kind == AssocKind::Method && item.defaultness.has_value())
.collect()
}
})
}
- pub fn opt_associated_item(self, def_id: DefId) -> Option<AssociatedItem> {
+ pub fn opt_associated_item(self, def_id: DefId) -> Option<AssocItem> {
let is_associated_item = if let Some(hir_id) = self.hir().as_local_hir_id(def_id) {
match self.hir().get_by_hir_id(hir_id) {
Node::TraitItem(_) | Node::ImplItem(_) => true,
}
} else {
match self.def_kind(def_id).expect("no def for def-id") {
- DefKind::AssociatedConst
+ DefKind::AssocConst
| DefKind::Method
- | DefKind::AssociatedTy => true,
+ | DefKind::AssocTy => true,
_ => false,
}
};
parent_def_id: DefId,
parent_vis: &hir::Visibility,
trait_item_ref: &hir::TraitItemRef)
- -> AssociatedItem {
+ -> AssocItem {
let def_id = self.hir().local_def_id_from_hir_id(trait_item_ref.id.hir_id);
let (kind, has_self) = match trait_item_ref.kind {
- hir::AssociatedItemKind::Const => (ty::AssociatedKind::Const, false),
- hir::AssociatedItemKind::Method { has_self } => {
- (ty::AssociatedKind::Method, has_self)
+ hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
+ hir::AssocItemKind::Method { has_self } => {
+ (ty::AssocKind::Method, has_self)
}
- hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false),
- hir::AssociatedItemKind::Existential => bug!("only impls can have existentials"),
+ hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
+ hir::AssocItemKind::Existential => bug!("only impls can have existentials"),
};
- AssociatedItem {
+ AssocItem {
ident: trait_item_ref.ident,
kind,
// Visibility of trait items is inherited from their traits.
fn associated_item_from_impl_item_ref(self,
parent_def_id: DefId,
impl_item_ref: &hir::ImplItemRef)
- -> AssociatedItem {
+ -> AssocItem {
let def_id = self.hir().local_def_id_from_hir_id(impl_item_ref.id.hir_id);
let (kind, has_self) = match impl_item_ref.kind {
- hir::AssociatedItemKind::Const => (ty::AssociatedKind::Const, false),
- hir::AssociatedItemKind::Method { has_self } => {
- (ty::AssociatedKind::Method, has_self)
+ hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
+ hir::AssocItemKind::Method { has_self } => {
+ (ty::AssocKind::Method, has_self)
}
- hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false),
- hir::AssociatedItemKind::Existential => (ty::AssociatedKind::Existential, false),
+ hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
+ hir::AssocItemKind::Existential => (ty::AssocKind::Existential, false),
};
- AssociatedItem {
+ AssocItem {
ident: impl_item_ref.ident,
kind,
// Visibility of trait impl items doesn't matter.
pub fn associated_items(
self,
def_id: DefId,
- ) -> AssociatedItemsIterator<'a, 'gcx, 'tcx> {
+ ) -> AssocItemsIterator<'a, 'gcx, 'tcx> {
// Ideally, we would use `-> impl Iterator` here, but it falls
// afoul of the conservative "capture [restrictions]" we put
// in place, so we use a hand-written iterator.
//
// [restrictions]: https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999
- AssociatedItemsIterator {
+ AssocItemsIterator {
tcx: self,
def_ids: self.associated_item_def_ids(def_id),
next_index: 0,
}
}
-pub struct AssociatedItemsIterator<'a, 'gcx: 'tcx, 'tcx: 'a> {
+pub struct AssocItemsIterator<'a, 'gcx: 'tcx, 'tcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
def_ids: &'gcx [DefId],
next_index: usize,
}
-impl Iterator for AssociatedItemsIterator<'_, '_, '_> {
- type Item = AssociatedItem;
+impl Iterator for AssocItemsIterator<'_, '_, '_> {
+ type Item = AssocItem;
- fn next(&mut self) -> Option<AssociatedItem> {
+ fn next(&mut self) -> Option<AssocItem> {
let def_id = self.def_ids.get(self.next_index)?;
self.next_index += 1;
Some(self.tcx.associated_item(*def_id))
}
}
-fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> AssociatedItem {
+fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> AssocItem {
let id = tcx.hir().as_local_hir_id(def_id).unwrap();
let parent_id = tcx.hir().get_parent_item(id);
let parent_def_id = tcx.hir().local_def_id_from_hir_id(parent_id);
type Region;
type Type;
type DynExistential;
+ type Const;
fn tcx(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
) -> Result<Self::DynExistential, Self::Error>;
+ fn print_const(
+ self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<Self::Const, Self::Error>;
+
fn path_crate(
self,
cnum: CrateNum,
cx.print_dyn_existential(self)
}
}
+
+impl<'gcx: 'tcx, 'tcx, P: Printer<'gcx, 'tcx>> Print<'gcx, 'tcx, P> for &'tcx ty::Const<'tcx> {
+ type Output = P::Const;
+ type Error = P::Error;
+ fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
+ cx.print_const(self)
+ }
+}
use crate::hir;
-use crate::hir::def::Namespace;
+use crate::hir::def::{Namespace, DefKind};
use crate::hir::map::{DefPathData, DisambiguatedDefPathData};
use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use crate::middle::cstore::{ExternCrate, ExternCrateSource};
use crate::middle::region;
use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
use crate::ty::subst::{Kind, Subst, UnpackedKind};
-use crate::mir::interpret::ConstValue;
+use crate::ty::layout::Size;
+use crate::mir::interpret::{ConstValue, sign_extend, Scalar};
+use syntax::ast;
+use rustc_apfloat::ieee::{Double, Single};
+use rustc_apfloat::Float;
use rustc_target::spec::abi::Abi;
use syntax::symbol::{kw, InternedString};
Region = Self,
Type = Self,
DynExistential = Self,
+ Const = Self,
> +
fmt::Write
{
},
ty::Array(ty, sz) => {
p!(write("["), print(ty), write("; "));
- match sz.val {
- ConstValue::Unevaluated(..) |
- ConstValue::Infer(..) => p!(write("_")),
- ConstValue::Param(ParamConst { name, .. }) =>
- p!(write("{}", name)),
- _ => p!(write("{}", sz.unwrap_usize(self.tcx()))),
+ if let Some(n) = sz.assert_usize(self.tcx()) {
+ p!(write("{}", n));
+ } else {
+ p!(write("_"));
}
p!(write("]"))
}
Ok(self)
}
+
+ fn pretty_print_const(
+ mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<Self::Const, Self::Error> {
+ define_scoped_cx!(self);
+
+ let u8 = self.tcx().types.u8;
+ if let ty::FnDef(did, substs) = ct.ty.sty {
+ p!(print_value_path(did, substs));
+ return Ok(self);
+ }
+ if let ConstValue::Unevaluated(did, substs) = ct.val {
+ match self.tcx().def_kind(did) {
+ | Some(DefKind::Static)
+ | Some(DefKind::Const)
+ | Some(DefKind::AssocConst) => p!(print_value_path(did, substs)),
+ _ => if did.is_local() {
+ let span = self.tcx().def_span(did);
+ if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
+ p!(write("{}", snip))
+ } else {
+ p!(write("_: "), print(ct.ty))
+ }
+ } else {
+ p!(write("_: "), print(ct.ty))
+ },
+ }
+ return Ok(self);
+ }
+ if let ConstValue::Infer(..) = ct.val {
+ p!(write("_: "), print(ct.ty));
+ return Ok(self);
+ }
+ if let ConstValue::Param(ParamConst { name, .. }) = ct.val {
+ p!(write("{}", name));
+ return Ok(self);
+ }
+ if let ConstValue::Scalar(Scalar::Bits { bits, .. }) = ct.val {
+ match ct.ty.sty {
+ ty::Bool => {
+ p!(write("{}", if bits == 0 { "false" } else { "true" }));
+ return Ok(self);
+ },
+ ty::Float(ast::FloatTy::F32) => {
+ p!(write("{}f32", Single::from_bits(bits)));
+ return Ok(self);
+ },
+ ty::Float(ast::FloatTy::F64) => {
+ p!(write("{}f64", Double::from_bits(bits)));
+ return Ok(self);
+ },
+ ty::Uint(ui) => {
+ p!(write("{}{}", bits, ui));
+ return Ok(self);
+ },
+ ty::Int(i) =>{
+ let ty = self.tcx().lift_to_global(&ct.ty).unwrap();
+ let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty))
+ .unwrap()
+ .size;
+ p!(write("{}{}", sign_extend(bits, size) as i128, i));
+ return Ok(self);
+ },
+ ty::Char => {
+ p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap()));
+ return Ok(self);
+ }
+ _ => {},
+ }
+ }
+ if let ty::Ref(_, ref_ty, _) = ct.ty.sty {
+ let byte_str = match (ct.val, &ref_ty.sty) {
+ (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => {
+ let n = n.unwrap_usize(self.tcx());
+ Some(self.tcx()
+ .alloc_map.lock()
+ .unwrap_memory(ptr.alloc_id)
+ .get_bytes(&self.tcx(), ptr, Size::from_bytes(n)).unwrap())
+ },
+ (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => {
+ Some(&data.bytes[start..end])
+ },
+ (ConstValue::Slice { data, start, end }, ty::Str) => {
+ let slice = &data.bytes[start..end];
+ let s = ::std::str::from_utf8(slice)
+ .expect("non utf8 str from miri");
+ p!(write("{:?}", s));
+ return Ok(self);
+ },
+ _ => None,
+ };
+ if let Some(byte_str) = byte_str {
+ p!(write("b\""));
+ for &c in byte_str {
+ for e in std::ascii::escape_default(c) {
+ self.write_char(e as char)?;
+ }
+ }
+ p!(write("\""));
+ return Ok(self);
+ }
+ }
+ p!(write("{:?} : ", ct.val), print(ct.ty));
+
+ Ok(self)
+ }
}
// HACK(eddyb) boxed to avoid moving around a large struct by-value.
type Region = Self;
type Type = Self;
type DynExistential = Self;
+ type Const = Self;
fn tcx(&'a self) -> TyCtxt<'a, 'gcx, 'tcx> {
self.tcx
self.pretty_print_dyn_existential(predicates)
}
+ fn print_const(
+ self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<Self::Const, Self::Error> {
+ self.pretty_print_const(ct)
+ }
+
fn path_crate(
mut self,
cnum: CrateNum,
forward_display_to_print! {
Ty<'tcx>,
&'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
+ &'tcx ty::Const<'tcx>,
// HACK(eddyb) these are exhaustive instead of generic,
// because `for<'gcx: 'tcx, 'tcx>` isn't possible yet.
p!(print_def_path(self.def_id, self.substs));
}
- &'tcx ty::Const<'tcx> {
- match self.val {
- ConstValue::Unevaluated(..) |
- ConstValue::Infer(..) => p!(write("_")),
- ConstValue::Param(ParamConst { name, .. }) => p!(write("{}", name)),
- _ => p!(write("{:?}", self)),
- }
- }
-
ty::ParamTy {
p!(write("{}", self.name))
}
use crate::hir::def::Namespace;
use crate::mir::ProjectionKind;
use crate::mir::interpret::ConstValue;
-use crate::ty::{self, Lift, Ty, TyCtxt, ConstVid, InferConst};
+use crate::ty::{self, Lift, Ty, TyCtxt, InferConst};
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use crate::ty::print::{FmtPrinter, Printer};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use crate::mir::interpret;
use std::fmt;
-use std::marker::PhantomData;
use std::rc::Rc;
impl fmt::Debug for ty::GenericParamDef {
}
}
-impl<'a, 'tcx> Lift<'tcx> for ConstVid<'a> {
- type Lifted = ConstVid<'tcx>;
- fn lift_to_tcx<'b, 'gcx>(&self, _: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
- Some(ConstVid {
- index: self.index,
- phantom: PhantomData,
- })
- }
-}
-
///////////////////////////////////////////////////////////////////////////
// TypeFoldable implementations.
//
ConstValue::Param(p) => ConstValue::Param(p.fold_with(folder)),
ConstValue::Placeholder(p) => ConstValue::Placeholder(p),
ConstValue::Scalar(a) => ConstValue::Scalar(a),
- ConstValue::Slice(a, b) => ConstValue::Slice(a, b),
+ ConstValue::Slice { data, start, end } => ConstValue::Slice { data, start, end },
ConstValue::Unevaluated(did, substs)
=> ConstValue::Unevaluated(did, substs.fold_with(folder)),
}
ConstValue::Param(p) => p.visit_with(visitor),
ConstValue::Placeholder(_) => false,
ConstValue::Scalar(_) => false,
- ConstValue::Slice(..) => false,
+ ConstValue::Slice { .. } => false,
ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor),
}
}
tcx: TyCtxt<'_, '_, '_>, trait_ref: ty::TraitRef<'tcx>, item_name: Ident
) -> ProjectionTy<'tcx> {
let item_def_id = tcx.associated_items(trait_ref.def_id).find(|item| {
- item.kind == ty::AssociatedKind::Type &&
+ item.kind == ty::AssocKind::Type &&
tcx.hygienic_eq(item_name, item.ident, trait_ref.def_id)
}).unwrap().def_id;
}
#[cfg(target_arch = "x86_64")]
-static_assert_size!(Const<'_>, 48);
+static_assert_size!(Const<'_>, 40);
impl<'tcx> Const<'tcx> {
#[inline]
pub fn from_scalar(
+ tcx: TyCtxt<'_, '_, 'tcx>,
val: Scalar,
ty: Ty<'tcx>,
- ) -> Self {
- Self {
+ ) -> &'tcx Self {
+ tcx.mk_const(Self {
val: ConstValue::Scalar(val),
ty,
- }
+ })
}
#[inline]
tcx: TyCtxt<'_, '_, 'tcx>,
bits: u128,
ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
- ) -> Self {
+ ) -> &'tcx Self {
let ty = tcx.lift_to_global(&ty).unwrap();
let size = tcx.layout_of(ty).unwrap_or_else(|e| {
panic!("could not compute layout for {:?}: {:?}", ty, e)
}).size;
let truncated = truncate(bits, size);
assert_eq!(truncated, bits, "from_bits called with untruncated value");
- Self::from_scalar(Scalar::Bits { bits, size: size.bytes() as u8 }, ty.value)
+ Self::from_scalar(tcx, Scalar::Bits { bits, size: size.bytes() as u8 }, ty.value)
}
#[inline]
- pub fn zero_sized(ty: Ty<'tcx>) -> Self {
- Self::from_scalar(Scalar::Bits { bits: 0, size: 0 }, ty)
+ pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
+ Self::from_scalar(tcx, Scalar::Bits { bits: 0, size: 0 }, ty)
}
#[inline]
- pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> Self {
+ pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> &'tcx Self {
Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool))
}
#[inline]
- pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> Self {
+ pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> &'tcx Self {
Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
}
// the specialized routine `ty::replace_late_regions()`.
match *r {
ty::ReEarlyBound(data) => {
- let r = self.substs.get(data.index as usize).map(|k| k.unpack());
- match r {
+ let rk = self.substs.get(data.index as usize).map(|k| k.unpack());
+ match rk {
Some(UnpackedKind::Lifetime(lt)) => {
self.shift_region_through_binders(lt)
}
_ => {
let span = self.span.unwrap_or(DUMMY_SP);
- span_bug!(
- span,
+ let msg = format!(
"Region parameter out of range \
when substituting in region {} (root type={:?}) \
(index={})",
data.name,
self.root_ty,
data.index);
+ self.tcx.sess.delay_span_bug(span, &msg);
+ r
}
}
}
use std::borrow::Cow;
use std::error::Error;
+use std::fs;
use std::mem::{self, Discriminant};
+use std::path::Path;
use std::process;
use std::thread::ThreadId;
use std::u32;
}
impl SelfProfiler {
- pub fn new(event_filters: &Option<Vec<String>>) -> Result<SelfProfiler, Box<dyn Error>> {
- let filename = format!("pid-{}.rustc_profile", process::id());
- let path = std::path::Path::new(&filename);
- let profiler = Profiler::new(path)?;
+ pub fn new(
+ output_directory: &Path,
+ crate_name: Option<&str>,
+ event_filters: &Option<Vec<String>>
+ ) -> Result<SelfProfiler, Box<dyn Error>> {
+ fs::create_dir_all(output_directory)?;
+
+ let crate_name = crate_name.unwrap_or("unknown-crate");
+ let filename = format!("{}-{}.rustc_profile", crate_name, process::id());
+ let path = output_directory.join(&filename);
+ let profiler = Profiler::new(&path)?;
let query_event_kind = profiler.alloc_string("Query");
let generic_activity_event_kind = profiler.alloc_string("GenericActivity");
call_site: item.span, // use the call site of the static
def_site: None,
format: MacroAttribute(Symbol::intern(name)),
- allow_internal_unstable: Some(vec![
- Symbol::intern("rustc_attrs"),
- ].into()),
+ allow_internal_unstable: Some(vec![sym::rustc_attrs].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
edition: self.sess.edition,
}
fn attrs(&self) -> Vec<Attribute> {
- let special = Symbol::intern("rustc_std_internal_symbol");
+ let special = sym::rustc_std_internal_symbol;
let special = self.cx.meta_word(self.span, special);
vec![self.cx.attribute(self.span, special)]
}
use rustc::hir::def_id::LOCAL_CRATE;
use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, run_assembler};
use rustc_codegen_ssa::traits::*;
-use rustc::session::config::{self, OutputType, Passes, Lto, PgoGenerate};
+use rustc::session::config::{self, OutputType, Passes, Lto, SwitchWithOptPath};
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc_codegen_ssa::{RLIB_BYTECODE_EXTENSION, ModuleCodegen, CompiledModule};
let inline_threshold = config.inline_threshold;
let pgo_gen_path = match config.pgo_gen {
- PgoGenerate::Enabled(ref opt_dir_path) => {
+ SwitchWithOptPath::Enabled(ref opt_dir_path) => {
let path = if let Some(dir_path) = opt_dir_path {
dir_path.join("default_%m.profraw")
} else {
Some(CString::new(format!("{}", path.display())).unwrap())
}
- PgoGenerate::Disabled => {
+ SwitchWithOptPath::Disabled => {
None
}
};
- let pgo_use_path = if config.pgo_use.is_empty() {
- None
- } else {
- Some(CString::new(config.pgo_use.as_bytes()).unwrap())
- };
+ let pgo_use_path = config.pgo_use.as_ref().map(|path_buf| {
+ CString::new(path_buf.to_string_lossy().as_bytes()).unwrap()
+ });
llvm::LLVMRustConfigurePassManagerBuilder(
builder,
use rustc::dep_graph::cgu_reuse_tracker::CguReuseTracker;
use rustc::middle::cstore::EncodedMetadata;
use rustc::session::config::{self, OutputFilenames, OutputType, Passes, Lto,
- Sanitizer, PgoGenerate};
+ Sanitizer, SwitchWithOptPath};
use rustc::session::Session;
use rustc::util::nodemap::FxHashMap;
use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
/// Some(level) to optimize binary size, or None to not affect program size.
pub opt_size: Option<config::OptLevel>,
- pub pgo_gen: PgoGenerate,
- pub pgo_use: String,
+ pub pgo_gen: SwitchWithOptPath,
+ pub pgo_use: Option<PathBuf>,
// Flags indicating which outputs to produce.
pub emit_pre_lto_bc: bool,
opt_level: None,
opt_size: None,
- pgo_gen: PgoGenerate::Disabled,
- pgo_use: String::new(),
+ pgo_gen: SwitchWithOptPath::Disabled,
+ pgo_use: None,
emit_no_opt_bc: false,
emit_pre_lto_bc: false,
pub fn eval_mir_constant(
&mut self,
constant: &mir::Constant<'tcx>,
- ) -> Result<ty::Const<'tcx>, ErrorHandled> {
+ ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> {
match constant.literal.val {
mir::interpret::ConstValue::Unevaluated(def_id, ref substs) => {
let substs = self.monomorphize(substs);
};
self.cx.tcx().const_eval(ty::ParamEnv::reveal_all().and(cid))
},
- _ => Ok(*self.monomorphize(&constant.literal)),
+ _ => Ok(self.monomorphize(&constant.literal)),
}
}
bx: &Bx,
span: Span,
ty: Ty<'tcx>,
- constant: Result<ty::Const<'tcx>, ErrorHandled>,
+ constant: Result<&'tcx ty::Const<'tcx>, ErrorHandled>,
) -> (Bx::Value, Ty<'tcx>) {
constant
.map(|c| {
-use rustc::mir::interpret::{ConstValue, ErrorHandled};
+use rustc::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar};
use rustc::mir;
use rustc::ty;
-use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
+use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, Size};
use crate::base;
use crate::MemFlags;
pub fn from_const<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
- val: ty::Const<'tcx>
+ val: &'tcx ty::Const<'tcx>
) -> Result<Self, ErrorHandled> {
let layout = bx.layout_of(val.ty);
);
OperandValue::Immediate(llval)
},
- ConstValue::Slice(a, b) => {
+ ConstValue::Slice { data, start, end } => {
let a_scalar = match layout.abi {
layout::Abi::ScalarPair(ref a, _) => a,
_ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout)
};
+ let a = Scalar::from(Pointer::new(
+ bx.tcx().alloc_map.lock().allocate(data),
+ Size::from_bytes(start as u64),
+ )).into();
let a_llval = bx.scalar_to_backend(
a,
a_scalar,
bx.scalar_pair_element_backend_type(layout, 0, true),
);
- let b_llval = bx.const_usize(b);
+ let b_llval = bx.const_usize((end - start) as u64);
OperandValue::Pair(a_llval, b_llval)
},
ConstValue::ByRef(ptr, alloc) => {
use rustc::ty::query::Providers;
use rustc::ty::subst::{Kind, SubstsRef, UnpackedKind};
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::mir::interpret::{ConstValue, Scalar};
use rustc::util::common::record_time;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_mir::monomorphize::item::{InstantiationMode, MonoItem, MonoItemExt};
type Region = Self;
type Type = Self;
type DynExistential = Self;
+ type Const = Self;
fn tcx(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
self.tcx
Ok(self)
}
+ fn print_const(
+ mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<Self::Const, Self::Error> {
+ // only print integers
+ if let ConstValue::Scalar(Scalar::Bits { .. }) = ct.val {
+ if ct.ty.is_integral() {
+ return self.pretty_print_const(ct);
+ }
+ }
+ self.write_str("_")?;
+ Ok(self)
+ }
+
fn path_crate(
mut self,
cnum: CrateNum,
sess: &Session,
codegen_backend: &dyn CodegenBackend,
) {
- let tf = Symbol::intern("target_feature");
+ let tf = sym::target_feature;
cfg.extend(
codegen_backend
{
let next_edition = match cx.sess.edition() {
Edition::Edition2015 => {
- match &ident.as_str()[..] {
- "async" | "await" | "try" => Edition::Edition2018,
+ match ident.name {
+ kw::Async | kw::Await | kw::Try => Edition::Edition2018,
// rust-lang/rust#56327: Conservatively do not
// attempt to report occurrences of `dyn` within
// its precise role in the parsed AST and thus are
// assured this is truly an attempt to use it as
// an identifier.
- "dyn" if !under_macro => Edition::Edition2018,
+ kw::Dyn if !under_macro => Edition::Edition2018,
_ => return,
}
let mut keyword_stream = quote! {};
let mut symbols_stream = quote! {};
+ let mut digits_stream = quote! {};
let mut prefill_stream = quote! {};
let mut counter = 0u32;
let mut keys = HashSet::<String>::new();
}
};
+ // Generate the listed keywords.
for keyword in &input.keywords.0 {
let name = &keyword.name;
let value = &keyword.value;
counter += 1;
}
+ // Generate the listed symbols.
for symbol in &input.symbols.0 {
let name = &symbol.name;
let value = match &symbol.value {
counter += 1;
}
+ // Generate symbols for the strings "0", "1", ..., "9".
+ for n in 0..10 {
+ let n = n.to_string();
+ check_dup(&n);
+ prefill_stream.extend(quote! {
+ #n,
+ });
+ digits_stream.extend(quote! {
+ Symbol::new(#counter),
+ });
+ counter += 1;
+ }
+
let tt = TokenStream::from(quote! {
macro_rules! keywords {
() => {
macro_rules! symbols {
() => {
#symbols_stream
+
+ pub const digits_array: &[Symbol; 10] = &[
+ #digits_stream
+ ];
}
}
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
let ext = SyntaxExtension::ProcMacro {
expander: Box::new(BangProcMacro { client }),
- allow_internal_unstable: Some(vec![
- Symbol::intern("proc_macro_def_site"),
- ].into()),
+ allow_internal_unstable: Some(vec![sym::proc_macro_def_site].into()),
edition: data.root.edition,
};
return LoadedMacro::ProcMacro(Lrc::new(ext));
})
}
- pub fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssociatedItem {
+ pub fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssocItem {
self.get_crate_data(def.krate).get_associated_item(def.index)
}
}
fn def_kind(&self) -> Option<DefKind> {
Some(match *self {
EntryKind::Const(..) => DefKind::Const,
- EntryKind::AssociatedConst(..) => DefKind::AssociatedConst,
+ EntryKind::AssocConst(..) => DefKind::AssocConst,
EntryKind::ImmStatic |
EntryKind::MutStatic |
EntryKind::ForeignImmStatic |
EntryKind::TypeParam => DefKind::TyParam,
EntryKind::ConstParam => DefKind::ConstParam,
EntryKind::Existential => DefKind::Existential,
- EntryKind::AssociatedType(_) => DefKind::AssociatedTy,
- EntryKind::AssociatedExistential(_) => DefKind::AssociatedExistential,
+ EntryKind::AssocType(_) => DefKind::AssocTy,
+ EntryKind::AssocExistential(_) => DefKind::AssocExistential,
EntryKind::Mod(_) => DefKind::Mod,
EntryKind::Variant(_) => DefKind::Variant,
EntryKind::Trait(_) => DefKind::Trait,
pub fn const_is_rvalue_promotable_to_static(&self, id: DefIndex) -> bool {
match self.entry(id).kind {
- EntryKind::AssociatedConst(_, data, _) |
+ EntryKind::AssocConst(_, data, _) |
EntryKind::Const(data, _) => data.ast_promotable,
_ => bug!(),
}
pub fn mir_const_qualif(&self, id: DefIndex) -> u8 {
match self.entry(id).kind {
EntryKind::Const(qualif, _) |
- EntryKind::AssociatedConst(AssociatedContainer::ImplDefault, qualif, _) |
- EntryKind::AssociatedConst(AssociatedContainer::ImplFinal, qualif, _) => {
+ EntryKind::AssocConst(AssocContainer::ImplDefault, qualif, _) |
+ EntryKind::AssocConst(AssocContainer::ImplFinal, qualif, _) => {
qualif.mir
}
_ => bug!(),
}
}
- pub fn get_associated_item(&self, id: DefIndex) -> ty::AssociatedItem {
+ pub fn get_associated_item(&self, id: DefIndex) -> ty::AssocItem {
let item = self.entry(id);
let def_key = self.def_key(id);
let parent = self.local_def_id(def_key.parent.unwrap());
let name = def_key.disambiguated_data.data.get_opt_name().unwrap();
let (kind, container, has_self) = match item.kind {
- EntryKind::AssociatedConst(container, _, _) => {
- (ty::AssociatedKind::Const, container, false)
+ EntryKind::AssocConst(container, _, _) => {
+ (ty::AssocKind::Const, container, false)
}
EntryKind::Method(data) => {
let data = data.decode(self);
- (ty::AssociatedKind::Method, data.container, data.has_self)
+ (ty::AssocKind::Method, data.container, data.has_self)
}
- EntryKind::AssociatedType(container) => {
- (ty::AssociatedKind::Type, container, false)
+ EntryKind::AssocType(container) => {
+ (ty::AssocKind::Type, container, false)
}
- EntryKind::AssociatedExistential(container) => {
- (ty::AssociatedKind::Existential, container, false)
+ EntryKind::AssocExistential(container) => {
+ (ty::AssocKind::Existential, container, false)
}
_ => bug!("cannot get associated-item of `{:?}`", def_key)
};
- ty::AssociatedItem {
+ ty::AssocItem {
ident: Ident::from_interned_str(name),
kind,
vis: item.visibility.decode(self),
pub fn get_rendered_const(&self, id: DefIndex) -> String {
match self.entry(id).kind {
EntryKind::Const(_, data) |
- EntryKind::AssociatedConst(_, _, data) => data.decode(self).0,
+ EntryKind::AssocConst(_, _, data) => data.decode(self).0,
_ => bug!(),
}
}
let container = match trait_item.defaultness {
hir::Defaultness::Default { has_value: true } =>
- AssociatedContainer::TraitWithDefault,
+ AssocContainer::TraitWithDefault,
hir::Defaultness::Default { has_value: false } =>
- AssociatedContainer::TraitRequired,
+ AssocContainer::TraitRequired,
hir::Defaultness::Final =>
span_bug!(ast_item.span, "traits cannot have final items"),
};
let kind = match trait_item.kind {
- ty::AssociatedKind::Const => {
+ ty::AssocKind::Const => {
let const_qualif =
if let hir::TraitItemKind::Const(_, Some(body)) = ast_item.node {
self.const_qualif(0, body)
hir::print::to_string(self.tcx.hir(), |s| s.print_trait_item(ast_item));
let rendered_const = self.lazy(&RenderedConst(rendered));
- EntryKind::AssociatedConst(container, const_qualif, rendered_const)
+ EntryKind::AssocConst(container, const_qualif, rendered_const)
}
- ty::AssociatedKind::Method => {
+ ty::AssocKind::Method => {
let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node {
let arg_names = match *m {
hir::TraitMethod::Required(ref names) => {
has_self: trait_item.method_has_self_argument,
}))
}
- ty::AssociatedKind::Type => EntryKind::AssociatedType(container),
- ty::AssociatedKind::Existential =>
+ ty::AssocKind::Type => EntryKind::AssocType(container),
+ ty::AssocKind::Existential =>
span_bug!(ast_item.span, "existential type in trait"),
};
deprecation: self.encode_deprecation(def_id),
ty: match trait_item.kind {
- ty::AssociatedKind::Const |
- ty::AssociatedKind::Method => {
+ ty::AssocKind::Const |
+ ty::AssocKind::Method => {
Some(self.encode_item_type(def_id))
}
- ty::AssociatedKind::Type => {
+ ty::AssocKind::Type => {
if trait_item.defaultness.has_value() {
Some(self.encode_item_type(def_id))
} else {
None
}
}
- ty::AssociatedKind::Existential => unreachable!(),
+ ty::AssocKind::Existential => unreachable!(),
},
inherent_impls: LazySeq::empty(),
- variances: if trait_item.kind == ty::AssociatedKind::Method {
+ variances: if trait_item.kind == ty::AssocKind::Method {
self.encode_variances_of(def_id)
} else {
LazySeq::empty()
let impl_item = self.tcx.associated_item(def_id);
let container = match impl_item.defaultness {
- hir::Defaultness::Default { has_value: true } => AssociatedContainer::ImplDefault,
- hir::Defaultness::Final => AssociatedContainer::ImplFinal,
+ hir::Defaultness::Default { has_value: true } => AssocContainer::ImplDefault,
+ hir::Defaultness::Final => AssocContainer::ImplFinal,
hir::Defaultness::Default { has_value: false } =>
span_bug!(ast_item.span, "impl items always have values (currently)"),
};
let kind = match impl_item.kind {
- ty::AssociatedKind::Const => {
+ ty::AssocKind::Const => {
if let hir::ImplItemKind::Const(_, body_id) = ast_item.node {
let mir = self.tcx.at(ast_item.span).mir_const_qualif(def_id).0;
- EntryKind::AssociatedConst(container,
+ EntryKind::AssocConst(container,
self.const_qualif(mir, body_id),
self.encode_rendered_const_for_body(body_id))
} else {
bug!()
}
}
- ty::AssociatedKind::Method => {
+ ty::AssocKind::Method => {
let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
FnData {
constness: sig.header.constness,
has_self: impl_item.method_has_self_argument,
}))
}
- ty::AssociatedKind::Existential => EntryKind::AssociatedExistential(container),
- ty::AssociatedKind::Type => EntryKind::AssociatedType(container)
+ ty::AssocKind::Existential => EntryKind::AssocExistential(container),
+ ty::AssocKind::Type => EntryKind::AssocType(container)
};
let mir =
ty: Some(self.encode_item_type(def_id)),
inherent_impls: LazySeq::empty(),
- variances: if impl_item.kind == ty::AssociatedKind::Method {
+ variances: if impl_item.kind == ty::AssocKind::Method {
self.encode_variances_of(def_id)
} else {
LazySeq::empty()
Trait(Lazy<TraitData<'tcx>>),
Impl(Lazy<ImplData<'tcx>>),
Method(Lazy<MethodData<'tcx>>),
- AssociatedType(AssociatedContainer),
- AssociatedExistential(AssociatedContainer),
- AssociatedConst(AssociatedContainer, ConstQualif, Lazy<RenderedConst>),
+ AssocType(AssocContainer),
+ AssocExistential(AssocContainer),
+ AssocConst(AssocContainer, ConstQualif, Lazy<RenderedConst>),
TraitAlias(Lazy<TraitAliasData<'tcx>>),
}
-/// Additional data for EntryKind::Const and EntryKind::AssociatedConst
+/// Additional data for EntryKind::Const and EntryKind::AssocConst
#[derive(Clone, Copy, RustcEncodable, RustcDecodable)]
pub struct ConstQualif {
pub mir: u8,
/// is a trait or an impl and whether, in a trait, it has
/// a default, or an in impl, whether it's marked "default".
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
-pub enum AssociatedContainer {
+pub enum AssocContainer {
TraitRequired,
TraitWithDefault,
ImplDefault,
ImplFinal,
}
-impl AssociatedContainer {
- pub fn with_def_id(&self, def_id: DefId) -> ty::AssociatedItemContainer {
+impl AssocContainer {
+ pub fn with_def_id(&self, def_id: DefId) -> ty::AssocItemContainer {
match *self {
- AssociatedContainer::TraitRequired |
- AssociatedContainer::TraitWithDefault => ty::TraitContainer(def_id),
+ AssocContainer::TraitRequired |
+ AssocContainer::TraitWithDefault => ty::TraitContainer(def_id),
- AssociatedContainer::ImplDefault |
- AssociatedContainer::ImplFinal => ty::ImplContainer(def_id),
+ AssocContainer::ImplDefault |
+ AssocContainer::ImplFinal => ty::ImplContainer(def_id),
}
}
pub fn defaultness(&self) -> hir::Defaultness {
match *self {
- AssociatedContainer::TraitRequired => hir::Defaultness::Default {
+ AssocContainer::TraitRequired => hir::Defaultness::Default {
has_value: false,
},
- AssociatedContainer::TraitWithDefault |
- AssociatedContainer::ImplDefault => hir::Defaultness::Default {
+ AssocContainer::TraitWithDefault |
+ AssocContainer::ImplDefault => hir::Defaultness::Default {
has_value: true,
},
- AssociatedContainer::ImplFinal => hir::Defaultness::Final,
+ AssocContainer::ImplFinal => hir::Defaultness::Final,
}
}
}
#[derive(RustcEncodable, RustcDecodable)]
pub struct MethodData<'tcx> {
pub fn_data: FnData<'tcx>,
- pub container: AssociatedContainer,
+ pub container: AssocContainer,
pub has_self: bool,
}
span,
format!("value moved{} here, in previous iteration of loop", move_msg),
);
- if Some(CompilerDesugaringKind::ForLoop) == span.compiler_desugaring_kind() {
- if let Ok(snippet) = self.infcx.tcx.sess.source_map()
- .span_to_snippet(span)
- {
- err.span_suggestion(
- move_span,
- "consider borrowing this to avoid moving it into the for loop",
- format!("&{}", snippet),
- Applicability::MaybeIncorrect,
- );
- }
- }
is_loop_move = true;
} else if move_site.traversed_back_edge {
err.span_label(
&mut err,
format!("variable moved due to use{}", move_spans.describe()),
);
- };
+ }
+ if Some(CompilerDesugaringKind::ForLoop) == move_span.compiler_desugaring_kind() {
+ if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
+ err.span_suggestion(
+ move_span,
+ "consider borrowing to avoid moving into the for loop",
+ format!("&{}", snippet),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
}
use_spans.var_span_label(
let (mut err, err_span) = {
let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind<'_>) =
match error {
- GroupedMoveError::MovesFromPlace {
- span,
- ref original_path,
- ref kind,
- ..
- } |
+ 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)
debug!("report: original_path={:?} span={:?}, kind={:?} \
original_path.is_upvar_field_projection={:?}", original_path, span, kind,
self.is_upvar_field_projection(original_path));
- (
- match kind {
- IllegalMoveOriginKind::Static => {
- self.infcx.tcx.cannot_move_out_of(span, "static item", origin)
- }
- IllegalMoveOriginKind::BorrowedContent { target_place: place } => {
- // Inspect the type of the content behind the
- // borrow to provide feedback about why this
- // was a move rather than a copy.
- let ty = place.ty(self.mir, self.infcx.tcx).ty;
- let is_upvar_field_projection =
- self.prefixes(&original_path, PrefixSet::All)
- .any(|p| self.is_upvar_field_projection(p).is_some());
- debug!("report: ty={:?}", ty);
- match ty.sty {
- ty::Array(..) | ty::Slice(..) =>
- self.infcx.tcx.cannot_move_out_of_interior_noncopy(
- span, ty, None, origin
- ),
- ty::Closure(def_id, closure_substs)
- if def_id == self.mir_def_id && is_upvar_field_projection
- => {
- let closure_kind_ty =
- closure_substs.closure_kind_ty(def_id, self.infcx.tcx);
- let closure_kind = closure_kind_ty.to_opt_closure_kind();
- let place_description = match closure_kind {
- Some(ty::ClosureKind::Fn) => {
- "captured variable in an `Fn` closure"
- }
- Some(ty::ClosureKind::FnMut) => {
- "captured variable in an `FnMut` closure"
- }
- Some(ty::ClosureKind::FnOnce) => {
- bug!("closure kind does not match first argument type")
- }
- None => bug!("closure kind not inferred by borrowck"),
- };
- debug!("report: closure_kind_ty={:?} closure_kind={:?} \
- place_description={:?}", closure_kind_ty, closure_kind,
- place_description);
-
- let mut diag = self.infcx.tcx.cannot_move_out_of(
- span, place_description, origin);
-
- for prefix in self.prefixes(&original_path, PrefixSet::All) {
- if let Some(field) = self.is_upvar_field_projection(prefix) {
- let upvar_hir_id = self.upvars[field.index()].var_hir_id;
- let upvar_span = self.infcx.tcx.hir().span_by_hir_id(
- upvar_hir_id);
- diag.span_label(upvar_span, "captured outer variable");
- break;
- }
+ let err = match kind {
+ IllegalMoveOriginKind::Static => {
+ self.infcx.tcx.cannot_move_out_of(span, "static item", origin)
+ }
+ IllegalMoveOriginKind::BorrowedContent { target_place: place } => {
+ // Inspect the type of the content behind the
+ // borrow to provide feedback about why this
+ // was a move rather than a copy.
+ let ty = place.ty(self.mir, self.infcx.tcx).ty;
+ let is_upvar_field_projection =
+ self.prefixes(&original_path, PrefixSet::All)
+ .any(|p| self.is_upvar_field_projection(p).is_some());
+ debug!("report: ty={:?}", ty);
+ let mut err = match ty.sty {
+ ty::Array(..) | ty::Slice(..) =>
+ self.infcx.tcx.cannot_move_out_of_interior_noncopy(
+ span, ty, None, origin
+ ),
+ ty::Closure(def_id, closure_substs)
+ if def_id == self.mir_def_id && is_upvar_field_projection
+ => {
+ let closure_kind_ty =
+ closure_substs.closure_kind_ty(def_id, self.infcx.tcx);
+ let closure_kind = closure_kind_ty.to_opt_closure_kind();
+ let place_description = match closure_kind {
+ Some(ty::ClosureKind::Fn) => {
+ "captured variable in an `Fn` closure"
+ }
+ Some(ty::ClosureKind::FnMut) => {
+ "captured variable in an `FnMut` closure"
+ }
+ Some(ty::ClosureKind::FnOnce) => {
+ bug!("closure kind does not match first argument type")
+ }
+ None => bug!("closure kind not inferred by borrowck"),
+ };
+ debug!("report: closure_kind_ty={:?} closure_kind={:?} \
+ place_description={:?}", closure_kind_ty, closure_kind,
+ place_description);
+
+ let mut diag = self.infcx.tcx.cannot_move_out_of(
+ span, place_description, origin);
+
+ for prefix in self.prefixes(&original_path, PrefixSet::All) {
+ if let Some(field) = self.is_upvar_field_projection(prefix) {
+ let upvar_hir_id = self.upvars[field.index()].var_hir_id;
+ let upvar_span = self.infcx.tcx.hir().span_by_hir_id(
+ upvar_hir_id);
+ diag.span_label(upvar_span, "captured outer variable");
+ break;
}
-
- diag
}
- _ => {
- let source = self.borrowed_content_source(place);
- self.infcx.tcx.cannot_move_out_of(
- span, &source.to_string(), origin
- )
- },
+
+ diag
}
+ _ => {
+ let source = self.borrowed_content_source(place);
+ self.infcx.tcx.cannot_move_out_of(
+ span, &source.to_string(), origin
+ )
+ },
+ };
+ let orig_path_ty = format!(
+ "{:?}",
+ original_path.ty(self.mir, self.infcx.tcx).ty,
+ );
+ let snippet = self.infcx.tcx.sess.source_map().span_to_snippet(span).unwrap();
+ let is_option = orig_path_ty.starts_with("std::option::Option");
+ let is_result = orig_path_ty.starts_with("std::result::Result");
+ if is_option || is_result {
+ err.span_suggestion(
+ span,
+ &format!("consider borrowing the `{}`'s content", if is_option {
+ "Option"
+ } else {
+ "Result"
+ }),
+ format!("{}.as_ref()", snippet),
+ Applicability::MaybeIncorrect,
+ );
}
- IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
- self.infcx.tcx
- .cannot_move_out_of_interior_of_drop(span, ty, origin)
- }
- IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } =>
- self.infcx.tcx.cannot_move_out_of_interior_noncopy(
- span, ty, Some(*is_index), origin
- ),
- },
- span,
- )
+ err
+ }
+ IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
+ self.infcx.tcx
+ .cannot_move_out_of_interior_of_drop(span, ty, origin)
+ }
+ IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } =>
+ self.infcx.tcx.cannot_move_out_of_interior_noncopy(
+ span, ty, Some(*is_index), origin
+ ),
+ };
+ (err, span)
};
self.add_move_hints(error, &mut err, err_span);
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::mir::interpret::{InterpError::BoundsCheck, ConstValue};
use rustc::mir::tcx::PlaceTy;
-use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
+use rustc::mir::visit::{PlaceContext, Visitor, NonMutatingUseContext};
use rustc::mir::*;
use rustc::traits::query::type_op;
use rustc::traits::query::type_op::custom::CustomTypeOp;
context: PlaceContext,
) -> PlaceTy<'tcx> {
debug!("sanitize_place: {:?}", place);
- let place_ty = match place {
- Place::Base(PlaceBase::Local(index)) =>
- PlaceTy::from_ty(self.mir.local_decls[*index].ty),
- Place::Base(PlaceBase::Static(box Static { kind, ty: sty })) => {
- let sty = self.sanitize_type(place, sty);
- let check_err =
- |verifier: &mut TypeVerifier<'a, 'b, 'gcx, 'tcx>,
- place: &Place<'tcx>,
- ty,
- sty| {
- if let Err(terr) = verifier.cx.eq_types(
- sty,
- ty,
- location.to_locations(),
- ConstraintCategory::Boring,
- ) {
- span_mirbug!(
- verifier,
- place,
- "bad promoted type ({:?}: {:?}): {:?}",
- ty,
- sty,
- terr
- );
+
+ place.iterate(|place_base, place_projection| {
+ let mut place_ty = match place_base {
+ PlaceBase::Local(index) =>
+ PlaceTy::from_ty(self.mir.local_decls[*index].ty),
+ PlaceBase::Static(box Static { kind, ty: sty }) => {
+ let sty = self.sanitize_type(place, sty);
+ let check_err =
+ |verifier: &mut TypeVerifier<'a, 'b, 'gcx, 'tcx>,
+ place: &Place<'tcx>,
+ ty,
+ sty| {
+ if let Err(terr) = verifier.cx.eq_types(
+ sty,
+ ty,
+ location.to_locations(),
+ ConstraintCategory::Boring,
+ ) {
+ span_mirbug!(
+ verifier,
+ place,
+ "bad promoted type ({:?}: {:?}): {:?}",
+ ty,
+ sty,
+ terr
+ );
+ };
};
- };
- match kind {
- StaticKind::Promoted(promoted) => {
- if !self.errors_reported {
- let promoted_mir = &self.mir.promoted[*promoted];
- self.sanitize_promoted(promoted_mir, location);
-
- let promoted_ty = promoted_mir.return_ty();
- check_err(self, place, promoted_ty, sty);
+ match kind {
+ StaticKind::Promoted(promoted) => {
+ if !self.errors_reported {
+ let promoted_mir = &self.mir.promoted[*promoted];
+ self.sanitize_promoted(promoted_mir, location);
+
+ let promoted_ty = promoted_mir.return_ty();
+ check_err(self, place, promoted_ty, sty);
+ }
}
- }
- StaticKind::Static(def_id) => {
- let ty = self.tcx().type_of(*def_id);
- let ty = self.cx.normalize(ty, location);
+ StaticKind::Static(def_id) => {
+ let ty = self.tcx().type_of(*def_id);
+ let ty = self.cx.normalize(ty, location);
- check_err(self, place, ty, sty);
+ check_err(self, place, ty, sty);
+ }
}
+ PlaceTy::from_ty(sty)
+ }
+ };
+
+ // FIXME use place_projection.is_empty() when is available
+ if let Place::Base(_) = place {
+ if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
+ let tcx = self.tcx();
+ let trait_ref = ty::TraitRef {
+ def_id: tcx.lang_items().copy_trait().unwrap(),
+ substs: tcx.mk_substs_trait(place_ty.ty, &[]),
+ };
+
+ // In order to have a Copy operand, the type T of the
+ // value must be Copy. Note that we prove that T: Copy,
+ // rather than using the `is_copy_modulo_regions`
+ // test. This is important because
+ // `is_copy_modulo_regions` ignores the resulting region
+ // obligations and assumes they pass. This can result in
+ // bounds from Copy impls being unsoundly ignored (e.g.,
+ // #29149). Note that we decide to use Copy before knowing
+ // whether the bounds fully apply: in effect, the rule is
+ // that if a value of some type could implement Copy, then
+ // it must.
+ self.cx.prove_trait_ref(
+ trait_ref,
+ location.to_locations(),
+ ConstraintCategory::CopyBound,
+ );
}
- PlaceTy::from_ty(sty)
}
- Place::Projection(ref proj) => {
- let base_context = if context.is_mutating_use() {
- PlaceContext::MutatingUse(MutatingUseContext::Projection)
- } else {
- PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
- };
- let base_ty = self.sanitize_place(&proj.base, location, base_context);
- if base_ty.variant_index.is_none() {
- if base_ty.ty.references_error() {
+
+ for proj in place_projection {
+ if place_ty.variant_index.is_none() {
+ if place_ty.ty.references_error() {
assert!(self.errors_reported);
return PlaceTy::from_ty(self.tcx().types.err);
}
}
- self.sanitize_projection(base_ty, &proj.elem, place, location)
+ place_ty = self.sanitize_projection(place_ty, &proj.elem, place, location)
}
- };
- if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
- let tcx = self.tcx();
- let trait_ref = ty::TraitRef {
- def_id: tcx.lang_items().copy_trait().unwrap(),
- substs: tcx.mk_substs_trait(place_ty.ty, &[]),
- };
- // In order to have a Copy operand, the type T of the
- // value must be Copy. Note that we prove that T: Copy,
- // rather than using the `is_copy_modulo_regions`
- // test. This is important because
- // `is_copy_modulo_regions` ignores the resulting region
- // obligations and assumes they pass. This can result in
- // bounds from Copy impls being unsoundly ignored (e.g.,
- // #29149). Note that we decide to use Copy before knowing
- // whether the bounds fully apply: in effect, the rule is
- // that if a value of some type could implement Copy, then
- // it must.
- self.cx.prove_trait_ref(
- trait_ref,
- location.to_locations(),
- ConstraintCategory::CopyBound,
- );
- }
- place_ty
+ place_ty
+ })
}
fn sanitize_promoted(&mut self, promoted_mir: &'b Mir<'tcx>, location: Location) {
/// Determines if a given borrow is borrowing local data
/// This is called for all Yield statements on movable generators
pub(super) fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool {
- match place {
- Place::Base(PlaceBase::Static(..)) => false,
- Place::Base(PlaceBase::Local(..)) => true,
- Place::Projection(box proj) => {
- match proj.elem {
- // Reborrow of already borrowed data is ignored
- // Any errors will be caught on the initial borrow
- ProjectionElem::Deref => false,
+ place.iterate(|place_base, place_projection| {
+ match place_base {
+ PlaceBase::Static(..) => return false,
+ PlaceBase::Local(..) => {},
+ }
- // For interior references and downcasts, find out if the base is local
- ProjectionElem::Field(..)
- | ProjectionElem::Index(..)
- | ProjectionElem::ConstantIndex { .. }
- | ProjectionElem::Subslice { .. }
- | ProjectionElem::Downcast(..) => borrow_of_local_data(&proj.base),
+ for proj in place_projection {
+ // Reborrow of already borrowed data is ignored
+ // Any errors will be caught on the initial borrow
+ if proj.elem == ProjectionElem::Deref {
+ return false;
}
}
- }
+
+ true
+ })
}
mir: &Mir<'tcx>,
locals_state_at_exit: &LocalsStateAtExit,
) -> bool {
- match self {
- // If a local variable is immutable, then we only need to track borrows to guard
- // against two kinds of errors:
- // * The variable being dropped while still borrowed (e.g., because the fn returns
- // a reference to a local variable)
- // * The variable being moved while still borrowed
- //
- // In particular, the variable cannot be mutated -- the "access checks" will fail --
- // so we don't have to worry about mutation while borrowed.
- Place::Base(PlaceBase::Local(index)) => {
- match locals_state_at_exit {
- LocalsStateAtExit::AllAreInvalidated => false,
- LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
- let ignore = !has_storage_dead_or_moved.contains(*index) &&
- mir.local_decls[*index].mutability == Mutability::Not;
- debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
- ignore
+ self.iterate(|place_base, place_projection| {
+ let ignore = match place_base {
+ // If a local variable is immutable, then we only need to track borrows to guard
+ // against two kinds of errors:
+ // * The variable being dropped while still borrowed (e.g., because the fn returns
+ // a reference to a local variable)
+ // * The variable being moved while still borrowed
+ //
+ // In particular, the variable cannot be mutated -- the "access checks" will fail --
+ // so we don't have to worry about mutation while borrowed.
+ PlaceBase::Local(index) => {
+ match locals_state_at_exit {
+ LocalsStateAtExit::AllAreInvalidated => false,
+ LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
+ let ignore = !has_storage_dead_or_moved.contains(*index) &&
+ mir.local_decls[*index].mutability == Mutability::Not;
+ debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
+ ignore
+ }
}
}
- }
- Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) =>
- false,
- Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => {
- tcx.is_mutable_static(*def_id)
- }
- Place::Projection(proj) => match proj.elem {
- ProjectionElem::Field(..)
- | ProjectionElem::Downcast(..)
- | ProjectionElem::Subslice { .. }
- | ProjectionElem::ConstantIndex { .. }
- | ProjectionElem::Index(_) => proj.base.ignore_borrow(
- tcx, mir, locals_state_at_exit),
+ PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) =>
+ false,
+ PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => {
+ tcx.is_mutable_static(*def_id)
+ }
+ };
- ProjectionElem::Deref => {
+ for proj in place_projection {
+ if proj.elem == ProjectionElem::Deref {
let ty = proj.base.ty(mir, tcx).ty;
match ty.sty {
// For both derefs of raw pointers and `&T`
// original path into a new variable and
// borrowed *that* one, leaving the original
// path unborrowed.
- ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => true,
- _ => proj.base.ignore_borrow(tcx, mir, locals_state_at_exit),
+ ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => return true,
+ _ => {}
}
}
- },
- }
+ }
+
+ ignore
+ })
}
}
}) => {
// Not projected from the implicit `self` in a closure.
debug_assert!(
- match *base {
- Place::Base(PlaceBase::Local(local)) => local == Local::new(1),
- Place::Projection(box Projection {
- ref base,
- elem: ProjectionElem::Deref,
- }) => *base == Place::Base(PlaceBase::Local(Local::new(1))),
- _ => false,
+ match base.local() {
+ Some(local) => local == Local::new(1),
+ None => false,
},
"Unexpected capture place"
);
SwitchInt {
switch_ty: Ty<'tcx>,
options: Vec<u128>,
- indices: FxHashMap<ty::Const<'tcx>, usize>,
+ indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
},
// test for equality
Eq {
- value: ty::Const<'tcx>,
+ value: &'tcx ty::Const<'tcx>,
ty: Ty<'tcx>,
},
candidate: &Candidate<'pat, 'tcx>,
switch_ty: Ty<'tcx>,
options: &mut Vec<u128>,
- indices: &mut FxHashMap<ty::Const<'tcx>, usize>)
+ indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>)
-> bool
{
let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
}
let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap();
let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty.into()]);
- let method = self.hir.tcx().mk_const(method);
let re_erased = self.hir.tcx().lifetimes.re_erased;
// take the argument by reference
TestKind::Range(PatternRange { ref lo, ref hi, ty, ref end }) => {
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
- let lo = self.literal_operand(test.span, ty.clone(), lo.clone());
- let hi = self.literal_operand(test.span, ty.clone(), hi.clone());
+ let lo = self.literal_operand(test.span, ty, lo);
+ let hi = self.literal_operand(test.span, ty, hi);
let val = Operand::Copy(place.clone());
let fail = self.cfg.start_new_block();
fn const_range_contains(
&self,
range: PatternRange<'tcx>,
- value: ty::Const<'tcx>,
+ value: &'tcx ty::Const<'tcx>,
) -> Option<bool> {
use std::cmp::Ordering::*;
fn values_not_contained_in_range(
&self,
range: PatternRange<'tcx>,
- indices: &FxHashMap<ty::Const<'tcx>, usize>,
+ indices: &FxHashMap<&'tcx ty::Const<'tcx>, usize>,
) -> Option<bool> {
for &val in indices.keys() {
if self.const_range_contains(range, val)? {
pub fn literal_operand(&mut self,
span: Span,
ty: Ty<'tcx>,
- literal: ty::Const<'tcx>)
+ literal: &'tcx ty::Const<'tcx>)
-> Operand<'tcx> {
let constant = box Constant {
span,
ty,
user_ty: None,
- literal: self.hir.tcx().mk_const(literal),
+ literal,
};
Operand::Constant(constant)
}
use std::borrow::{Borrow, Cow};
use std::hash::Hash;
use std::collections::hash_map::Entry;
+use std::convert::TryInto;
use rustc::hir::def::DefKind;
use rustc::hir::def_id::DefId;
fn mplace_to_const<'tcx>(
ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
mplace: MPlaceTy<'tcx>,
-) -> ty::Const<'tcx> {
+) -> &'tcx ty::Const<'tcx> {
let MemPlace { ptr, align, meta } = *mplace;
// extract alloc-offset pair
assert!(meta.is_none());
// interned this? I thought that is the entire point of that `FinishStatic` stuff?
let alloc = ecx.tcx.intern_const_alloc(alloc);
let val = ConstValue::ByRef(ptr, alloc);
- ty::Const { val, ty: mplace.layout.ty }
+ ecx.tcx.mk_const(ty::Const { val, ty: mplace.layout.ty })
}
fn op_to_const<'tcx>(
ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
op: OpTy<'tcx>,
-) -> ty::Const<'tcx> {
+) -> &'tcx ty::Const<'tcx> {
// We do not normalize just any data. Only non-union scalars and slices.
let normalize = match op.layout.abi {
layout::Abi::Scalar(..) => op.layout.ty.ty_adt_def().map_or(true, |adt| !adt.is_union()),
- layout::Abi::ScalarPair(..) => op.layout.ty.is_slice(),
+ layout::Abi::ScalarPair(..) => match op.layout.ty.sty {
+ ty::Ref(_, inner, _) => match inner.sty {
+ ty::Slice(elem) => elem == ecx.tcx.types.u8,
+ ty::Str => true,
+ _ => false,
+ },
+ _ => false,
+ },
_ => false,
};
let normalized_op = if normalize {
Ok(mplace) => return mplace_to_const(ecx, mplace),
Err(Immediate::Scalar(x)) =>
ConstValue::Scalar(x.not_undef().unwrap()),
- Err(Immediate::ScalarPair(a, b)) =>
- ConstValue::Slice(a.not_undef().unwrap(), b.to_usize(ecx).unwrap()),
+ Err(Immediate::ScalarPair(a, b)) => {
+ let (data, start) = match a.not_undef().unwrap() {
+ Scalar::Ptr(ptr) => (
+ ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id),
+ ptr.offset.bytes(),
+ ),
+ Scalar::Bits { .. } => (
+ ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(b"", ())),
+ 0,
+ ),
+ };
+ let len = b.to_usize(&ecx.tcx.tcx).unwrap();
+ let start = start.try_into().unwrap();
+ let len: usize = len.try_into().unwrap();
+ ConstValue::Slice {
+ data,
+ start,
+ end: start + len,
+ }
+ },
};
- ty::Const { val, ty: op.layout.ty }
+ ecx.tcx.mk_const(ty::Const { val, ty: op.layout.ty })
}
// Returns a pointer to where the result lives
param_env: ty::ParamEnv<'tcx>,
variant: Option<VariantIdx>,
field: mir::Field,
- value: ty::Const<'tcx>,
-) -> ty::Const<'tcx> {
+ value: &'tcx ty::Const<'tcx>,
+) -> &'tcx ty::Const<'tcx> {
trace!("const_field: {:?}, {:?}", field, value);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
// get the operand again
pub fn const_variant_index<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
- val: ty::Const<'tcx>,
+ val: &'tcx ty::Const<'tcx>,
) -> VariantIdx {
trace!("const_variant_index: {:?}", val);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
// note that validation may still cause a hard error on this very same constant,
// because any code that existed before validation could not have failed validation
// thus preventing such a hard error from being a backwards compatibility hazard
- Some(DefKind::Const) | Some(DefKind::AssociatedConst) => {
+ Some(DefKind::Const) | Some(DefKind::AssocConst) => {
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
err.report_as_lint(
tcx.at(tcx.def_span(def_id)),
}
fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
- match *place {
- Place::Base(PlaceBase::Local(l)) => Some(l),
- Place::Base(PlaceBase::Static(..)) => None,
- Place::Projection(ref proj) => {
- match proj.elem {
- ProjectionElem::Deref => None,
- _ => find_local(&proj.base)
+ place.iterate(|place_base, place_projection| {
+ for proj in place_projection {
+ if proj.elem == ProjectionElem::Deref {
+ return None;
}
}
- }
+
+ if let PlaceBase::Local(local) = place_base {
+ Some(*local)
+ } else {
+ None
+ }
+ })
}
impl<'tcx, 'b, 'c> Visitor<'tcx> for BorrowedLocalsVisitor<'b, 'c> {
-> Result<MovePathIndex, MoveError<'tcx>>
{
debug!("lookup({:?})", place);
- match *place {
- Place::Base(PlaceBase::Local(local)) => Ok(self.builder.data.rev_lookup.locals[local]),
- Place::Base(PlaceBase::Static(..)) => {
- Err(MoveError::cannot_move_out_of(self.loc, Static))
- }
- Place::Projection(ref proj) => {
- self.move_path_for_projection(place, proj)
+ place.iterate(|place_base, place_projection| {
+ let mut base = match place_base {
+ PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[*local],
+ PlaceBase::Static(..) => {
+ return Err(MoveError::cannot_move_out_of(self.loc, Static));
+ }
+ };
+
+ for proj in place_projection {
+ let mir = self.builder.mir;
+ let tcx = self.builder.tcx;
+ let place_ty = proj.base.ty(mir, tcx).ty;
+ match place_ty.sty {
+ ty::Ref(..) | ty::RawPtr(..) =>
+ return Err(MoveError::cannot_move_out_of(
+ self.loc,
+ BorrowedContent {
+ target_place: Place::Projection(Box::new(proj.clone())),
+ })),
+ ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() =>
+ return Err(MoveError::cannot_move_out_of(self.loc,
+ InteriorOfTypeWithDestructor {
+ container_ty: place_ty
+ })),
+ // move out of union - always move the entire union
+ ty::Adt(adt, _) if adt.is_union() =>
+ return Err(MoveError::UnionMove { path: base }),
+ ty::Slice(_) =>
+ return Err(MoveError::cannot_move_out_of(
+ self.loc,
+ InteriorOfSliceOrArray {
+ ty: place_ty, is_index: match proj.elem {
+ ProjectionElem::Index(..) => true,
+ _ => false
+ },
+ })),
+ ty::Array(..) => match proj.elem {
+ ProjectionElem::Index(..) =>
+ return Err(MoveError::cannot_move_out_of(
+ self.loc,
+ InteriorOfSliceOrArray {
+ ty: place_ty, is_index: true
+ })),
+ _ => {
+ // FIXME: still badly broken
+ }
+ },
+ _ => {}
+ };
+
+ base = match self
+ .builder
+ .data
+ .rev_lookup
+ .projections
+ .entry((base, proj.elem.lift()))
+ {
+ Entry::Occupied(ent) => *ent.get(),
+ Entry::Vacant(ent) => {
+ let path = MoveDataBuilder::new_move_path(
+ &mut self.builder.data.move_paths,
+ &mut self.builder.data.path_map,
+ &mut self.builder.data.init_path_map,
+ Some(base),
+ Place::Projection(Box::new(proj.clone())),
+ );
+ ent.insert(path);
+ path
+ }
+ };
}
- }
+
+ Ok(base)
+ })
}
fn create_move_path(&mut self, place: &Place<'tcx>) {
// drop), so this not being a valid move path is OK.
let _ = self.move_path_for(place);
}
-
- fn move_path_for_projection(&mut self,
- place: &Place<'tcx>,
- proj: &Projection<'tcx>)
- -> Result<MovePathIndex, MoveError<'tcx>>
- {
- let base = self.move_path_for(&proj.base)?;
- let mir = self.builder.mir;
- let tcx = self.builder.tcx;
- let place_ty = proj.base.ty(mir, tcx).ty;
- match place_ty.sty {
- ty::Ref(..) | ty::RawPtr(..) =>
- return Err(MoveError::cannot_move_out_of(
- self.loc,
- BorrowedContent { target_place: place.clone() })),
- ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() =>
- return Err(MoveError::cannot_move_out_of(self.loc,
- InteriorOfTypeWithDestructor {
- container_ty: place_ty
- })),
- // move out of union - always move the entire union
- ty::Adt(adt, _) if adt.is_union() =>
- return Err(MoveError::UnionMove { path: base }),
- ty::Slice(_) =>
- return Err(MoveError::cannot_move_out_of(
- self.loc,
- InteriorOfSliceOrArray {
- ty: place_ty, is_index: match proj.elem {
- ProjectionElem::Index(..) => true,
- _ => false
- },
- })),
- ty::Array(..) => match proj.elem {
- ProjectionElem::Index(..) =>
- return Err(MoveError::cannot_move_out_of(
- self.loc,
- InteriorOfSliceOrArray {
- ty: place_ty, is_index: true
- })),
- _ => {
- // FIXME: still badly broken
- }
- },
- _ => {}
- };
- match self.builder.data.rev_lookup.projections.entry((base, proj.elem.lift())) {
- Entry::Occupied(ent) => Ok(*ent.get()),
- Entry::Vacant(ent) => {
- let path = MoveDataBuilder::new_move_path(
- &mut self.builder.data.move_paths,
- &mut self.builder.data.path_map,
- &mut self.builder.data.init_path_map,
- Some(base),
- place.clone()
- );
- ent.insert(path);
- Ok(path)
- }
- }
- }
}
impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> {
// unknown place, but will rather return the nearest available
// parent.
pub fn find(&self, place: &Place<'tcx>) -> LookupResult {
- match *place {
- Place::Base(PlaceBase::Local(local)) => LookupResult::Exact(self.locals[local]),
- Place::Base(PlaceBase::Static(..)) => LookupResult::Parent(None),
- Place::Projection(ref proj) => {
- match self.find(&proj.base) {
- LookupResult::Exact(base_path) => {
- match self.projections.get(&(base_path, proj.elem.lift())) {
- Some(&subpath) => LookupResult::Exact(subpath),
- None => LookupResult::Parent(Some(base_path))
- }
- }
- inexact => inexact
+ place.iterate(|place_base, place_projection| {
+ let mut result = match place_base {
+ PlaceBase::Local(local) => self.locals[*local],
+ PlaceBase::Static(..) => return LookupResult::Parent(None),
+ };
+
+ for proj in place_projection {
+ if let Some(&subpath) = self.projections.get(&(result, proj.elem.lift())) {
+ result = subpath;
+ } else {
+ return LookupResult::Parent(Some(result));
}
}
- }
+
+ LookupResult::Exact(result)
+ })
}
pub fn find_local(&self, local: Local) -> MovePathIndex {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
ty: Ty<'tcx>,
neg: bool,
-) -> Result<ty::Const<'tcx>, LitToConstError> {
+) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
use syntax::ast::*;
let trunc = |n| {
let lit = match *lit {
LitKind::Str(ref s, _) => {
let s = s.as_str();
- let id = tcx.allocate_bytes(s.as_bytes());
- ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64)
+ let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes(), ());
+ let allocation = tcx.intern_const_alloc(allocation);
+ ConstValue::Slice { data: allocation, start: 0, end: s.len() }
},
LitKind::Err(ref s) => {
let s = s.as_str();
- let id = tcx.allocate_bytes(s.as_bytes());
- return Ok(ty::Const {
- val: ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64),
+ let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes(), ());
+ let allocation = tcx.intern_const_alloc(allocation);
+ return Ok(tcx.mk_const(ty::Const {
+ val: ConstValue::Slice{ data: allocation, start: 0, end: s.len() },
ty: tcx.types.err,
- });
+ }));
},
LitKind::ByteStr(ref data) => {
let id = tcx.allocate_bytes(data);
LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)),
LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)),
};
- Ok(ty::Const { val: lit, ty })
+ Ok(tcx.mk_const(ty::Const { val: lit, ty }))
}
fn parse_float<'tcx>(
}
hir::ExprKind::Lit(ref lit) => ExprKind::Literal {
- literal: cx.tcx.mk_const(
- cx.const_eval_literal(&lit.node, expr_ty, lit.span, false)
- ),
+ literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false),
user_ty: None,
},
} else {
if let hir::ExprKind::Lit(ref lit) = arg.node {
ExprKind::Literal {
- literal: cx.tcx.mk_const(
- cx.const_eval_literal(&lit.node, expr_ty, lit.span, true)
- ),
+ literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true),
user_ty: None,
}
} else {
ty: var_ty,
span: expr.span,
kind: ExprKind::Literal {
- literal: cx.tcx.mk_const(literal),
+ literal,
user_ty: None
},
}.to_ref();
// in case we are offsetting from a computed discriminant
// and not the beginning of discriminants (which is always `0`)
let substs = InternalSubsts::identity_for_item(cx.tcx(), did);
- let lhs = mk_const(ty::Const {
+ let lhs = mk_const(cx.tcx().mk_const(ty::Const {
val: ConstValue::Unevaluated(did, substs),
ty: var_ty,
- });
+ }));
let bin = ExprKind::Binary {
op: BinOp::Add,
lhs,
Res::Def(DefKind::Method, _) |
Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) |
Res::Def(DefKind::Const, _) |
- Res::Def(DefKind::AssociatedConst, _) =>
+ Res::Def(DefKind::AssocConst, _) =>
cx.tables().user_provided_types().get(hir_id).map(|u_ty| *u_ty),
// A unit struct/variant which is used as a value (e.g.,
ty,
span,
kind: ExprKind::Literal {
- literal: cx.tcx().mk_const(
- ty::Const::zero_sized(ty)
- ),
+ literal: ty::Const::zero_sized(cx.tcx(), ty),
user_ty,
},
}
let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res);
debug!("convert_path_expr: user_ty={:?}", user_ty);
ExprKind::Literal {
- literal: cx.tcx.mk_const(ty::Const::zero_sized(
+ literal: ty::Const::zero_sized(
+ cx.tcx,
cx.tables().node_type(expr.hir_id),
- )),
+ ),
user_ty,
}
}
}
Res::Def(DefKind::Const, def_id) |
- Res::Def(DefKind::AssociatedConst, def_id) => {
+ Res::Def(DefKind::AssocConst, def_id) => {
let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res);
debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
ExprKind::Literal {
}
pub fn usize_literal(&mut self, value: u64) -> &'tcx ty::Const<'tcx> {
- self.tcx.mk_const(ty::Const::from_usize(self.tcx, value))
+ ty::Const::from_usize(self.tcx, value)
}
pub fn bool_ty(&mut self) -> Ty<'tcx> {
}
pub fn true_literal(&mut self) -> &'tcx ty::Const<'tcx> {
- self.tcx.mk_const(ty::Const::from_bool(self.tcx, true))
+ ty::Const::from_bool(self.tcx, true)
}
pub fn false_literal(&mut self) -> &'tcx ty::Const<'tcx> {
- self.tcx.mk_const(ty::Const::from_bool(self.tcx, false))
+ ty::Const::from_bool(self.tcx, false)
}
pub fn const_eval_literal(
ty: Ty<'tcx>,
sp: Span,
neg: bool,
- ) -> ty::Const<'tcx> {
+ ) -> &'tcx ty::Const<'tcx> {
trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
match lit_to_const(lit, self.tcx, ty, neg) {
method_name: &str,
self_ty: Ty<'tcx>,
params: &[Kind<'tcx>])
- -> (Ty<'tcx>, ty::Const<'tcx>) {
+ -> (Ty<'tcx>, &'tcx ty::Const<'tcx>) {
let method_name = Symbol::intern(method_name);
let substs = self.tcx.mk_substs_trait(self_ty, params);
for item in self.tcx.associated_items(trait_def_id) {
- if item.kind == ty::AssociatedKind::Method && item.ident.name == method_name {
+ if item.kind == ty::AssocKind::Method && item.ident.name == method_name {
let method_ty = self.tcx.type_of(item.def_id);
let method_ty = method_ty.subst(self.tcx, substs);
- return (method_ty, ty::Const::zero_sized(method_ty));
+ return (method_ty, ty::Const::zero_sized(self.tcx, method_ty));
}
}
use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size};
use rustc::mir::Field;
-use rustc::mir::interpret::{ConstValue, Scalar, truncate};
+use rustc::mir::interpret::{ConstValue, Scalar, truncate, AllocId, Pointer};
use rustc::util::common::ErrorReported;
use syntax::attr::{SignedInt, UnsignedInt};
use std::iter::{FromIterator, IntoIterator};
use std::ops::RangeInclusive;
use std::u128;
+use std::convert::TryInto;
pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>)
-> &'a Pattern<'tcx>
// unsize array to slice if pattern is array but match value or other patterns are slice
(ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
assert_eq!(t, u);
- ConstValue::Slice(
- Scalar::Ptr(p),
- n.val.try_to_scalar()
- .unwrap()
- .to_usize(&self.tcx)
- .unwrap(),
- )
+ ConstValue::Slice {
+ data: self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id),
+ start: p.offset.bytes().try_into().unwrap(),
+ end: n.unwrap_usize(self.tcx).try_into().unwrap(),
+ }
},
// fat pointers stay the same
- (ConstValue::Slice(..), _, _) => val,
+ | (ConstValue::Slice { .. }, _, _)
+ | (_, ty::Slice(_), ty::Slice(_))
+ | (_, ty::Str, ty::Str)
+ => val,
// FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used
_ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
}
subpattern: Pattern {
ty: rty,
span: pat.span,
- kind: box PatternKind::Constant { value: Const {
- val: self.fold_const_value_deref(val, rty, crty),
+ kind: box PatternKind::Constant { value: self.tcx.mk_const(Const {
+ val: self.fold_const_value_deref(*val, rty, crty),
ty: rty,
- } },
+ }) },
}
}
}
/// Enum variants.
Variant(DefId),
/// Literal values.
- ConstantValue(ty::Const<'tcx>),
+ ConstantValue(&'tcx ty::Const<'tcx>),
/// Ranges of literal values (`2...5` and `2..5`).
ConstantRange(u128, u128, Ty<'tcx>, RangeEnd),
/// Array patterns of length n.
max_fixed_len,
n.unwrap_usize(cx.tcx),
),
- (ConstValue::Slice(_, n), ty::Slice(_)) => max_fixed_len = cmp::max(
+ (ConstValue::Slice{ start, end, .. }, ty::Slice(_)) => max_fixed_len = cmp::max(
max_fixed_len,
- n,
+ (end - start) as u64,
),
_ => {},
}
fn slice_pat_covered_by_const<'tcx>(
tcx: TyCtxt<'_, 'tcx, '_>,
_span: Span,
- const_val: ty::Const<'tcx>,
+ const_val: &'tcx ty::Const<'tcx>,
prefix: &[Pattern<'tcx>],
slice: &Option<Pattern<'tcx>>,
suffix: &[Pattern<'tcx>]
) -> Result<bool, ErrorReported> {
let data: &[u8] = match (const_val.val, &const_val.ty.sty) {
(ConstValue::ByRef(ptr, alloc), ty::Array(t, n)) => {
- if *t != tcx.types.u8 {
- // FIXME(oli-obk): can't mix const patterns with slice patterns and get
- // any sort of exhaustiveness/unreachable check yet
- // This solely means that we don't lint about unreachable patterns, even if some
- // are definitely unreachable.
- return Ok(false);
- }
+ assert_eq!(*t, tcx.types.u8);
let n = n.assert_usize(tcx).unwrap();
alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
},
- // a slice fat pointer to a zero length slice
- (ConstValue::Slice(Scalar::Bits { .. }, 0), ty::Slice(t)) => {
- if *t != tcx.types.u8 {
- // FIXME(oli-obk): can't mix const patterns with slice patterns and get
- // any sort of exhaustiveness/unreachable check yet
- // This solely means that we don't lint about unreachable patterns, even if some
- // are definitely unreachable.
- return Ok(false);
- }
- &[]
- },
- //
- (ConstValue::Slice(Scalar::Ptr(ptr), n), ty::Slice(t)) => {
- if *t != tcx.types.u8 {
- // FIXME(oli-obk): can't mix const patterns with slice patterns and get
- // any sort of exhaustiveness/unreachable check yet
- // This solely means that we don't lint about unreachable patterns, even if some
- // are definitely unreachable.
- return Ok(false);
- }
- tcx.alloc_map
- .lock()
- .unwrap_memory(ptr.alloc_id)
- .get_bytes(&tcx, ptr, Size::from_bytes(n))
- .unwrap()
+ (ConstValue::Slice { data, start, end }, ty::Slice(t)) => {
+ assert_eq!(*t, tcx.types.u8);
+ let ptr = Pointer::new(AllocId(0), Size::from_bytes(start as u64));
+ data.get_bytes(&tcx, ptr, Size::from_bytes((end - start) as u64)).unwrap()
},
+ // FIXME(oli-obk): create a way to extract fat pointers from ByRef
+ (_, ty::Slice(_)) => return Ok(false),
_ => bug!(
"slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
const_val, prefix, slice, suffix,
// necessarily point to memory, they are usually just integers. The only time
// they should be pointing to memory is when they are subslices of nonzero
// slices
- let (opt_ptr, n, ty) = match value.ty.sty {
+ let (alloc, offset, n, ty) = match value.ty.sty {
ty::Array(t, n) => {
match value.val {
ConstValue::ByRef(ptr, alloc) => (
- Some((ptr, alloc)),
+ alloc,
+ ptr.offset,
n.unwrap_usize(cx.tcx),
t,
),
},
ty::Slice(t) => {
match value.val {
- ConstValue::Slice(ptr, n) => (
- ptr.to_ptr().ok().map(|ptr| (
- ptr,
- cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id),
- )),
- n,
+ ConstValue::Slice { data, start, end } => (
+ data,
+ Size::from_bytes(start as u64),
+ (end - start) as u64,
t,
),
+ ConstValue::ByRef(..) => {
+ // FIXME(oli-obk): implement `deref` for `ConstValue`
+ return None;
+ },
_ => span_bug!(
pat.span,
"slice pattern constant must be scalar pair but is {:?}",
};
if wild_patterns.len() as u64 == n {
// convert a constant slice/array pattern to a list of patterns.
- match (n, opt_ptr) {
- (0, _) => Some(SmallVec::new()),
- (_, Some((ptr, alloc))) => {
- let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
- (0..n).map(|i| {
- let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
- let scalar = alloc.read_scalar(
- &cx.tcx, ptr, layout.size,
- ).ok()?;
- let scalar = scalar.not_undef().ok()?;
- let value = ty::Const::from_scalar(scalar, ty);
- let pattern = Pattern {
- ty,
- span: pat.span,
- kind: box PatternKind::Constant { value },
- };
- Some(&*cx.pattern_arena.alloc(pattern))
- }).collect()
- },
- (_, None) => span_bug!(
- pat.span,
- "non zero length slice with const-val {:?}",
- value,
- ),
- }
+ let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
+ let ptr = Pointer::new(AllocId(0), offset);
+ (0..n).map(|i| {
+ let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
+ let scalar = alloc.read_scalar(
+ &cx.tcx, ptr, layout.size,
+ ).ok()?;
+ let scalar = scalar.not_undef().ok()?;
+ let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
+ let pattern = Pattern {
+ ty,
+ span: pat.span,
+ kind: box PatternKind::Constant { value },
+ };
+ Some(&*cx.pattern_arena.alloc(pattern))
+ }).collect()
} else {
None
}
PatternError::StaticInPattern(span) => {
self.span_e0158(span, "statics cannot be referenced in patterns")
}
- PatternError::AssociatedConstInPattern(span) => {
+ PatternError::AssocConstInPattern(span) => {
self.span_e0158(span, "associated consts cannot be referenced in patterns")
}
PatternError::FloatBug => {
use crate::hair::util::UserAnnotatedTyHelpers;
use crate::hair::constant::*;
-use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
+use rustc::mir::{Field, BorrowKind, Mutability};
use rustc::mir::{UserTypeProjection};
-use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
+use rustc::mir::interpret::{GlobalId, ConstValue, sign_extend, AllocId, Pointer};
use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, UserType, DefIdTree};
use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations};
use rustc::ty::subst::{SubstsRef, Kind};
-use rustc::ty::layout::VariantIdx;
+use rustc::ty::layout::{VariantIdx, Size};
use rustc::hir::{self, PatKind, RangeEnd};
use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind};
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
#[derive(Clone, Debug)]
pub enum PatternError {
- AssociatedConstInPattern(Span),
+ AssocConstInPattern(Span),
StaticInPattern(Span),
FloatBug,
NonConstPath(Span),
},
Constant {
- value: ty::Const<'tcx>,
+ value: &'tcx ty::Const<'tcx>,
},
Range(PatternRange<'tcx>),
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct PatternRange<'tcx> {
- pub lo: ty::Const<'tcx>,
- pub hi: ty::Const<'tcx>,
+ pub lo: &'tcx ty::Const<'tcx>,
+ pub hi: &'tcx ty::Const<'tcx>,
pub ty: Ty<'tcx>,
pub end: RangeEnd,
}
write!(f, "{}", subpattern)
}
PatternKind::Constant { value } => {
- fmt_const_val(f, value)
+ write!(f, "{}", value)
}
PatternKind::Range(PatternRange { lo, hi, ty: _, end }) => {
- fmt_const_val(f, lo)?;
+ write!(f, "{}", lo)?;
match end {
RangeEnd::Included => write!(f, "..=")?,
RangeEnd::Excluded => write!(f, "..")?,
}
- fmt_const_val(f, hi)
+ write!(f, "{}", hi)
}
PatternKind::Slice { ref prefix, ref slice, ref suffix } |
PatternKind::Array { ref prefix, ref slice, ref suffix } => {
| Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
| Res::Def(DefKind::Union, _)
| Res::Def(DefKind::TyAlias, _)
- | Res::Def(DefKind::AssociatedTy, _)
+ | Res::Def(DefKind::AssocTy, _)
| Res::SelfTy(..)
| Res::SelfCtor(..) => {
PatternKind::Leaf { subpatterns }
let ty = self.tables.node_type(id);
let res = self.tables.qpath_res(qpath, id);
let is_associated_const = match res {
- Res::Def(DefKind::AssociatedConst, _) => true,
+ Res::Def(DefKind::AssocConst, _) => true,
_ => false,
};
let kind = match res {
- Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssociatedConst, def_id) => {
+ Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
let substs = self.tables.node_substs(id);
match ty::Instance::resolve(
self.tcx,
},
None => {
self.errors.push(if is_associated_const {
- PatternError::AssociatedConstInPattern(span)
+ PatternError::AssocConstInPattern(span)
} else {
PatternError::StaticInPattern(span)
});
fn const_to_pat(
&self,
instance: ty::Instance<'tcx>,
- cv: ty::Const<'tcx>,
+ cv: &'tcx ty::Const<'tcx>,
id: hir::HirId,
span: Span,
) -> Pattern<'tcx> {
PatternKind::Constant {
value
} => PatternKind::Constant {
- value: value.fold_with(folder)
+ value,
},
PatternKind::Range(PatternRange {
lo,
ty,
end,
}) => PatternKind::Range(PatternRange {
- lo: lo.fold_with(folder),
- hi: hi.fold_with(folder),
+ lo,
+ hi,
ty: ty.fold_with(folder),
end,
}),
pub fn compare_const_vals<'a, 'gcx, 'tcx>(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
- a: ty::Const<'tcx>,
- b: ty::Const<'tcx>,
+ a: &'tcx ty::Const<'tcx>,
+ b: &'tcx ty::Const<'tcx>,
ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> Option<Ordering> {
trace!("compare_const_vals: {:?}, {:?}", a, b);
if let ty::Str = ty.value.sty {
match (a.val, b.val) {
(
- ConstValue::Slice(
- Scalar::Ptr(ptr_a),
- len_a,
- ),
- ConstValue::Slice(
- Scalar::Ptr(ptr_b),
- len_b,
- ),
- ) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => {
- if len_a == len_b {
- let map = tcx.alloc_map.lock();
- let alloc_a = map.unwrap_memory(ptr_a.alloc_id);
- let alloc_b = map.unwrap_memory(ptr_b.alloc_id);
- if alloc_a.bytes.len() as u64 == len_a {
- return from_bool(alloc_a == alloc_b);
- }
+ ConstValue::Slice { data: alloc_a, start: offset_a, end: end_a },
+ ConstValue::Slice { data: alloc_b, start: offset_b, end: end_b },
+ ) => {
+ let len_a = end_a - offset_a;
+ let len_b = end_b - offset_b;
+ let a = alloc_a.get_bytes(
+ &tcx,
+ // invent a pointer, only the offset is relevant anyway
+ Pointer::new(AllocId(0), Size::from_bytes(offset_a as u64)),
+ Size::from_bytes(len_a as u64),
+ );
+ let b = alloc_b.get_bytes(
+ &tcx,
+ // invent a pointer, only the offset is relevant anyway
+ Pointer::new(AllocId(0), Size::from_bytes(offset_b as u64)),
+ Size::from_bytes(len_b as u64),
+ );
+ if let (Ok(a), Ok(b)) = (a, b) {
+ return from_bool(a == b);
}
}
_ => (),
// statics and constants don't have `Storage*` statements, no need to look for them
Some(DefKind::Static)
| Some(DefKind::Const)
- | Some(DefKind::AssociatedConst) => {},
+ | Some(DefKind::AssocConst) => {},
_ => {
trace!("push_stack_frame: {:?}: num_bbs: {}", span, mir.basic_blocks().len());
for block in mir.basic_blocks() {
use super::{
Pointer, AllocId, Allocation, GlobalId, AllocationExtra,
EvalResult, Scalar, InterpError, AllocKind, PointerArithmetic,
- Machine, AllocMap, MayLeak, ErrorHandled, InboundsCheck,
+ Machine, AllocMap, MayLeak, ErrorHandled, CheckInAllocMsg, InboundsCheck,
};
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
Scalar::Ptr(ptr) => {
// check this is not NULL -- which we can ensure only if this is in-bounds
// of some (potentially dead) allocation.
- let align = self.check_bounds_ptr(ptr, InboundsCheck::MaybeDead)?;
+ let align = self.check_bounds_ptr(ptr, InboundsCheck::MaybeDead,
+ CheckInAllocMsg::NullPointerTest)?;
(ptr.offset.bytes(), align)
}
Scalar::Bits { bits, size } => {
&self,
ptr: Pointer<M::PointerTag>,
liveness: InboundsCheck,
+ msg: CheckInAllocMsg,
) -> EvalResult<'tcx, Align> {
let (allocation_size, align) = self.get_size_and_align(ptr.alloc_id, liveness)?;
- ptr.check_in_alloc(allocation_size, liveness)?;
+ ptr.check_in_alloc(allocation_size, msg)?;
Ok(align)
}
}
/// Obtain the size and alignment of an allocation, even if that allocation has been deallocated
///
- /// If `liveness` is `InboundsCheck::Dead`, this function always returns `Ok`
+ /// If `liveness` is `InboundsCheck::MaybeDead`, this function always returns `Ok`
pub fn get_size_and_align(
&self,
id: AllocId,
use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt, VariantIdx};
use rustc::mir::interpret::{
- GlobalId, AllocId, InboundsCheck,
+ GlobalId, AllocId, CheckInAllocMsg,
ConstValue, Pointer, Scalar,
- EvalResult, InterpError,
+ EvalResult, InterpError, InboundsCheck,
sign_extend, truncate,
};
use super::{
mir_place: &mir::Place<'tcx>,
layout: Option<TyLayout<'tcx>>,
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
- use rustc::mir::Place::*;
+ use rustc::mir::Place;
use rustc::mir::PlaceBase;
- let op = match *mir_place {
- Base(PlaceBase::Local(mir::RETURN_PLACE)) => return err!(ReadFromReturnPointer),
- Base(PlaceBase::Local(local)) => self.access_local(self.frame(), local, layout)?,
- Projection(ref proj) => {
- let op = self.eval_place_to_op(&proj.base, None)?;
- self.operand_projection(op, &proj.elem)?
- }
+ mir_place.iterate(|place_base, place_projection| {
+ let mut op = match place_base {
+ PlaceBase::Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
+ PlaceBase::Local(local) => {
+ // FIXME use place_projection.is_empty() when is available
+ // Do not use the layout passed in as argument if the base we are looking at
+ // here is not the entire place.
+ let layout = if let Place::Base(_) = mir_place {
+ layout
+ } else {
+ None
+ };
+
+ self.access_local(self.frame(), *local, layout)?
+ }
+ PlaceBase::Static(place_static) => {
+ self.eval_static_to_mplace(place_static)?.into()
+ }
+ };
- _ => self.eval_place_to_mplace(mir_place)?.into(),
- };
+ for proj in place_projection {
+ op = self.operand_projection(op, &proj.elem)?
+ }
- trace!("eval_place_to_op: got {:?}", *op);
- Ok(op)
+ trace!("eval_place_to_op: got {:?}", *op);
+ Ok(op)
+ })
}
/// Evaluate the operand, returning a place where you can then find the data.
Move(ref place) =>
self.eval_place_to_op(place, layout)?,
- Constant(ref constant) => self.eval_const_to_op(*constant.literal, layout)?,
+ Constant(ref constant) => self.eval_const_to_op(constant.literal, layout)?,
};
trace!("{:?}: {:?}", mir_op, *op);
Ok(op)
// in patterns via the `const_eval` module
crate fn eval_const_to_op(
&self,
- val: ty::Const<'tcx>,
+ val: &'tcx ty::Const<'tcx>,
layout: Option<TyLayout<'tcx>>,
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
let op = match val.val {
MemPlace::from_ptr(ptr.with_default_tag(), alloc.align)
)
},
- ConstValue::Slice(a, b) =>
+ ConstValue::Slice { data, start, end } =>
Operand::Immediate(Immediate::ScalarPair(
- a.with_default_tag().into(),
- Scalar::from_uint(b, self.tcx.data_layout.pointer_size)
- .with_default_tag().into(),
+ Scalar::from(Pointer::new(
+ self.tcx.alloc_map.lock().allocate(data),
+ Size::from_bytes(start as u64),
+ )).with_default_tag().into(),
+ Scalar::from_uint(
+ (end - start) as u64,
+ self.tcx.data_layout.pointer_size,
+ ).with_default_tag().into(),
)),
ConstValue::Scalar(x) =>
Operand::Immediate(Immediate::Scalar(x.with_default_tag().into())),
ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) => {
// The niche must be just 0 (which an inbounds pointer value never is)
let ptr_valid = niche_start == 0 && variants_start == variants_end &&
- self.memory.check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok();
+ self.memory.check_bounds_ptr(ptr, InboundsCheck::MaybeDead,
+ CheckInAllocMsg::NullPointerTest).is_ok();
if !ptr_valid {
return err!(InvalidDiscriminant(raw_discr.erase_tag()));
}
/// Evaluate statics and promoteds to an `MPlace`. Used to share some code between
/// `eval_place` and `eval_place_to_op`.
- pub(super) fn eval_place_to_mplace(
+ pub(super) fn eval_static_to_mplace(
&self,
- mir_place: &mir::Place<'tcx>
+ place_static: &mir::Static<'tcx>
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
- use rustc::mir::Place::*;
- use rustc::mir::PlaceBase;
- use rustc::mir::{Static, StaticKind};
- Ok(match *mir_place {
- Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(promoted), .. })) => {
+ use rustc::mir::StaticKind;
+
+ Ok(match place_static.kind {
+ StaticKind::Promoted(promoted) => {
let instance = self.frame().instance;
self.const_eval_raw(GlobalId {
instance,
})?
}
- Base(PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), ty })) => {
+ StaticKind::Static(def_id) => {
+ let ty = place_static.ty;
assert!(!ty.needs_subst());
let layout = self.layout_of(ty)?;
let instance = ty::Instance::mono(*self.tcx, def_id);
let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
}
-
- _ => bug!("eval_place_to_mplace called on {:?}", mir_place),
})
}
/// place; for reading, a more efficient alternative is `eval_place_for_read`.
pub fn eval_place(
&mut self,
- mir_place: &mir::Place<'tcx>
+ mir_place: &mir::Place<'tcx>,
) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
- use rustc::mir::Place::*;
use rustc::mir::PlaceBase;
- let place = match *mir_place {
- Base(PlaceBase::Local(mir::RETURN_PLACE)) => match self.frame().return_place {
- Some(return_place) =>
- // We use our layout to verify our assumption; caller will validate
- // their layout on return.
- PlaceTy {
- place: *return_place,
- layout: self.layout_of(self.monomorphize(self.frame().mir.return_ty())?)?,
+
+ mir_place.iterate(|place_base, place_projection| {
+ let mut place = match place_base {
+ PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place {
+ Some(return_place) => {
+ // We use our layout to verify our assumption; caller will validate
+ // their layout on return.
+ PlaceTy {
+ place: *return_place,
+ layout: self
+ .layout_of(self.monomorphize(self.frame().mir.return_ty())?)?,
+ }
+ }
+ None => return err!(InvalidNullPointerUsage),
+ },
+ PlaceBase::Local(local) => PlaceTy {
+ // This works even for dead/uninitialized locals; we check further when writing
+ place: Place::Local {
+ frame: self.cur_frame(),
+ local: *local,
},
- None => return err!(InvalidNullPointerUsage),
- },
- Base(PlaceBase::Local(local)) => PlaceTy {
- // This works even for dead/uninitialized locals; we check further when writing
- place: Place::Local {
- frame: self.cur_frame(),
- local,
+ layout: self.layout_of_local(self.frame(), *local, None)?,
},
- layout: self.layout_of_local(self.frame(), local, None)?,
- },
+ PlaceBase::Static(place_static) => self.eval_static_to_mplace(place_static)?.into(),
+ };
- Projection(ref proj) => {
- let place = self.eval_place(&proj.base)?;
- self.place_projection(place, &proj.elem)?
+ for proj in place_projection {
+ place = self.place_projection(place, &proj.elem)?
}
- _ => self.eval_place_to_mplace(mir_place)?.into(),
- };
-
- self.dump_place(place.place);
- Ok(place)
+ self.dump_place(place.place);
+ Ok(place)
+ })
}
/// Write a scalar to a place
use std::hash::Hash;
use std::ops::RangeInclusive;
-use syntax_pos::symbol::Symbol;
+use syntax_pos::symbol::{sym, Symbol};
use rustc::hir;
use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf, VariantIdx};
use rustc::ty;
use rustc_data_structures::fx::FxHashSet;
use rustc::mir::interpret::{
- Scalar, AllocKind, EvalResult, InterpError,
+ Scalar, AllocKind, EvalResult, InterpError, CheckInAllocMsg,
};
use super::{
PathElem::ClosureVar(name.unwrap_or_else(|| {
// Fall back to showing the field index.
- Symbol::intern(&field.to_string())
+ sym::integer(field)
}))
}
try_validation!(
self.ecx.memory
.get(ptr.alloc_id)?
- .check_bounds(self.ecx, ptr, size),
+ .check_bounds(self.ecx, ptr, size, CheckInAllocMsg::InboundsTest),
"dangling (not entirely in bounds) reference", self.path);
}
// Check if we have encountered this pointer+layout combination
use rustc::hir::map::blocks::FnLikeNode;
use rustc::lint::builtin::UNCONDITIONAL_RECURSION;
use rustc::mir::{self, Mir, TerminatorKind};
-use rustc::ty::{self, AssociatedItem, AssociatedItemContainer, Instance, TyCtxt};
+use rustc::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
use rustc::ty::subst::InternalSubsts;
pub fn check(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let param_env = tcx.param_env(def_id);
let trait_substs_count =
match tcx.opt_associated_item(def_id) {
- Some(AssociatedItem {
- container: AssociatedItemContainer::TraitContainer(trait_def_id),
+ Some(AssocItem {
+ container: AssocItemContainer::TraitContainer(trait_def_id),
..
}) => tcx.generics_of(trait_def_id).count(),
_ => 0
fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) {
debug!("visiting const {:?} @ {:?}", *constant, location);
- collect_const(self.tcx, **constant, self.param_substs, self.output);
+ collect_const(self.tcx, *constant, self.param_substs, self.output);
self.super_const(constant);
}
fn collect_const<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- constant: ty::Const<'tcx>,
+ constant: &'tcx ty::Const<'tcx>,
param_substs: SubstsRef<'tcx>,
output: &mut Vec<MonoItem<'tcx>>,
) {
debug!("visiting const {:?}", constant);
match constant.val {
- ConstValue::Slice(Scalar::Ptr(ptr), _) |
ConstValue::Scalar(Scalar::Ptr(ptr)) =>
collect_miri(tcx, ptr.alloc_id, output),
- ConstValue::ByRef(_ptr, alloc) => {
+ ConstValue::Slice { data: alloc, start: _, end: _ } |
+ ConstValue::ByRef(_, alloc) => {
for &((), id) in alloc.relocations.values() {
collect_miri(tcx, id, output);
}
// as well as the unprintable types of constants (see `push_type_name` for more details).
pub fn push_const_name(&self, c: &Const<'tcx>, output: &mut String, debug: bool) {
match c.val {
- ConstValue::Scalar(..) | ConstValue::Slice(..) | ConstValue::ByRef(..) => {
+ ConstValue::Scalar(..) | ConstValue::Slice { .. } | ConstValue::ByRef(..) => {
// FIXME(const_generics): we could probably do a better job here.
write!(output, "{:?}", c).unwrap()
}
substs);
let fn_once = tcx.lang_items().fn_once_trait().unwrap();
let call_once = tcx.associated_items(fn_once)
- .find(|it| it.kind == ty::AssociatedKind::Method)
+ .find(|it| it.kind == ty::AssocKind::Method)
.unwrap().def_id;
let def = ty::InstanceDef::ClosureOnceShim { call_once };
let fn_mut = tcx.lang_items().fn_mut_trait().unwrap();
let call_mut = tcx.global_tcx()
.associated_items(fn_mut)
- .find(|it| it.kind == ty::AssociatedKind::Method)
+ .find(|it| it.kind == ty::AssocKind::Method)
.unwrap().def_id;
build_call_shim(
span: self.span,
ty: func_ty,
user_ty: None,
- literal: tcx.mk_const(
- ty::Const::zero_sized(func_ty),
- ),
+ literal: ty::Const::zero_sized(tcx, func_ty),
});
let ref_loc = self.make_place(
span: self.span,
ty: self.tcx.types.usize,
user_ty: None,
- literal: self.tcx.mk_const(
- ty::Const::from_usize(self.tcx, value),
- ),
+ literal: ty::Const::from_usize(self.tcx, value),
}
}
span,
ty,
user_ty: None,
- literal: tcx.mk_const(
- ty::Const::zero_sized(ty)
- ),
+ literal: ty::Const::zero_sized(tcx, ty),
}),
vec![rcvr])
}
let is_fn_like = FnLikeNode::from_node(tcx.hir().get_by_hir_id(hir_id)).is_some();
let is_assoc_const = match tcx.def_kind(source.def_id()) {
- Some(DefKind::AssociatedConst) => true,
+ Some(DefKind::AssocConst) => true,
_ => false,
};
c: &Constant<'tcx>,
) -> Option<Const<'tcx>> {
self.ecx.tcx.span = c.span;
- match self.ecx.eval_const_to_op(*c.literal, None) {
+ match self.ecx.eval_const_to_op(c.literal, None) {
Ok(op) => {
Some(op)
},
}
fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
- match *place {
- Place::Base(PlaceBase::Local(loc)) => self.places[loc].clone(),
- Place::Projection(ref proj) => match proj.elem {
- ProjectionElem::Field(field, _) => {
- trace!("field proj on {:?}", proj.base);
- let base = self.eval_place(&proj.base, source_info)?;
+ trace!("eval_place(place={:?})", place);
+ place.iterate(|place_base, place_projection| {
+ let mut eval = match place_base {
+ PlaceBase::Local(loc) => self.places[*loc].clone()?,
+ PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted), ..}) => {
+ let generics = self.tcx.generics_of(self.source.def_id());
+ if generics.requires_monomorphization(self.tcx) {
+ // FIXME: can't handle code with generics
+ return None;
+ }
+ let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
+ let instance = Instance::new(self.source.def_id(), substs);
+ let cid = GlobalId {
+ instance,
+ promoted: Some(*promoted),
+ };
+ // cannot use `const_eval` here, because that would require having the MIR
+ // for the current function available, but we're producing said MIR right now
let res = self.use_ecx(source_info, |this| {
- this.ecx.operand_field(base, field.index() as u64)
+ let mir = &this.promoted[*promoted];
+ eval_promoted(this.tcx, cid, mir, this.param_env)
})?;
- Some(res)
- },
- // We could get more projections by using e.g., `operand_projection`,
- // but we do not even have the stack frame set up properly so
- // an `Index` projection would throw us off-track.
- _ => None,
- },
- Place::Base(
- PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted), ..})
- ) => {
- let generics = self.tcx.generics_of(self.source.def_id());
- if generics.requires_monomorphization(self.tcx) {
- // FIXME: can't handle code with generics
- return None;
+ trace!("evaluated promoted {:?} to {:?}", promoted, res);
+ res.into()
}
- let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
- let instance = Instance::new(self.source.def_id(), substs);
- let cid = GlobalId {
- instance,
- promoted: Some(promoted),
- };
- // cannot use `const_eval` here, because that would require having the MIR
- // for the current function available, but we're producing said MIR right now
- let res = self.use_ecx(source_info, |this| {
- let mir = &this.promoted[promoted];
- eval_promoted(this.tcx, cid, mir, this.param_env)
- })?;
- trace!("evaluated promoted {:?} to {:?}", promoted, res);
- Some(res.into())
- },
- _ => None,
- }
+ _ => return None,
+ };
+
+ for proj in place_projection {
+ match proj.elem {
+ ProjectionElem::Field(field, _) => {
+ trace!("field proj on {:?}", proj.base);
+ eval = self.use_ecx(source_info, |this| {
+ this.ecx.operand_field(eval, field.index() as u64)
+ })?;
+ },
+ // We could get more projections by using e.g., `operand_projection`,
+ // but we do not even have the stack frame set up properly so
+ // an `Index` projection would throw us off-track.
+ _ => return None,
+ }
+ }
+
+ Some(eval)
+ })
}
fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
span,
ty,
user_ty: None,
- literal: self.tcx.mk_const(ty::Const::from_scalar(
+ literal: self.tcx.mk_const(*ty::Const::from_scalar(
+ self.tcx,
scalar,
ty,
))
}
fn replace_with_const(&self, rval: &mut Rvalue<'tcx>, value: Const<'tcx>, span: Span) {
+ trace!("attepting to replace {:?} with {:?}", rval, value);
self.ecx.validate_operand(
value,
vec![],
// FIXME(oli-obk): lint variables until they are used in a condition
// FIXME(oli-obk): lint if return value is constant
*val = mir.local_kind(local) == LocalKind::Temp;
+
+ if !*val {
+ trace!("local {:?} can't be propagated because it's not a temporary", local);
+ }
}
cpv.visit_mir(mir);
cpv.can_const_prop
// FIXME(oli-obk): we could be more powerful here, if the multiple writes
// only occur in independent execution paths
MutatingUse(MutatingUseContext::Store) => if self.found_assignment[local] {
+ trace!("local {:?} can't be propagated because of multiple assignments", local);
self.can_const_prop[local] = false;
} else {
self.found_assignment[local] = true
NonMutatingUse(NonMutatingUseContext::Projection) |
MutatingUse(MutatingUseContext::Projection) |
NonUse(_) => {},
- _ => self.can_const_prop[local] = false,
+ _ => {
+ trace!("local {:?} can't be propagaged because it's used: {:?}", local, context);
+ self.can_const_prop[local] = false;
+ },
}
}
}
span,
ty: self.tcx.types.bool,
user_ty: None,
- literal: self.tcx.mk_const(
- ty::Const::from_bool(self.tcx, val),
- ),
+ literal: ty::Const::from_bool(self.tcx, val),
})))
}
span: mir.span,
ty: tcx.types.bool,
user_ty: None,
- literal: tcx.mk_const(
- ty::Const::from_bool(tcx, false),
- ),
+ literal: ty::Const::from_bool(tcx, false),
}),
expected: true,
msg: message,
// writes to `i`. To prevent this we need to create a temporary
// borrow of the place and pass the destination as `*temp` instead.
fn dest_needs_borrow(place: &Place<'_>) -> bool {
- match *place {
- Place::Projection(ref p) => {
- match p.elem {
+ place.iterate(|place_base, place_projection| {
+ for proj in place_projection {
+ match proj.elem {
ProjectionElem::Deref |
- ProjectionElem::Index(_) => true,
- _ => dest_needs_borrow(&p.base)
+ ProjectionElem::Index(_) => return true,
+ _ => {}
}
}
- // Static variables need a borrow because the callee
- // might modify the same static.
- Place::Base(PlaceBase::Static(_)) => true,
- _ => false
- }
+
+ match place_base {
+ // Static variables need a borrow because the callee
+ // might modify the same static.
+ PlaceBase::Static(_) => true,
+ _ => false
+ }
+ })
}
let dest = if dest_needs_borrow(&destination.0) {
) -> McfResult {
match rvalue {
Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => {
- check_operand(tcx, mir, operand, span)
+ check_operand(operand, span)
}
Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => {
- check_place(tcx, mir, place, span)
+ check_place(place, span)
}
Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
use rustc::ty::cast::CastTy;
(CastTy::RPtr(_), CastTy::Float) => bug!(),
(CastTy::RPtr(_), CastTy::Int(_)) => bug!(),
(CastTy::Ptr(_), CastTy::RPtr(_)) => bug!(),
- _ => check_operand(tcx, mir, operand, span),
+ _ => check_operand(operand, span),
}
}
Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, _) => {
- check_operand(tcx, mir, operand, span)
+ check_operand(operand, span)
}
Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), _, _) |
Rvalue::Cast(CastKind::Pointer(PointerCast::ClosureFnPointer(_)), _, _) |
)),
// binops are fine on integers
Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
- check_operand(tcx, mir, lhs, span)?;
- check_operand(tcx, mir, rhs, span)?;
+ check_operand(lhs, span)?;
+ check_operand(rhs, span)?;
let ty = lhs.ty(mir, tcx);
if ty.is_integral() || ty.is_bool() || ty.is_char() {
Ok(())
Rvalue::UnaryOp(_, operand) => {
let ty = operand.ty(mir, tcx);
if ty.is_integral() || ty.is_bool() {
- check_operand(tcx, mir, operand, span)
+ check_operand(operand, span)
} else {
Err((
span,
}
Rvalue::Aggregate(_, operands) => {
for operand in operands {
- check_operand(tcx, mir, operand, span)?;
+ check_operand(operand, span)?;
}
Ok(())
}
let span = statement.source_info.span;
match &statement.kind {
StatementKind::Assign(place, rval) => {
- check_place(tcx, mir, place, span)?;
+ check_place(place, span)?;
check_rvalue(tcx, mir, rval, span)
}
- StatementKind::FakeRead(_, place) => check_place(tcx, mir, place, span),
+ StatementKind::FakeRead(_, place) => check_place(place, span),
// just an assignment
StatementKind::SetDiscriminant { .. } => Ok(()),
}
fn check_operand(
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- mir: &'a Mir<'tcx>,
operand: &Operand<'tcx>,
span: Span,
) -> McfResult {
match operand {
Operand::Move(place) | Operand::Copy(place) => {
- check_place(tcx, mir, place, span)
+ check_place(place, span)
}
Operand::Constant(_) => Ok(()),
}
}
-fn check_place(
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- mir: &'a Mir<'tcx>,
- place: &Place<'tcx>,
- span: Span,
-) -> McfResult {
- match place {
- Place::Base(PlaceBase::Local(_)) => Ok(()),
- // promoteds are always fine, they are essentially constants
- Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. })) => Ok(()),
- Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Static(_), .. })) =>
- Err((span, "cannot access `static` items in const fn".into())),
- Place::Projection(proj) => {
+fn check_place(place: &Place<'tcx>, span: Span) -> McfResult {
+ place.iterate(|place_base, place_projection| {
+ for proj in place_projection {
match proj.elem {
- | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. }
- | ProjectionElem::Deref | ProjectionElem::Field(..) | ProjectionElem::Index(_) => {
- check_place(tcx, mir, &proj.base, span)
- }
- | ProjectionElem::Downcast(..) => {
- Err((span, "`match` or `if let` in `const fn` is unstable".into()))
+ ProjectionElem::Downcast(..) => {
+ return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
}
+ ProjectionElem::ConstantIndex { .. }
+ | ProjectionElem::Subslice { .. }
+ | ProjectionElem::Deref
+ | ProjectionElem::Field(..)
+ | ProjectionElem::Index(_) => {}
}
}
- }
+
+ match place_base {
+ PlaceBase::Static(box Static { kind: StaticKind::Static(_), .. }) => {
+ Err((span, "cannot access `static` items in const fn".into()))
+ }
+ PlaceBase::Local(_)
+ | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => Ok(()),
+ }
+ })
}
fn check_terminator(
| TerminatorKind::Resume => Ok(()),
TerminatorKind::Drop { location, .. } => {
- check_place(tcx, mir, location, span)
+ check_place(location, span)
}
TerminatorKind::DropAndReplace { location, value, .. } => {
- check_place(tcx, mir, location, span)?;
- check_operand(tcx, mir, value, span)
+ check_place(location, span)?;
+ check_operand(value, span)
},
TerminatorKind::FalseEdges { .. } | TerminatorKind::SwitchInt { .. } => Err((
)),
}
- check_operand(tcx, mir, func, span)?;
+ check_operand(func, span)?;
for arg in args {
- check_operand(tcx, mir, arg, span)?;
+ check_operand(arg, span)?;
}
Ok(())
} else {
msg: _,
target: _,
cleanup: _,
- } => check_operand(tcx, mir, cond, span),
+ } => check_operand(cond, span),
TerminatorKind::FalseUnwind { .. } => {
Err((span, "loops are not allowed in const fn".into()))
span: self.source_info.span,
ty: self.tcx().types.usize,
user_ty: None,
- literal: self.tcx().mk_const(
- ty::Const::from_usize(self.tcx(), val.into())
- ),
+ literal: ty::Const::from_usize(self.tcx(), val.into()),
})
}
match (kind, src.promoted) {
(_, Some(i)) => write!(w, "{:?} in ", i)?,
(Some(DefKind::Const), _)
- | (Some(DefKind::AssociatedConst), _) => write!(w, "const ")?,
+ | (Some(DefKind::AssocConst), _) => write!(w, "const ")?,
(Some(DefKind::Static), _) =>
write!(w, "static {}", if tcx.is_mutable_static(src.def_id()) { "mut " } else { "" })?,
(_, _) if is_function => write!(w, "fn ")?,
}
Res::Def(DefKind::Const, did) |
- Res::Def(DefKind::AssociatedConst, did) => {
+ Res::Def(DefKind::AssocConst, did) => {
let promotable = if v.tcx.trait_of_item(did).is_some() {
// Don't peek inside trait associated constants.
NotPromotable
use std::mem;
use std::path::PathBuf;
use syntax::ast;
-use syntax::span_err;
+use syntax::struct_span_err;
use syntax::symbol::{Symbol, kw, sym};
use syntax_pos::{Span, DUMMY_SP};
plugins: Vec<PluginRegistrar>,
}
-fn call_malformed_plugin_attribute(a: &Session, b: Span) {
- span_err!(a, b, E0498, "malformed plugin attribute");
+fn call_malformed_plugin_attribute(sess: &Session, span: Span) {
+ struct_span_err!(sess, span, E0498, "malformed `plugin` attribute")
+ .span_label(span, "malformed attribute")
+ .emit();
}
/// Read plugin metadata and dynamically load registrar functions.
#[macro_use] extern crate syntax;
use rustc::bug;
-use rustc::hir::{self, Node, PatKind, AssociatedItemKind};
+use rustc::hir::{self, Node, PatKind, AssocItemKind};
use rustc::hir::def::{Res, DefKind};
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
let mut reach = self.reach(trait_item_ref.id.hir_id, item_level);
reach.generics().predicates();
- if trait_item_ref.kind == AssociatedItemKind::Type &&
+ if trait_item_ref.kind == AssocItemKind::Type &&
!trait_item_ref.defaultness.has_value() {
// No type to visit.
} else {
let def = def.filter(|(kind, _)| {
match kind {
DefKind::Method
- | DefKind::AssociatedConst
- | DefKind::AssociatedTy
- | DefKind::AssociatedExistential
+ | DefKind::AssocConst
+ | DefKind::AssocTy
+ | DefKind::AssocExistential
| DefKind::Static => true,
_ => false,
}
if self.item_is_public(&impl_item_ref.id.hir_id, &impl_item_ref.vis) {
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item_ref.kind {
- AssociatedItemKind::Const => {
+ AssocItemKind::Const => {
found_pub_static = true;
intravisit::walk_impl_item(self, impl_item);
}
- AssociatedItemKind::Method { has_self: false } => {
+ AssocItemKind::Method { has_self: false } => {
found_pub_static = true;
intravisit::walk_impl_item(self, impl_item);
}
}
}
- fn check_trait_or_impl_item(&self, hir_id: hir::HirId, assoc_item_kind: AssociatedItemKind,
+ fn check_trait_or_impl_item(&self, hir_id: hir::HirId, assoc_item_kind: AssocItemKind,
defaultness: hir::Defaultness, vis: ty::Visibility) {
let mut check = self.check(hir_id, vis);
let (check_ty, is_assoc_ty) = match assoc_item_kind {
- AssociatedItemKind::Const | AssociatedItemKind::Method { .. } => (true, false),
- AssociatedItemKind::Type => (defaultness.has_value(), true),
+ AssocItemKind::Const | AssocItemKind::Method { .. } => (true, false),
+ AssocItemKind::Type => (defaultness.has_value(), true),
// `ty()` for existential types is the underlying type,
// it's not a part of interface, so we skip it.
- AssociatedItemKind::Existential => (false, true),
+ AssocItemKind::Existential => (false, true),
};
check.in_assoc_ty = is_assoc_ty;
check.generics().predicates();
for child in self.cstore.item_children_untracked(def_id, self.session) {
let res = child.res.map_id(|_| panic!("unexpected id"));
- let ns = if let Res::Def(DefKind::AssociatedTy, _) = res {
+ let ns = if let Res::Def(DefKind::AssocTy, _) = res {
TypeNS
} else { ValueNS };
self.define(module, child.ident, ns,
// Add the item to the trait info.
let item_def_id = self.resolver.definitions.local_def_id(item.id);
let (res, ns) = match item.node {
- TraitItemKind::Const(..) => (Res::Def(DefKind::AssociatedConst, item_def_id), ValueNS),
+ TraitItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS),
TraitItemKind::Method(ref sig, _) => {
if sig.decl.has_self() {
self.resolver.has_self.insert(item_def_id);
}
(Res::Def(DefKind::Method, item_def_id), ValueNS)
}
- TraitItemKind::Type(..) => (Res::Def(DefKind::AssociatedTy, item_def_id), TypeNS),
+ TraitItemKind::Type(..) => (Res::Def(DefKind::AssocTy, item_def_id), TypeNS),
TraitItemKind::Macro(_) => bug!(), // handled above
};
err.note("can't use `Self` as a constructor, you must use the implemented struct");
}
(Res::Def(DefKind::TyAlias, _), _)
- | (Res::Def(DefKind::AssociatedTy, _), _) if ns == ValueNS => {
+ | (Res::Def(DefKind::AssocTy, _), _) if ns == ValueNS => {
err.note("can't use a type alias as a constructor");
}
_ => return false,
| Res::Def(DefKind::Trait, _)
| Res::Def(DefKind::TraitAlias, _)
| Res::Def(DefKind::TyAlias, _)
- | Res::Def(DefKind::AssociatedTy, _)
+ | Res::Def(DefKind::AssocTy, _)
| Res::PrimTy(..)
| Res::Def(DefKind::TyParam, _)
| Res::SelfTy(..)
| Res::Upvar(..)
| Res::Def(DefKind::Fn, _)
| Res::Def(DefKind::Method, _)
- | Res::Def(DefKind::AssociatedConst, _)
+ | Res::Def(DefKind::AssocConst, _)
| Res::SelfCtor(..)
| Res::Def(DefKind::ConstParam, _) => true,
_ => false,
},
PathSource::Pat => match res {
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) |
- Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssociatedConst, _) |
+ Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) |
Res::SelfCtor(..) => true,
_ => false,
},
| Res::Def(DefKind::Union, _)
| Res::Def(DefKind::Variant, _)
| Res::Def(DefKind::TyAlias, _)
- | Res::Def(DefKind::AssociatedTy, _)
+ | Res::Def(DefKind::AssocTy, _)
| Res::SelfTy(..) => true,
_ => false,
},
PathSource::TraitItem(ns) => match res {
- Res::Def(DefKind::AssociatedConst, _)
+ Res::Def(DefKind::AssocConst, _)
| Res::Def(DefKind::Method, _) if ns == ValueNS => true,
- Res::Def(DefKind::AssociatedTy, _) if ns == TypeNS => true,
+ Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true,
_ => false,
},
PathSource::Visibility => match res {
fn is_importable(&self) -> bool {
match self.res() {
- Res::Def(DefKind::AssociatedConst, _)
+ Res::Def(DefKind::AssocConst, _)
| Res::Def(DefKind::Method, _)
- | Res::Def(DefKind::AssociatedTy, _) => false,
+ | Res::Def(DefKind::AssocTy, _) => false,
_ => true,
}
}
}
Res::Def(HirDefKind::Ctor(..), _) |
Res::Def(HirDefKind::Const, _) |
- Res::Def(HirDefKind::AssociatedConst, _) |
+ Res::Def(HirDefKind::AssocConst, _) |
Res::Def(HirDefKind::Struct, _) |
Res::Def(HirDefKind::Variant, _) |
Res::Def(HirDefKind::TyAlias, _) |
- Res::Def(HirDefKind::AssociatedTy, _) |
+ Res::Def(HirDefKind::AssocTy, _) |
Res::SelfTy(..) => {
self.dump_path_ref(id, &ast::Path::from_ident(ident));
}
Res::Def(HirDefKind::TyAlias, def_id) |
Res::Def(HirDefKind::ForeignTy, def_id) |
Res::Def(HirDefKind::TraitAlias, def_id) |
- Res::Def(HirDefKind::AssociatedExistential, def_id) |
- Res::Def(HirDefKind::AssociatedTy, def_id) |
+ Res::Def(HirDefKind::AssocExistential, def_id) |
+ Res::Def(HirDefKind::AssocTy, def_id) |
Res::Def(HirDefKind::Trait, def_id) |
Res::Def(HirDefKind::Existential, def_id) |
Res::Def(HirDefKind::TyParam, def_id) => {
}
Res::Def(HirDefKind::Static, _) |
Res::Def(HirDefKind::Const, _) |
- Res::Def(HirDefKind::AssociatedConst, _) |
+ Res::Def(HirDefKind::AssocConst, _) |
Res::Def(HirDefKind::Ctor(..), _) => {
Some(Ref {
kind: RefKind::Variable,
refs: vec![],
})
}
- Res::Def(DefKind::AssociatedConst, _)
+ Res::Def(DefKind::AssocConst, _)
| Res::Def(DefKind::Variant, _)
| Res::Def(DefKind::Ctor(..), _) => {
let len = self.segments.len();
rustc_cratesio_shim = { path = "../librustc_cratesio_shim" }
rustc_data_structures = { path = "../librustc_data_structures" }
serialize = { path = "../libserialize" }
+syntax_pos = { path = "../libsyntax_pos" }
use std::ops::{Add, Deref, Sub, Mul, AddAssign, Range, RangeInclusive};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use syntax_pos::symbol::{sym, Symbol};
pub mod call;
}
}
+ pub fn to_symbol(self) -> Symbol {
+ match self {
+ FloatTy::F32 => sym::f32,
+ FloatTy::F64 => sym::f64,
+ }
+ }
+
pub fn bit_width(self) -> usize {
match self {
FloatTy::F32 => 32,
| Some(DefKind::TraitAlias) => program_clauses_for_trait(tcx, def_id),
// FIXME(eddyb) deduplicate this `associated_item` call with
// `program_clauses_for_associated_type_{value,def}`.
- Some(DefKind::AssociatedTy) => match tcx.associated_item(def_id).container {
- ty::AssociatedItemContainer::ImplContainer(_) =>
+ Some(DefKind::AssocTy) => match tcx.associated_item(def_id).container {
+ ty::AssocItemContainer::ImplContainer(_) =>
program_clauses_for_associated_type_value(tcx, def_id),
- ty::AssociatedItemContainer::TraitContainer(_) =>
+ ty::AssocItemContainer::TraitContainer(_) =>
program_clauses_for_associated_type_def(tcx, def_id)
},
Some(DefKind::Struct)
// ```
let item = tcx.associated_item(item_id);
- debug_assert_eq!(item.kind, ty::AssociatedKind::Type);
+ debug_assert_eq!(item.kind, ty::AssocKind::Type);
let trait_id = match item.container {
- ty::AssociatedItemContainer::TraitContainer(trait_id) => trait_id,
+ ty::AssocItemContainer::TraitContainer(trait_id) => trait_id,
_ => bug!("not an trait container"),
};
// ```
let item = tcx.associated_item(item_id);
- debug_assert_eq!(item.kind, ty::AssociatedKind::Type);
+ debug_assert_eq!(item.kind, ty::AssocKind::Type);
let impl_id = match item.container {
- ty::AssociatedItemContainer::ImplContainer(impl_id) => impl_id,
+ ty::AssocItemContainer::ImplContainer(impl_id) => impl_id,
_ => bug!("not an impl container"),
};
-> bool
{
self.tcx().associated_items(trait_def_id).any(|item| {
- item.kind == ty::AssociatedKind::Type &&
+ item.kind == ty::AssocKind::Type &&
self.tcx().hygienic_eq(assoc_name, item.ident, trait_def_id)
})
}
let (assoc_ident, def_scope) =
tcx.adjust_ident(binding.item_name, candidate.def_id(), hir_ref_id);
let assoc_ty = tcx.associated_items(candidate.def_id()).find(|i| {
- i.kind == ty::AssociatedKind::Type && i.ident.modern() == assoc_ident
+ i.kind == ty::AssocKind::Type && i.ident.modern() == assoc_ident
}).expect("missing associated type");
if !assoc_ty.vis.is_accessible_from(def_scope, tcx) {
ty::Predicate::Trait(pred) => {
associated_types
.extend(tcx.associated_items(pred.def_id())
- .filter(|item| item.kind == ty::AssociatedKind::Type)
+ .filter(|item| item.kind == ty::AssocKind::Type)
.map(|item| item.def_id));
}
ty::Predicate::Projection(pred) => {
for bound in bounds {
let bound_span = self.tcx().associated_items(bound.def_id()).find(|item| {
- item.kind == ty::AssociatedKind::Type &&
+ item.kind == ty::AssocKind::Type &&
self.tcx().hygienic_eq(assoc_name, item.ident, bound.def_id())
})
.and_then(|item| self.tcx().hir().span_if_local(item.def_id));
let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, bound);
let ty = self.normalize_ty(span, ty);
- let kind = DefKind::AssociatedTy;
+ let kind = DefKind::AssocTy;
if !item.vis.is_accessible_from(def_scope, tcx) {
let msg = format!("{} `{}` is private", kind.descr(), assoc_ident);
tcx.sess.span_err(span, &msg);
// Case 4. Reference to a method or associated const.
DefKind::Method
- | DefKind::AssociatedConst => {
+ | DefKind::AssocConst => {
if segments.len() >= 2 {
let generics = tcx.generics_of(def_id);
path_segs.push(PathSeg(generics.parent.unwrap(), last - 1));
self.prohibit_generics(&path.segments);
tcx.mk_self_type()
}
- Res::Def(DefKind::AssociatedTy, def_id) => {
+ Res::Def(DefKind::AssocTy, def_id) => {
debug_assert!(path.segments.len() >= 2);
self.prohibit_generics(&path.segments[..path.segments.len() - 2]);
self.qpath_to_ty(span,
PatKind::Path(ref qpath) => {
let (def, _, _) = self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span);
match def {
- Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssociatedConst, _) => false,
+ Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => false,
_ => true,
}
}
return tcx.types.err;
}
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | Res::SelfCtor(..) |
- Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssociatedConst, _) => {} // OK
+ Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {} // OK
_ => bug!("unexpected pattern resolution: {:?}", res)
}
on_error();
return tcx.types.err;
}
- Res::Def(DefKind::AssociatedConst, _) | Res::Def(DefKind::Method, _) => {
+ Res::Def(DefKind::AssocConst, _) | Res::Def(DefKind::Method, _) => {
report_unexpected_res(res);
return tcx.types.err;
}
/// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- impl_m: &ty::AssociatedItem,
+ impl_m: &ty::AssocItem,
impl_m_span: Span,
- trait_m: &ty::AssociatedItem,
+ trait_m: &ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>,
trait_item_span: Option<Span>) {
debug!("compare_impl_method(impl_trait_ref={:?})",
}
fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- impl_m: &ty::AssociatedItem,
+ impl_m: &ty::AssocItem,
impl_m_span: Span,
- trait_m: &ty::AssociatedItem,
+ trait_m: &ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>)
-> Result<(), ErrorReported> {
let trait_to_impl_substs = impl_trait_ref.substs;
fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
span: Span,
- impl_m: &ty::AssociatedItem,
- trait_m: &ty::AssociatedItem,
+ impl_m: &ty::AssocItem,
+ trait_m: &ty::AssocItem,
trait_generics: &ty::Generics,
impl_generics: &ty::Generics,
trait_to_skol_substs: SubstsRef<'tcx>)
param_env: ty::ParamEnv<'tcx>,
terr: &TypeError<'_>,
cause: &ObligationCause<'tcx>,
- impl_m: &ty::AssociatedItem,
+ impl_m: &ty::AssocItem,
impl_sig: ty::FnSig<'tcx>,
- trait_m: &ty::AssociatedItem,
+ trait_m: &ty::AssocItem,
trait_sig: ty::FnSig<'tcx>)
-> (Span, Option<Span>) {
let tcx = infcx.tcx;
}
fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- impl_m: &ty::AssociatedItem,
+ impl_m: &ty::AssocItem,
impl_m_span: Span,
- trait_m: &ty::AssociatedItem,
+ trait_m: &ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>)
-> Result<(), ErrorReported>
{
// inscrutable, particularly for cases where one method has no
// self.
- let self_string = |method: &ty::AssociatedItem| {
+ let self_string = |method: &ty::AssocItem| {
let untransformed_self_ty = match method.container {
ty::ImplContainer(_) => impl_trait_ref.self_ty(),
ty::TraitContainer(_) => tcx.mk_self_type()
fn compare_number_of_generics<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- impl_: &ty::AssociatedItem,
+ impl_: &ty::AssocItem,
impl_span: Span,
- trait_: &ty::AssociatedItem,
+ trait_: &ty::AssocItem,
trait_span: Option<Span>,
) -> Result<(), ErrorReported> {
let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();
}
fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- impl_m: &ty::AssociatedItem,
+ impl_m: &ty::AssocItem,
impl_m_span: Span,
- trait_m: &ty::AssociatedItem,
+ trait_m: &ty::AssocItem,
trait_item_span: Option<Span>)
-> Result<(), ErrorReported> {
let impl_m_fty = tcx.fn_sig(impl_m.def_id);
}
fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- impl_m: &ty::AssociatedItem,
- trait_m: &ty::AssociatedItem)
+ impl_m: &ty::AssocItem,
+ trait_m: &ty::AssocItem)
-> Result<(), ErrorReported> {
// FIXME(chrisvittal) Clean up this function, list of FIXME items:
// 1. Better messages for the span labels
}
pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- impl_c: &ty::AssociatedItem,
+ impl_c: &ty::AssocItem,
impl_c_span: Span,
- trait_c: &ty::AssociatedItem,
+ trait_c: &ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>) {
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
use rustc::hir;
use rustc::hir::Node;
use rustc::hir::{print, lowering::is_range_literal};
-use rustc::ty::{self, Ty, AssociatedItem};
+use rustc::ty::{self, Ty, AssocItem};
use rustc::ty::adjustment::AllowTwoPhase;
use errors::{Applicability, DiagnosticBuilder};
}
pub fn get_conversion_methods(&self, span: Span, expected: Ty<'tcx>, checked_ty: Ty<'tcx>)
- -> Vec<AssociatedItem> {
+ -> Vec<AssocItem> {
let mut methods = self.probe_for_return_type(span,
probe::Mode::MethodCall,
expected,
}
// This function checks if the method isn't static and takes other arguments than `self`.
- fn has_no_input_arg(&self, method: &AssociatedItem) -> bool {
+ fn has_no_input_arg(&self, method: &AssocItem) -> bool {
match method.kind {
- ty::AssociatedKind::Method => {
+ ty::AssocKind::Method => {
self.tcx.fn_sig(method.def_id).inputs().skip_binder().len() == 1
}
_ => false,
pub static_candidates: Vec<CandidateSource>,
pub unsatisfied_predicates: Vec<TraitRef<'tcx>>,
pub out_of_scope_traits: Vec<DefId>,
- pub lev_candidate: Option<ty::AssociatedItem>,
+ pub lev_candidate: Option<ty::AssocItem>,
pub mode: probe::Mode,
}
pub fn new(static_candidates: Vec<CandidateSource>,
unsatisfied_predicates: Vec<TraitRef<'tcx>>,
out_of_scope_traits: Vec<DefId>,
- lev_candidate: Option<ty::AssociatedItem>,
+ lev_candidate: Option<ty::AssocItem>,
mode: probe::Mode)
-> Self {
NoMatchData {
/// Finds item with name `item_name` defined in impl/trait `def_id`
/// and return it, or `None`, if no such item was defined there.
pub fn associated_item(&self, def_id: DefId, item_name: ast::Ident, ns: Namespace)
- -> Option<ty::AssociatedItem> {
+ -> Option<ty::AssocItem> {
self.tcx.associated_items(def_id).find(|item| {
Namespace::from(item.kind) == ns &&
self.tcx.hygienic_eq(item_name, item.ident, def_id)
#[derive(Debug)]
struct Candidate<'tcx> {
// Candidates are (I'm not quite sure, but they are mostly) basically
- // some metadata on top of a `ty::AssociatedItem` (without substs).
+ // some metadata on top of a `ty::AssocItem` (without substs).
//
// However, method probing wants to be able to evaluate the predicates
// for a function with the substs applied - for example, if a function
// if `T: Sized`.
xform_self_ty: Ty<'tcx>,
xform_ret_ty: Option<Ty<'tcx>>,
- item: ty::AssociatedItem,
+ item: ty::AssocItem,
kind: CandidateKind<'tcx>,
import_ids: SmallVec<[hir::HirId; 1]>,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Pick<'tcx> {
- pub item: ty::AssociatedItem,
+ pub item: ty::AssocItem,
pub kind: PickKind<'tcx>,
pub import_ids: SmallVec<[hir::HirId; 1]>,
return_type: Ty<'tcx>,
self_ty: Ty<'tcx>,
scope_expr_id: hir::HirId)
- -> Vec<ty::AssociatedItem> {
+ -> Vec<ty::AssocItem> {
debug!("probe(self_ty={:?}, return_type={}, scope_expr_id={})",
self_ty,
return_type,
mut mk_cand: F)
where F: for<'b> FnMut(&mut ProbeContext<'b, 'gcx, 'tcx>,
ty::PolyTraitRef<'tcx>,
- ty::AssociatedItem)
+ ty::AssocItem)
{
let tcx = self.tcx;
for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
}
pub fn matches_return_type(&self,
- method: &ty::AssociatedItem,
+ method: &ty::AssocItem,
self_ty: Option<Ty<'tcx>>,
expected: Ty<'tcx>) -> bool {
match method.kind {
- ty::AssociatedKind::Method => {
+ ty::AssocKind::Method => {
let fty = self.tcx.fn_sig(method.def_id);
self.probe(|_| {
let substs = self.fresh_substs_for_item(self.span, method.def_id);
/// Similarly to `probe_for_return_type`, this method attempts to find the best matching
/// candidate method where the method name may have been misspelt. Similarly to other
/// Levenshtein based suggestions, we provide at most one such suggestion.
- fn probe_for_lev_candidate(&mut self) -> Result<Option<ty::AssociatedItem>, MethodError<'tcx>> {
+ fn probe_for_lev_candidate(&mut self) -> Result<Option<ty::AssocItem>, MethodError<'tcx>> {
debug!("Probing for method names similar to {:?}",
self.method_name);
let method_names = pcx.candidate_method_names();
pcx.allow_similar_names = false;
- let applicable_close_candidates: Vec<ty::AssociatedItem> = method_names
+ let applicable_close_candidates: Vec<ty::AssocItem> = method_names
.iter()
.filter_map(|&method_name| {
pcx.reset();
///////////////////////////////////////////////////////////////////////////
// MISCELLANY
- fn has_applicable_self(&self, item: &ty::AssociatedItem) -> bool {
+ fn has_applicable_self(&self, item: &ty::AssocItem) -> bool {
// "Fast track" -- check for usage of sugar when in method call
// mode.
//
match self.mode {
Mode::MethodCall => item.method_has_self_argument,
Mode::Path => match item.kind {
- ty::AssociatedKind::Existential |
- ty::AssociatedKind::Type => false,
- ty::AssociatedKind::Method | ty::AssociatedKind::Const => true
+ ty::AssocKind::Existential |
+ ty::AssocKind::Type => false,
+ ty::AssocKind::Method | ty::AssocKind::Const => true
},
}
// FIXME -- check for types that deref to `Self`,
}
fn xform_self_ty(&self,
- item: &ty::AssociatedItem,
+ item: &ty::AssocItem,
impl_ty: Ty<'tcx>,
substs: SubstsRef<'tcx>)
-> (Ty<'tcx>, Option<Ty<'tcx>>) {
- if item.kind == ty::AssociatedKind::Method && self.mode == Mode::MethodCall {
+ if item.kind == ty::AssocKind::Method && self.mode == Mode::MethodCall {
let sig = self.xform_method_sig(item.def_id, substs);
(sig.inputs()[0], Some(sig.output()))
} else {
/// Finds the method with the appropriate name (or return type, as the case may be). If
/// `allow_similar_names` is set, find methods with close-matching names.
- fn impl_or_trait_item(&self, def_id: DefId) -> Vec<ty::AssociatedItem> {
+ fn impl_or_trait_item(&self, def_id: DefId) -> Vec<ty::AssocItem> {
if let Some(name) = self.method_name {
if self.allow_similar_names {
let max_dist = max(name.as_str().len(), 3) / 3;
fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
trait_def: &ty::TraitDef,
- trait_item: &ty::AssociatedItem,
+ trait_item: &ty::AssocItem,
impl_id: DefId,
impl_item: &hir::ImplItem)
{
let ancestors = trait_def.ancestors(tcx, impl_id);
let kind = match impl_item.node {
- hir::ImplItemKind::Const(..) => ty::AssociatedKind::Const,
- hir::ImplItemKind::Method(..) => ty::AssociatedKind::Method,
- hir::ImplItemKind::Existential(..) => ty::AssociatedKind::Existential,
- hir::ImplItemKind::Type(_) => ty::AssociatedKind::Type
+ hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
+ hir::ImplItemKind::Method(..) => ty::AssocKind::Method,
+ hir::ImplItemKind::Existential(..) => ty::AssocKind::Existential,
+ hir::ImplItemKind::Type(_) => ty::AssocKind::Type
};
let parent = ancestors.defs(tcx, trait_item.ident, kind, trait_def.def_id).nth(1)
match impl_item.node {
hir::ImplItemKind::Const(..) => {
// Find associated const definition.
- if ty_trait_item.kind == ty::AssociatedKind::Const {
+ if ty_trait_item.kind == ty::AssocKind::Const {
compare_const_impl(tcx,
&ty_impl_item,
impl_item.span,
}
hir::ImplItemKind::Method(..) => {
let trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
- if ty_trait_item.kind == ty::AssociatedKind::Method {
+ if ty_trait_item.kind == ty::AssocKind::Method {
compare_impl_method(tcx,
&ty_impl_item,
impl_item.span,
}
hir::ImplItemKind::Existential(..) |
hir::ImplItemKind::Type(_) => {
- if ty_trait_item.kind == ty::AssociatedKind::Type {
+ if ty_trait_item.kind == ty::AssocKind::Type {
if ty_trait_item.defaultness.has_value() {
overridden_associated_type = Some(impl_item);
}
fn resolve_place_op(&self, op: PlaceOp, is_mut: bool) -> (Option<DefId>, ast::Ident) {
let (tr, name) = match (op, is_mut) {
- (PlaceOp::Deref, false) =>
- (self.tcx.lang_items().deref_trait(), "deref"),
- (PlaceOp::Deref, true) =>
- (self.tcx.lang_items().deref_mut_trait(), "deref_mut"),
- (PlaceOp::Index, false) =>
- (self.tcx.lang_items().index_trait(), "index"),
- (PlaceOp::Index, true) =>
- (self.tcx.lang_items().index_mut_trait(), "index_mut"),
+ (PlaceOp::Deref, false) => (self.tcx.lang_items().deref_trait(), sym::deref),
+ (PlaceOp::Deref, true) => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut),
+ (PlaceOp::Index, false) => (self.tcx.lang_items().index_trait(), sym::index),
+ (PlaceOp::Index, true) => (self.tcx.lang_items().index_mut_trait(), sym::index_mut),
};
- (tr, ast::Ident::from_str(name))
+ (tr, ast::Ident::with_empty_ctxt(name))
}
fn try_overloaded_place_op(&self,
Res::Def(DefKind::Struct, _)
| Res::Def(DefKind::Union, _)
| Res::Def(DefKind::TyAlias, _)
- | Res::Def(DefKind::AssociatedTy, _)
+ | Res::Def(DefKind::AssocTy, _)
| Res::SelfTy(..) => {
match ty.sty {
ty::Adt(adt, substs) if !adt.is_enum() => {
if element_ty.references_error() {
tcx.types.err
} else if let Ok(count) = count {
- tcx.mk_ty(ty::Array(t, tcx.mk_const(count)))
+ tcx.mk_ty(ty::Array(t, count))
} else {
tcx.types.err
}
// This is less than ideal, it will not suggest a return type span on any
// method called `main`, regardless of whether it is actually the entry point,
// but it will still present it as the reason for the expected type.
- Some((decl, ident, ident.name != Symbol::intern("main")))
+ Some((decl, ident, ident.name != sym::main))
}),
Node::TraitItem(&hir::TraitItem {
ident, node: hir::TraitItemKind::Method(hir::MethodSig {
&self,
res: Res,
span: Span,
- ) -> Result<(DefKind, DefId, Ty<'tcx>), ErrorReported> {
+ ) -> Result<Res, ErrorReported> {
let tcx = self.tcx;
if let Res::SelfCtor(impl_def_id) = res {
let ty = self.impl_self_ty(span, impl_def_id).ty;
Some(adt_def) if adt_def.has_ctor() => {
let variant = adt_def.non_enum_variant();
let ctor_def_id = variant.ctor_def_id.unwrap();
- Ok((
- DefKind::Ctor(CtorOf::Struct, variant.ctor_kind),
- ctor_def_id,
- tcx.type_of(ctor_def_id),
- ))
+ Ok(Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id))
}
_ => {
let mut err = tcx.sess.struct_span_err(span,
}
}
} else {
- match res {
- Res::Def(kind, def_id) => {
- // The things we are substituting into the type should not contain
- // escaping late-bound regions, and nor should the base type scheme.
- let ty = tcx.type_of(def_id);
- Ok((kind, def_id, ty))
- }
- _ => span_bug!(span, "unexpected res in rewrite_self_ctor: {:?}", res),
- }
+ Ok(res)
}
}
let tcx = self.tcx;
- match res {
- Res::Local(hid) | Res::Upvar(hid, ..) => {
- let ty = self.local_ty(span, hid).decl_ty;
- let ty = self.normalize_associated_types_in(span, &ty);
- self.write_ty(hir_id, ty);
- return (ty, res);
- }
- _ => {}
- }
-
- let (kind, def_id, ty) = match self.rewrite_self_ctor(res, span) {
- Ok(result) => result,
+ let res = match self.rewrite_self_ctor(res, span) {
+ Ok(res) => res,
Err(ErrorReported) => return (tcx.types.err, res),
};
- let path_segs =
- AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id);
+ let path_segs = match res {
+ Res::Local(_) | Res::Upvar(..) => Vec::new(),
+ Res::Def(kind, def_id) =>
+ AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id),
+ _ => bug!("instantiate_value_path on {:?}", res),
+ };
let mut user_self_ty = None;
let mut is_alias_variant_ctor = false;
- match kind {
- DefKind::Ctor(CtorOf::Variant, _) => {
+ match res {
+ Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => {
if let Some(self_ty) = self_ty {
let adt_def = self_ty.ty_adt_def().unwrap();
user_self_ty = Some(UserSelfTy {
is_alias_variant_ctor = true;
}
}
- DefKind::Method
- | DefKind::AssociatedConst => {
+ Res::Def(DefKind::Method, def_id)
+ | Res::Def(DefKind::AssocConst, def_id) => {
let container = tcx.associated_item(def_id).container;
debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container);
match container {
None
}
}));
+
+ match res {
+ Res::Local(hid) | Res::Upvar(hid, ..) => {
+ let ty = self.local_ty(span, hid).decl_ty;
+ let ty = self.normalize_associated_types_in(span, &ty);
+ self.write_ty(hir_id, ty);
+ return (ty, res);
+ }
+ _ => {}
+ }
+
if generics_has_err {
// Don't try to infer type parameters when prohibited generic arguments were given.
user_self_ty = None;
tcx.generics_of(*def_id).has_self
}).unwrap_or(false);
+ let def_id = res.def_id();
+
+ // The things we are substituting into the type should not contain
+ // escaping late-bound regions, and nor should the base type scheme.
+ let ty = tcx.type_of(def_id);
+
let substs = AstConv::create_substs_for_generic_args(
tcx,
def_id,
ty_substituted);
self.write_substs(hir_id, substs);
- (ty_substituted, Res::Def(kind, def_id))
+ (ty_substituted, res)
}
fn check_rustc_args_require_const(&self,
};
match item.kind {
- ty::AssociatedKind::Const => {
+ ty::AssocKind::Const => {
let ty = fcx.tcx.type_of(item.def_id);
let ty = fcx.normalize_associated_types_in(span, &ty);
fcx.register_wf_obligation(ty, span, code.clone());
}
- ty::AssociatedKind::Method => {
+ ty::AssocKind::Method => {
reject_shadowing_parameters(fcx.tcx, item.def_id);
let sig = fcx.tcx.fn_sig(item.def_id);
let sig = fcx.normalize_associated_types_in(span, &sig);
let sig_if_method = sig_if_method.expect("bad signature for method");
check_method_receiver(fcx, sig_if_method, &item, self_ty);
}
- ty::AssociatedKind::Type => {
+ ty::AssocKind::Type => {
if item.defaultness.has_value() {
let ty = fcx.tcx.type_of(item.def_id);
let ty = fcx.normalize_associated_types_in(span, &ty);
fcx.register_wf_obligation(ty, span, code.clone());
}
}
- ty::AssociatedKind::Existential => {
+ ty::AssocKind::Existential => {
// do nothing, existential types check themselves
}
}
fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
method_sig: &hir::MethodSig,
- method: &ty::AssociatedItem,
+ method: &ty::AssocItem,
self_ty: Ty<'tcx>)
{
// check that the method has a valid receiver type, given the type `Self`
use rustc::hir::GenericParamKind;
use rustc::hir::{self, CodegenFnAttrFlags, CodegenFnAttrs, Unsafety};
+use errors::Applicability;
+
use std::iter;
struct OnlySelfBounds(bool);
Some(list) => list,
None => return,
};
+ let bad_item = |span| {
+ let msg = "malformed `target_feature` attribute input";
+ let code = "enable = \"..\"".to_owned();
+ tcx.sess.struct_span_err(span, &msg)
+ .span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
+ .emit();
+ };
let rust_features = tcx.features();
for item in list {
// Only `enable = ...` is accepted in the meta item list
if !item.check_name(sym::enable) {
- let msg = "#[target_feature(..)] only accepts sub-keys of `enable` \
- currently";
- tcx.sess.span_err(item.span(), &msg);
+ bad_item(item.span());
continue;
}
let value = match item.value_str() {
Some(value) => value,
None => {
- let msg = "#[target_feature] attribute must be of the form \
- #[target_feature(enable = \"..\")]";
- tcx.sess.span_err(item.span(), &msg);
+ bad_item(item.span());
continue;
}
};
Some(g) => g,
None => {
let msg = format!(
- "the feature named `{}` is not valid for \
- this target",
+ "the feature named `{}` is not valid for this target",
feature
);
let mut err = tcx.sess.struct_span_err(item.span(), &msg);
-
+ err.span_label(
+ item.span(),
+ format!("`{}` is not valid for this target", feature),
+ );
if feature.starts_with("+") {
let valid = whitelist.contains_key(&feature[1..]);
if valid {
}
} else if attr.check_name(sym::target_feature) {
if tcx.fn_sig(id).unsafety() == Unsafety::Normal {
- let msg = "#[target_feature(..)] can only be applied to \
- `unsafe` function";
- tcx.sess.span_err(attr.span, msg);
+ let msg = "#[target_feature(..)] can only be applied to `unsafe` functions";
+ tcx.sess.struct_span_err(attr.span, msg)
+ .span_label(attr.span, "can only be applied to `unsafe` functions")
+ .span_label(tcx.def_span(id), "not an `unsafe` function")
+ .emit();
}
from_target_feature(
tcx,
.map(|item_ref| tcx.hir().local_def_id_from_hir_id(item_ref.id.hir_id))
.filter(|&def_id| {
let item = tcx.associated_item(def_id);
- item.kind == ty::AssociatedKind::Type && item.defaultness.has_value()
+ item.kind == ty::AssocKind::Type && item.defaultness.has_value()
})
.flat_map(|def_id| {
cgp::parameters_for(&tcx.type_of(def_id), true)
Value,
}
-impl From<ty::AssociatedKind> for Namespace {
- fn from(a_kind: ty::AssociatedKind) -> Self {
+impl From<ty::AssocKind> for Namespace {
+ fn from(a_kind: ty::AssocKind) -> Self {
match a_kind {
- ty::AssociatedKind::Existential |
- ty::AssociatedKind::Type => Namespace::Type,
- ty::AssociatedKind::Const |
- ty::AssociatedKind::Method => Namespace::Value,
+ ty::AssocKind::Existential |
+ ty::AssocKind::Type => Namespace::Type,
+ ty::AssocKind::Const |
+ ty::AssocKind::Method => Namespace::Value,
}
}
}
self.type_() == ItemType::Variant
}
pub fn is_associated_type(&self) -> bool {
- self.type_() == ItemType::AssociatedType
+ self.type_() == ItemType::AssocType
}
pub fn is_associated_const(&self) -> bool {
- self.type_() == ItemType::AssociatedConst
+ self.type_() == ItemType::AssocConst
}
pub fn is_method(&self) -> bool {
self.type_() == ItemType::Method
MacroItem(Macro),
ProcMacroItem(ProcMacro),
PrimitiveItem(PrimitiveType),
- AssociatedConstItem(Type, Option<String>),
- AssociatedTypeItem(Vec<GenericBound>, Option<Type>),
+ AssocConstItem(Type, Option<String>),
+ AssocTypeItem(Vec<GenericBound>, Option<Type>),
/// An item that has been stripped by a rustdoc pass
StrippedItem(Box<ItemEnum>),
KeywordItem(String),
pub fn is_associated(&self) -> bool {
match *self {
ItemEnum::TypedefItem(_, _) |
- ItemEnum::AssociatedTypeItem(_, _) => true,
+ ItemEnum::AssocTypeItem(_, _) => true,
_ => false,
}
}
fn clean(&self, cx: &DocContext<'_>) -> Item {
let inner = match self.node {
hir::TraitItemKind::Const(ref ty, default) => {
- AssociatedConstItem(ty.clean(cx),
+ AssocConstItem(ty.clean(cx),
default.map(|e| print_const_expr(cx, e)))
}
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
})
}
hir::TraitItemKind::Type(ref bounds, ref default) => {
- AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
+ AssocTypeItem(bounds.clean(cx), default.clean(cx))
}
};
let local_did = cx.tcx.hir().local_def_id_from_hir_id(self.hir_id);
fn clean(&self, cx: &DocContext<'_>) -> Item {
let inner = match self.node {
hir::ImplItemKind::Const(ref ty, expr) => {
- AssociatedConstItem(ty.clean(cx),
+ AssocConstItem(ty.clean(cx),
Some(print_const_expr(cx, expr)))
}
hir::ImplItemKind::Method(ref sig, body) => {
}
}
-impl<'tcx> Clean<Item> for ty::AssociatedItem {
+impl<'tcx> Clean<Item> for ty::AssocItem {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let inner = match self.kind {
- ty::AssociatedKind::Const => {
+ ty::AssocKind::Const => {
let ty = cx.tcx.type_of(self.def_id);
let default = if self.defaultness.has_value() {
Some(inline::print_inlined_const(cx, self.def_id))
} else {
None
};
- AssociatedConstItem(ty.clean(cx), default)
+ AssocConstItem(ty.clean(cx), default)
}
- ty::AssociatedKind::Method => {
+ ty::AssocKind::Method => {
let generics = (cx.tcx.generics_of(self.def_id),
&cx.tcx.explicit_predicates_of(self.def_id)).clean(cx);
let sig = cx.tcx.fn_sig(self.def_id);
})
}
}
- ty::AssociatedKind::Type => {
+ ty::AssocKind::Type => {
let my_name = self.ident.name.clean(cx);
if let ty::TraitContainer(did) = self.container {
None
};
- AssociatedTypeItem(bounds, ty.clean(cx))
+ AssocTypeItem(bounds, ty.clean(cx))
} else {
TypedefItem(Typedef {
type_: cx.tcx.type_of(self.def_id).clean(cx),
}, true)
}
}
- ty::AssociatedKind::Existential => unimplemented!(),
+ ty::AssocKind::Existential => unimplemented!(),
};
let visibility = match self.container {
ty::Str => Primitive(PrimitiveType::Str),
ty::Slice(ty) => Slice(box ty.clean(cx)),
ty::Array(ty, n) => {
- let mut n = *cx.tcx.lift(&n).expect("array lift failed");
+ let mut n = cx.tcx.lift(&n).expect("array lift failed");
if let ConstValue::Unevaluated(def_id, substs) = n.val {
let param_env = cx.tcx.param_env(def_id);
let cid = GlobalId {
}
}
-fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
+fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String {
match n.val {
ConstValue::Unevaluated(def_id, _) => {
if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
}
},
_ => {
- let mut s = String::new();
- ::rustc::mir::fmt_const_val(&mut s, n).expect("fmt_const_val failed");
+ let mut s = n.to_string();
// array lengths are obviously usize
if s.ends_with("usize") {
let n = s.len() - "usize".len();
s.truncate(n);
+ if s.ends_with(": ") {
+ let n = s.len() - ": ".len();
+ s.truncate(n);
+ }
}
s
},
}
Res::SelfTy(..)
| Res::Def(DefKind::TyParam, _)
- | Res::Def(DefKind::AssociatedTy, _) => true,
+ | Res::Def(DefKind::AssocTy, _) => true,
_ => false,
};
let did = register_res(&*cx, path.res);
"<a class=\"type\" href=\"{url}#{shortty}.{name}\" \
title=\"type {path}::{name}\">{name}</a>",
url = url,
- shortty = ItemType::AssociatedType,
+ shortty = ItemType::AssocType,
name = name,
path = path.join("::"))?;
}
Variant = 13,
Macro = 14,
Primitive = 15,
- AssociatedType = 16,
+ AssocType = 16,
Constant = 17,
- AssociatedConst = 18,
+ AssocConst = 18,
Union = 19,
ForeignType = 20,
Keyword = 21,
clean::ForeignStaticItem(..) => ItemType::Static, // no ForeignStatic
clean::MacroItem(..) => ItemType::Macro,
clean::PrimitiveItem(..) => ItemType::Primitive,
- clean::AssociatedConstItem(..) => ItemType::AssociatedConst,
- clean::AssociatedTypeItem(..) => ItemType::AssociatedType,
+ clean::AssocConstItem(..) => ItemType::AssocConst,
+ clean::AssocTypeItem(..) => ItemType::AssocType,
clean::ForeignTypeItem => ItemType::ForeignType,
clean::KeywordItem(..) => ItemType::Keyword,
clean::TraitAliasItem(..) => ItemType::TraitAlias,
ItemType::Variant => "variant",
ItemType::Macro => "macro",
ItemType::Primitive => "primitive",
- ItemType::AssociatedType => "associatedtype",
+ ItemType::AssocType => "associatedtype",
ItemType::Constant => "constant",
- ItemType::AssociatedConst => "associatedconstant",
+ ItemType::AssocConst => "associatedconstant",
ItemType::ForeignType => "foreigntype",
ItemType::Keyword => "keyword",
ItemType::Existential => "existential",
ItemType::Typedef |
ItemType::Trait |
ItemType::Primitive |
- ItemType::AssociatedType |
+ ItemType::AssocType |
ItemType::Existential |
ItemType::TraitAlias |
ItemType::ForeignType => NameSpace::Type,
ItemType::StructField |
ItemType::Variant |
ItemType::Constant |
- ItemType::AssociatedConst => NameSpace::Value,
+ ItemType::AssocConst => NameSpace::Value,
ItemType::Macro |
ItemType::ProcAttribute |
if let Some(ref s) = item.name {
let (parent, is_inherent_impl_item) = match item.inner {
clean::StrippedItem(..) => ((None, None), false),
- clean::AssociatedConstItem(..) |
+ clean::AssocConstItem(..) |
clean::TypedefItem(_, true) if self.parent_is_trait_impl => {
// skip associated items in trait impls
((None, None), false)
}
- clean::AssociatedTypeItem(..) |
+ clean::AssocTypeItem(..) |
clean::TyMethodItem(..) |
clean::StructFieldItem(..) |
clean::VariantItem(..) => {
Some(&self.stack[..self.stack.len() - 1])),
false)
}
- clean::MethodItem(..) | clean::AssociatedConstItem(..) => {
+ clean::MethodItem(..) | clean::AssocConstItem(..) => {
if self.parent_stack.is_empty() {
((None, None), false)
} else {
let name = it.name.as_ref().unwrap();
let ty = match it.type_() {
- Typedef | AssociatedType => AssociatedType,
+ Typedef | AssocType => AssocType,
s@_ => s,
};
clean::MethodItem(ref m) => {
method(w, item, m.header, &m.generics, &m.decl, link, parent)
}
- clean::AssociatedConstItem(ref ty, ref default) => {
+ clean::AssocConstItem(ref ty, ref default) => {
assoc_const(w, item, ty, default.as_ref(), link,
if parent == ItemType::Trait { " " } else { "" })
}
- clean::AssociatedTypeItem(ref bounds, ref default) => {
+ clean::AssocTypeItem(ref bounds, ref default) => {
assoc_type(w, item, bounds, default.as_ref(), link,
if parent == ItemType::Trait { " " } else { "" })
}
}
}
clean::TypedefItem(ref tydef, _) => {
- let id = cx.derive_id(format!("{}.{}", ItemType::AssociatedType, name));
+ let id = cx.derive_id(format!("{}.{}", ItemType::AssocType, name));
let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
write!(w, "<code id='{}'>", ns_id)?;
assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id), "")?;
write!(w, "</code></h4>")?;
}
- clean::AssociatedConstItem(ref ty, ref default) => {
+ clean::AssocConstItem(ref ty, ref default) => {
let id = cx.derive_id(format!("{}.{}", item_type, name));
let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
}
write!(w, "</h4>")?;
}
- clean::AssociatedTypeItem(ref bounds, ref default) => {
+ clean::AssocTypeItem(ref bounds, ref default) => {
let id = cx.derive_id(format!("{}.{}", item_type, name));
let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
ItemType::Variant => ("variants", "Variants"),
ItemType::Macro => ("macros", "Macros"),
ItemType::Primitive => ("primitives", "Primitive Types"),
- ItemType::AssociatedType => ("associated-types", "Associated Types"),
- ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
+ ItemType::AssocType => ("associated-types", "Associated Types"),
+ ItemType::AssocConst => ("associated-consts", "Associated Constants"),
ItemType::ForeignType => ("foreign-types", "Foreign Types"),
ItemType::Keyword => ("keywords", "Keywords"),
ItemType::Existential => ("existentials", "Existentials"),
ItemType::Enum, ItemType::Constant, ItemType::Static, ItemType::Trait,
ItemType::Function, ItemType::Typedef, ItemType::Union, ItemType::Impl,
ItemType::TyMethod, ItemType::Method, ItemType::StructField, ItemType::Variant,
- ItemType::AssociatedType, ItemType::AssociatedConst, ItemType::ForeignType] {
+ ItemType::AssocType, ItemType::AssocConst, ItemType::ForeignType] {
if items.iter().any(|it| !it.is_stripped() && it.type_() == myty) {
let (short, name) = item_ty_to_strs(&myty);
sidebar.push_str(&format!("<li><a href=\"#{id}\">{name}</a></li>",
// In case this is a trait item, skip the
// early return and try looking for the trait.
let value = match result.res {
- Res::Def(DefKind::Method, _) | Res::Def(DefKind::AssociatedConst, _) => true,
- Res::Def(DefKind::AssociatedTy, _) => false,
+ Res::Def(DefKind::Method, _) | Res::Def(DefKind::AssocConst, _) => true,
+ Res::Def(DefKind::AssocTy, _) => false,
Res::Def(DefKind::Variant, _) => return handle_variant(cx, result.res),
// Not a trait item; just return what we found.
_ => return Ok((result.res, None))
return cx.tcx.associated_items(did)
.find(|item| item.ident.name == item_name)
.and_then(|item| match item.kind {
- ty::AssociatedKind::Method => Some("method"),
+ ty::AssocKind::Method => Some("method"),
_ => None,
})
.map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name))))
.find(|item| item.ident.name == item_name);
if let Some(item) = item {
let out = match item.kind {
- ty::AssociatedKind::Method if ns == ValueNS => "method",
- ty::AssociatedKind::Const if ns == ValueNS => "associatedconstant",
+ ty::AssocKind::Method if ns == ValueNS => "method",
+ ty::AssocKind::Const if ns == ValueNS => "associatedconstant",
_ => return Err(())
};
Ok((ty.res, Some(format!("{}.{}", out, item_name))))
.find(|item| item.ident.name == item_name);
if let Some(item) = item {
let kind = match item.kind {
- ty::AssociatedKind::Const if ns == ValueNS => "associatedconstant",
- ty::AssociatedKind::Type if ns == TypeNS => "associatedtype",
- ty::AssociatedKind::Method if ns == ValueNS => {
+ ty::AssocKind::Const if ns == ValueNS => "associatedconstant",
+ ty::AssocKind::Type if ns == TypeNS => "associatedtype",
+ ty::AssocKind::Method if ns == ValueNS => {
if item.defaultness.has_value() {
"method"
} else {
| clean::ForeignStaticItem(..)
| clean::ConstantItem(..)
| clean::UnionItem(..)
- | clean::AssociatedConstItem(..)
+ | clean::AssocConstItem(..)
| clean::TraitAliasItem(..)
| clean::ForeignTypeItem => {
if i.def_id.is_local() {
clean::PrimitiveItem(..) => {}
// Associated types are never stripped
- clean::AssociatedTypeItem(..) => {}
+ clean::AssocTypeItem(..) => {}
// Keywords are never stripped
clean::KeywordItem(..) => {}
profiler_builtins = { path = "../libprofiler_builtins", optional = true }
unwind = { path = "../libunwind" }
hashbrown = { version = "0.3.0", features = ['rustc-dep-of-std'] }
-rustc-demangle = { version = "0.1.10", features = ['rustc-dep-of-std'] }
-backtrace-sys = { version = "0.1.24", features = ["rustc-dep-of-std"], optional = true }
+
+[dependencies.backtrace]
+version = "0.3.25"
+default-features = false # don't use coresymbolication on OSX
+features = [
+ "rustc-dep-of-std", # enable build support for integrating into libstd
+ "dbghelp", # backtrace/symbolize on MSVC
+ "libbacktrace", # symbolize on most platforms
+ "libunwind", # backtrace on most platforms
+ "dladdr", # symbolize on platforms w/o libbacktrace
+]
+optional = true
[dev-dependencies]
rand = "0.6.1"
[features]
default = ["std_detect_file_io", "std_detect_dlsym_getauxval"]
-backtrace = ["backtrace-sys"]
panic-unwind = ["panic_unwind"]
profiler = ["profiler_builtins"]
compiler-builtins-c = ["alloc/compiler-builtins-c"]
/// # }
/// ```
///
-/// Using `env::join_paths` with `env::spit_paths` to append an item to the `PATH` environment
+/// Using `env::join_paths` with [`env::split_paths`] to append an item to the `PATH` environment
/// variable:
///
/// ```
/// Ok(())
/// }
/// ```
+///
+/// [`env::split_paths`]: fn.split_paths.html
#[stable(feature = "env", since = "1.0.0")]
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
where I: IntoIterator<Item=T>, T: AsRef<OsStr>
+++ /dev/null
-use crate::error::Error;
-use crate::ffi::CStr;
-use crate::fmt;
-use crate::intrinsics;
-use crate::io;
-use crate::sys_common::backtrace::Frame;
-
-use unwind as uw;
-
-pub struct BacktraceContext;
-
-struct Context<'a> {
- idx: usize,
- frames: &'a mut [Frame],
-}
-
-#[derive(Debug)]
-struct UnwindError(uw::_Unwind_Reason_Code);
-
-impl Error for UnwindError {
- fn description(&self) -> &'static str {
- "unexpected return value while unwinding"
- }
-}
-
-impl fmt::Display for UnwindError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}: {:?}", self.description(), self.0)
- }
-}
-
-#[inline(never)] // if we know this is a function call, we can skip it when
- // tracing
-pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
- let mut cx = Context { idx: 0, frames };
- let result_unwind = unsafe {
- uw::_Unwind_Backtrace(trace_fn, &mut cx as *mut Context<'_> as *mut libc::c_void)
- };
- // See libunwind:src/unwind/Backtrace.c for the return values.
- // No, there is no doc.
- match result_unwind {
- // These return codes seem to be benign and need to be ignored for backtraces
- // to show up properly on all tested platforms.
- uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
- Ok((cx.idx, BacktraceContext))
- }
- _ => Err(io::Error::new(
- io::ErrorKind::Other,
- UnwindError(result_unwind),
- )),
- }
-}
-
-extern "C" fn trace_fn(
- ctx: *mut uw::_Unwind_Context,
- arg: *mut libc::c_void,
-) -> uw::_Unwind_Reason_Code {
- let cx = unsafe { &mut *(arg as *mut Context<'_>) };
- if cx.idx >= cx.frames.len() {
- return uw::_URC_NORMAL_STOP;
- }
-
- let mut ip_before_insn = 0;
- let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void };
- if !ip.is_null() && ip_before_insn == 0 {
- // this is a non-signaling frame, so `ip` refers to the address
- // after the calling instruction. account for that.
- ip = (ip as usize - 1) as *mut _;
- }
-
- let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) };
- cx.frames[cx.idx] = Frame {
- symbol_addr: symaddr as *mut u8,
- exact_position: ip as *mut u8,
- inline_context: 0,
- };
- cx.idx += 1;
-
- uw::_URC_NO_REASON
-}
-
-pub fn foreach_symbol_fileline<F>(_: Frame, _: F, _: &BacktraceContext) -> io::Result<bool>
-where
- F: FnMut(&[u8], u32) -> io::Result<()>,
-{
- // No way to obtain this information on CloudABI.
- Ok(false)
-}
-
-pub fn resolve_symname<F>(frame: Frame, callback: F, _: &BacktraceContext) -> io::Result<()>
-where
- F: FnOnce(Option<&str>) -> io::Result<()>,
-{
- unsafe {
- let mut info: Dl_info = intrinsics::init();
- let symname =
- if dladdr(frame.exact_position as *mut _, &mut info) == 0 || info.dli_sname.is_null() {
- None
- } else {
- CStr::from_ptr(info.dli_sname).to_str().ok()
- };
- callback(symname)
- }
-}
-
-#[repr(C)]
-struct Dl_info {
- dli_fname: *const libc::c_char,
- dli_fbase: *mut libc::c_void,
- dli_sname: *const libc::c_char,
- dli_saddr: *mut libc::c_void,
-}
-
-extern "C" {
- fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int;
-}
#[path = "../unix/alloc.rs"]
pub mod alloc;
pub mod args;
-#[cfg(feature = "backtrace")]
-pub mod backtrace;
#[path = "../unix/cmath.rs"]
pub mod cmath;
pub mod condvar;
+++ /dev/null
-/// See sys/unix/backtrace/mod.rs for an explanation of the method used here.
-
-pub use self::tracing::unwind_backtrace;
-pub use self::printing::{foreach_symbol_fileline, resolve_symname};
-
-// tracing impls:
-mod tracing;
-// symbol resolvers:
-mod printing;
-
-pub mod gnu {
- use crate::io;
- use crate::fs;
- use crate::vec::Vec;
- use crate::ffi::OsStr;
- use crate::os::unix::ffi::OsStrExt;
- use crate::io::Read;
- use libc::c_char;
-
- pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
- let mut exefile = fs::File::open("sys:exe")?;
- let mut exename = Vec::new();
- exefile.read_to_end(&mut exename)?;
- if exename.last() == Some(&b'\n') {
- exename.pop();
- }
- let file = fs::File::open(OsStr::from_bytes(&exename))?;
- Ok((exename.into_iter().map(|c| c as c_char).collect(), file))
- }
-}
-
-pub struct BacktraceContext;
+++ /dev/null
-pub use crate::sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
+++ /dev/null
-use crate::error::Error;
-use crate::fmt;
-use crate::io;
-use crate::sys::backtrace::BacktraceContext;
-use crate::sys_common::backtrace::Frame;
-
-use unwind as uw;
-
-struct Context<'a> {
- idx: usize,
- frames: &'a mut [Frame],
-}
-
-#[derive(Debug)]
-struct UnwindError(uw::_Unwind_Reason_Code);
-
-impl Error for UnwindError {
- fn description(&self) -> &'static str {
- "unexpected return value while unwinding"
- }
-}
-
-impl fmt::Display for UnwindError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}: {:?}", self.description(), self.0)
- }
-}
-
-#[inline(never)] // if we know this is a function call, we can skip it when
- // tracing
-pub fn unwind_backtrace(frames: &mut [Frame])
- -> io::Result<(usize, BacktraceContext)>
-{
- let mut cx = Context {
- idx: 0,
- frames: frames,
- };
- let result_unwind = unsafe {
- uw::_Unwind_Backtrace(trace_fn,
- &mut cx as *mut Context<'_>
- as *mut libc::c_void)
- };
- // See libunwind:src/unwind/Backtrace.c for the return values.
- // No, there is no doc.
- match result_unwind {
- // These return codes seem to be benign and need to be ignored for backtraces
- // to show up properly on all tested platforms.
- uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
- Ok((cx.idx, BacktraceContext))
- }
- _ => {
- Err(io::Error::new(io::ErrorKind::Other,
- UnwindError(result_unwind)))
- }
- }
-}
-
-extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
- arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
- let cx = unsafe { &mut *(arg as *mut Context<'_>) };
- if cx.idx >= cx.frames.len() {
- return uw::_URC_NORMAL_STOP;
- }
-
- let mut ip_before_insn = 0;
- let mut ip = unsafe {
- uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
- };
- if !ip.is_null() && ip_before_insn == 0 {
- // this is a non-signaling frame, so `ip` refers to the address
- // after the calling instruction. account for that.
- ip = (ip as usize - 1) as *mut _;
- }
-
- // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
- // it appears to work fine without it, so we only use
- // FindEnclosingFunction on non-osx platforms. In doing so, we get a
- // slightly more accurate stack trace in the process.
- //
- // This is often because panic involves the last instruction of a
- // function being "call std::rt::begin_unwind", with no ret
- // instructions after it. This means that the return instruction
- // pointer points *outside* of the calling function, and by
- // unwinding it we go back to the original function.
- let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
- ip
- } else {
- unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
- };
-
- cx.frames[cx.idx] = Frame {
- symbol_addr: symaddr as *mut u8,
- exact_position: ip as *mut u8,
- inline_context: 0,
- };
- cx.idx += 1;
-
- uw::_URC_NO_REASON
-}
#[path = "../unix/alloc.rs"]
pub mod alloc;
pub mod args;
-#[cfg(feature = "backtrace")]
-pub mod backtrace;
pub mod cmath;
pub mod condvar;
pub mod env;
+++ /dev/null
-use crate::io;
-use crate::error::Error;
-use crate::fmt;
-use crate::sys_common::backtrace::Frame;
-use crate::sys::sgx::abi::mem::image_base;
-
-use unwind as uw;
-
-pub struct BacktraceContext;
-
-struct Context<'a> {
- idx: usize,
- frames: &'a mut [Frame],
-}
-
-#[derive(Debug)]
-struct UnwindError(uw::_Unwind_Reason_Code);
-
-impl Error for UnwindError {
- fn description(&self) -> &'static str {
- "unexpected return value while unwinding"
- }
-}
-
-impl fmt::Display for UnwindError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}: {:?}", self.description(), self.0)
- }
-}
-
-#[inline(never)] // this function call can be skipped it when tracing.
-pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
- let mut cx = Context { idx: 0, frames };
- let result_unwind = unsafe {
- uw::_Unwind_Backtrace(trace_fn, &mut cx as *mut Context<'_> as *mut libc::c_void)
- };
- // See libunwind:src/unwind/Backtrace.c for the return values.
- // No, there is no doc.
- let res = match result_unwind {
- // These return codes seem to be benign and need to be ignored for backtraces
- // to show up properly on all tested platforms.
- uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
- Ok((cx.idx, BacktraceContext))
- }
- _ => Err(io::Error::new(
- io::ErrorKind::Other,
- UnwindError(result_unwind),
- )),
- };
- res
-}
-
-extern "C" fn trace_fn(
- ctx: *mut uw::_Unwind_Context,
- arg: *mut libc::c_void,
-) -> uw::_Unwind_Reason_Code {
- let cx = unsafe { &mut *(arg as *mut Context<'_>) };
- if cx.idx >= cx.frames.len() {
- return uw::_URC_NORMAL_STOP;
- }
-
- let mut ip_before_insn = 0;
- let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void };
- if !ip.is_null() && ip_before_insn == 0 {
- // this is a non-signaling frame, so `ip` refers to the address
- // after the calling instruction. account for that.
- ip = (ip as usize - 1) as *mut _;
- }
-
- let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) };
- cx.frames[cx.idx] = Frame {
- symbol_addr: symaddr as *mut u8,
- exact_position: ip as *mut u8,
- inline_context: 0,
- };
- cx.idx += 1;
-
- uw::_URC_NO_REASON
-}
-
-// To reduce TCB size in Sgx enclave, we do not want to implement resolve_symname functionality.
-// Rather, we print the offset of the address here, which could be later mapped to correct function.
-pub fn resolve_symname<F>(frame: Frame,
- callback: F,
- _: &BacktraceContext) -> io::Result<()>
- where F: FnOnce(Option<&str>) -> io::Result<()>
-{
- callback(Some(&format!("0x{:x}",
- (frame.symbol_addr.wrapping_offset_from(image_base() as _)))))
-}
-
-pub fn foreach_symbol_fileline<F>(_: Frame,
- _: F,
- _: &BacktraceContext) -> io::Result<bool>
- where F: FnMut(&[u8], u32) -> io::Result<()>
-{
- Ok(false)
-}
pub mod alloc;
pub mod args;
-#[cfg(feature = "backtrace")]
-pub mod backtrace;
pub mod cmath;
pub mod condvar;
pub mod env;
+++ /dev/null
-/// Backtrace support built on libgcc with some extra OS-specific support
-///
-/// Some methods of getting a backtrace:
-///
-/// * The backtrace() functions on unix. It turns out this doesn't work very
-/// well for green threads on macOS, and the address to symbol portion of it
-/// suffers problems that are described below.
-///
-/// * Using libunwind. This is more difficult than it sounds because libunwind
-/// isn't installed everywhere by default. It's also a bit of a hefty library,
-/// so possibly not the best option. When testing, libunwind was excellent at
-/// getting both accurate backtraces and accurate symbols across platforms.
-/// This route was not chosen in favor of the next option, however.
-///
-/// * We're already using libgcc_s for exceptions in rust (triggering thread
-/// unwinding and running destructors on the stack), and it turns out that it
-/// conveniently comes with a function that also gives us a backtrace. All of
-/// these functions look like _Unwind_*, but it's not quite the full
-/// repertoire of the libunwind API. Due to it already being in use, this was
-/// the chosen route of getting a backtrace.
-///
-/// After choosing libgcc_s for backtraces, the sad part is that it will only
-/// give us a stack trace of instruction pointers. Thankfully these instruction
-/// pointers are accurate (they work for green and native threads), but it's
-/// then up to us again to figure out how to translate these addresses to
-/// symbols. As with before, we have a few options. Before, that, a little bit
-/// of an interlude about symbols. This is my very limited knowledge about
-/// symbol tables, and this information is likely slightly wrong, but the
-/// general idea should be correct.
-///
-/// When talking about symbols, it's helpful to know a few things about where
-/// symbols are located. Some symbols are located in the dynamic symbol table
-/// of the executable which in theory means that they're available for dynamic
-/// linking and lookup. Other symbols end up only in the local symbol table of
-/// the file. This loosely corresponds to pub and priv functions in Rust.
-///
-/// Armed with this knowledge, we know that our solution for address to symbol
-/// translation will need to consult both the local and dynamic symbol tables.
-/// With that in mind, here's our options of translating an address to
-/// a symbol.
-///
-/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr()
-/// behind the scenes to translate, and this is why backtrace() was not used.
-/// Conveniently, this method works fantastically on macOS. It appears dladdr()
-/// uses magic to consult the local symbol table, or we're putting everything
-/// in the dynamic symbol table anyway. Regardless, for macOS, this is the
-/// method used for translation. It's provided by the system and easy to do.o
-///
-/// Sadly, all other systems have a dladdr() implementation that does not
-/// consult the local symbol table. This means that most functions are blank
-/// because they don't have symbols. This means that we need another solution.
-///
-/// * Use unw_get_proc_name(). This is part of the libunwind api (not the
-/// libgcc_s version of the libunwind api), but involves taking a dependency
-/// to libunwind. We may pursue this route in the future if we bundle
-/// libunwind, but libunwind was unwieldy enough that it was not chosen at
-/// this time to provide this functionality.
-///
-/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a
-/// semi-reasonable solution. The stdlib already knows how to spawn processes,
-/// so in theory it could invoke readelf, parse the output, and consult the
-/// local/dynamic symbol tables from there. This ended up not getting chosen
-/// due to the craziness of the idea plus the advent of the next option.
-///
-/// * Use `libbacktrace`. It turns out that this is a small library bundled in
-/// the gcc repository which provides backtrace and symbol translation
-/// functionality. All we really need from it is the backtrace functionality,
-/// and we only really need this on everything that's not macOS, so this is the
-/// chosen route for now.
-///
-/// In summary, the current situation uses libgcc_s to get a trace of stack
-/// pointers, and we use dladdr() or libbacktrace to translate these addresses
-/// to symbols. This is a bit of a hokey implementation as-is, but it works for
-/// all unix platforms we support right now, so it at least gets the job done.
-
-pub use self::tracing::unwind_backtrace;
-pub use self::printing::{foreach_symbol_fileline, resolve_symname};
-
-// tracing impls:
-mod tracing;
-// symbol resolvers:
-mod printing;
-
-#[cfg(not(target_os = "emscripten"))]
-pub mod gnu {
- use crate::io;
- use crate::fs;
-
- use libc::c_char;
-
- #[cfg(not(any(target_os = "macos", target_os = "ios")))]
- pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
- Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
- }
-
- #[cfg(any(target_os = "macos", target_os = "ios"))]
- pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
- use crate::env;
- use crate::os::unix::ffi::OsStrExt;
-
- let filename = env::current_exe()?;
- let file = fs::File::open(&filename)?;
- let mut filename_cstr: Vec<_> = filename.as_os_str().as_bytes().iter()
- .map(|&x| x as c_char).collect();
- filename_cstr.push(0); // Null terminate
- Ok((filename_cstr, file))
- }
-}
-
-pub struct BacktraceContext;
+++ /dev/null
-use crate::io;
-use crate::intrinsics;
-use crate::ffi::CStr;
-use crate::sys::backtrace::BacktraceContext;
-use crate::sys_common::backtrace::Frame;
-
-pub fn resolve_symname<F>(frame: Frame,
- callback: F,
- _: &BacktraceContext) -> io::Result<()>
- where F: FnOnce(Option<&str>) -> io::Result<()>
-{
- unsafe {
- let mut info: Dl_info = intrinsics::init();
- let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 ||
- info.dli_sname.is_null() {
- None
- } else {
- CStr::from_ptr(info.dli_sname).to_str().ok()
- };
- callback(symname)
- }
-}
-
-#[repr(C)]
-struct Dl_info {
- dli_fname: *const libc::c_char,
- dli_fbase: *mut libc::c_void,
- dli_sname: *const libc::c_char,
- dli_saddr: *mut libc::c_void,
-}
-
-extern {
- fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int;
-}
+++ /dev/null
-mod dladdr;
-
-use crate::sys::backtrace::BacktraceContext;
-use crate::sys_common::backtrace::Frame;
-use crate::io;
-
-#[cfg(target_os = "emscripten")]
-pub use self::dladdr::resolve_symname;
-
-#[cfg(target_os = "emscripten")]
-pub fn foreach_symbol_fileline<F>(_: Frame, _: F, _: &BacktraceContext) -> io::Result<bool>
-where
- F: FnMut(&[u8], u32) -> io::Result<()>
-{
- Ok(false)
-}
-
-#[cfg(not(target_os = "emscripten"))]
-pub use crate::sys_common::gnu::libbacktrace::foreach_symbol_fileline;
-
-#[cfg(not(target_os = "emscripten"))]
-pub fn resolve_symname<F>(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()>
-where
- F: FnOnce(Option<&str>) -> io::Result<()>
-{
- crate::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| {
- if symname.is_some() {
- callback(symname)
- } else {
- dladdr::resolve_symname(frame, callback, bc)
- }
- }, bc)
-}
+++ /dev/null
-/// As always - iOS on arm uses SjLj exceptions and
-/// _Unwind_Backtrace is even not available there. Still,
-/// backtraces could be extracted using a backtrace function,
-/// which thanks god is public
-///
-/// As mentioned in a huge comment block in `super::super`, backtrace
-/// doesn't play well with green threads, so while it is extremely nice and
-/// simple to use it should be used only on iOS devices as the only viable
-/// option.
-
-use crate::io;
-use crate::ptr;
-use crate::sys::backtrace::BacktraceContext;
-use crate::sys_common::backtrace::Frame;
-
-#[inline(never)] // if we know this is a function call, we can skip it when
- // tracing
-pub fn unwind_backtrace(frames: &mut [Frame])
- -> io::Result<(usize, BacktraceContext)>
-{
- const FRAME_LEN: usize = 100;
- assert!(FRAME_LEN >= frames.len());
- let mut raw_frames = [ptr::null_mut(); FRAME_LEN];
- let nb_frames = unsafe {
- backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int)
- } as usize;
- for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) {
- *to = Frame {
- exact_position: *from as *mut u8,
- symbol_addr: *from as *mut u8,
- inline_context: 0,
- };
- }
- Ok((nb_frames as usize, BacktraceContext))
-}
-
-extern {
- fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int;
-}
+++ /dev/null
-use crate::error::Error;
-use crate::fmt;
-use crate::io;
-use crate::sys::backtrace::BacktraceContext;
-use crate::sys_common::backtrace::Frame;
-
-use unwind as uw;
-
-struct Context<'a> {
- idx: usize,
- frames: &'a mut [Frame],
-}
-
-#[derive(Debug)]
-struct UnwindError(uw::_Unwind_Reason_Code);
-
-impl Error for UnwindError {
- fn description(&self) -> &'static str {
- "unexpected return value while unwinding"
- }
-}
-
-impl fmt::Display for UnwindError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}: {:?}", self.description(), self.0)
- }
-}
-
-#[inline(never)] // if we know this is a function call, we can skip it when
- // tracing
-pub fn unwind_backtrace(frames: &mut [Frame])
- -> io::Result<(usize, BacktraceContext)>
-{
- let mut cx = Context {
- idx: 0,
- frames,
- };
- let result_unwind = unsafe {
- uw::_Unwind_Backtrace(trace_fn,
- &mut cx as *mut Context<'_>
- as *mut libc::c_void)
- };
- // See libunwind:src/unwind/Backtrace.c for the return values.
- // No, there is no doc.
- match result_unwind {
- // These return codes seem to be benign and need to be ignored for backtraces
- // to show up properly on all tested platforms.
- uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
- Ok((cx.idx, BacktraceContext))
- }
- _ => {
- Err(io::Error::new(io::ErrorKind::Other,
- UnwindError(result_unwind)))
- }
- }
-}
-
-extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
- arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
- let cx = unsafe { &mut *(arg as *mut Context<'_>) };
- if cx.idx >= cx.frames.len() {
- return uw::_URC_NORMAL_STOP;
- }
-
- let mut ip_before_insn = 0;
- let mut ip = unsafe {
- uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
- };
- if !ip.is_null() && ip_before_insn == 0 {
- // this is a non-signaling frame, so `ip` refers to the address
- // after the calling instruction. account for that.
- ip = (ip as usize - 1) as *mut _;
- }
-
- // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
- // it appears to work fine without it, so we only use
- // FindEnclosingFunction on non-osx platforms. In doing so, we get a
- // slightly more accurate stack trace in the process.
- //
- // This is often because panic involves the last instruction of a
- // function being "call std::rt::begin_unwind", with no ret
- // instructions after it. This means that the return instruction
- // pointer points *outside* of the calling function, and by
- // unwinding it we go back to the original function.
- let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
- ip
- } else {
- unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
- };
-
- cx.frames[cx.idx] = Frame {
- symbol_addr: symaddr as *mut u8,
- exact_position: ip as *mut u8,
- inline_context: 0,
- };
- cx.idx += 1;
-
- uw::_URC_NO_REASON
-}
+++ /dev/null
-pub use self::imp::*;
-
-#[cfg(not(all(target_os = "ios", target_arch = "arm")))]
-#[path = "gcc_s.rs"]
-mod imp;
-#[cfg(all(target_os = "ios", target_arch = "arm"))]
-#[path = "backtrace_fn.rs"]
-mod imp;
pub mod alloc;
pub mod args;
pub mod android;
-#[cfg(feature = "backtrace")]
-pub mod backtrace;
pub mod cmath;
pub mod condvar;
pub mod env;
+++ /dev/null
-use crate::io;
-use crate::sys::unsupported;
-use crate::sys_common::backtrace::Frame;
-
-pub struct BacktraceContext;
-
-pub fn unwind_backtrace(_frames: &mut [Frame])
- -> io::Result<(usize, BacktraceContext)>
-{
- unsupported()
-}
-
-pub fn resolve_symname<F>(_frame: Frame,
- _callback: F,
- _: &BacktraceContext) -> io::Result<()>
- where F: FnOnce(Option<&str>) -> io::Result<()>
-{
- unsupported()
-}
-
-pub fn foreach_symbol_fileline<F>(_: Frame,
- _: F,
- _: &BacktraceContext) -> io::Result<bool>
- where F: FnMut(&[u8], u32) -> io::Result<()>
-{
- unsupported()
-}
pub mod alloc;
pub mod args;
-#[cfg(feature = "backtrace")]
-pub mod backtrace;
#[path = "../wasm/cmath.rs"]
pub mod cmath;
#[path = "../wasm/condvar.rs"]
+++ /dev/null
-use crate::io;
-use crate::sys::unsupported;
-use crate::sys_common::backtrace::Frame;
-
-pub struct BacktraceContext;
-
-pub fn unwind_backtrace(_frames: &mut [Frame])
- -> io::Result<(usize, BacktraceContext)>
-{
- unsupported()
-}
-
-pub fn resolve_symname<F>(_frame: Frame,
- _callback: F,
- _: &BacktraceContext) -> io::Result<()>
- where F: FnOnce(Option<&str>) -> io::Result<()>
-{
- unsupported()
-}
-
-pub fn foreach_symbol_fileline<F>(_: Frame,
- _: F,
- _: &BacktraceContext) -> io::Result<bool>
- where F: FnMut(&[u8], u32) -> io::Result<()>
-{
- unsupported()
-}
pub mod alloc;
pub mod args;
-#[cfg(feature = "backtrace")]
-pub mod backtrace;
pub mod cmath;
pub mod env;
pub mod fs;
+++ /dev/null
-use crate::io;
-use crate::sys::c;
-use crate::path::PathBuf;
-use crate::fs::{OpenOptions, File};
-use crate::sys::ext::fs::OpenOptionsExt;
-use crate::sys::handle::Handle;
-
-use libc::c_char;
-use super::super::{fill_utf16_buf, os2path, to_u16s, wide_char_to_multi_byte};
-
-fn query_full_process_image_name() -> io::Result<PathBuf> {
- unsafe {
- let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION,
- c::FALSE,
- c::GetCurrentProcessId()));
- fill_utf16_buf(|buf, mut sz| {
- if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 {
- 0
- } else {
- sz
- }
- }, os2path)
- }
-}
-
-fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> {
- // We query the current image name, open the file without FILE_SHARE_DELETE so it
- // can't be moved and then get the current image name again. If the names are the
- // same than we have successfully locked the file
- let image_name1 = query_full_process_image_name()?;
- let file = OpenOptions::new()
- .read(true)
- .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE)
- .open(&image_name1)?;
- let image_name2 = query_full_process_image_name()?;
-
- if image_name1 != image_name2 {
- return Err(io::Error::new(io::ErrorKind::Other,
- "executable moved while trying to lock it"));
- }
-
- Ok((image_name1, file))
-}
-
-// Get the executable filename for libbacktrace
-// This returns the path in the ANSI code page and a File which should remain open
-// for as long as the path should remain valid
-pub fn get_executable_filename() -> io::Result<(Vec<c_char>, File)> {
- let (executable, file) = lock_and_get_executable_filename()?;
- let u16_executable = to_u16s(executable.into_os_string())?;
- Ok((wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS,
- &u16_executable, true)?, file))
-}
+++ /dev/null
-//! As always, windows has something very different than unix, we mainly want
-//! to avoid having to depend too much on libunwind for windows.
-//!
-//! If you google around, you'll find a fair bit of references to built-in
-//! functions to get backtraces on windows. It turns out that most of these are
-//! in an external library called dbghelp. I was unable to find this library
-//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
-//! of it.
-//!
-//! You'll also find that there's a function called CaptureStackBackTrace
-//! mentioned frequently (which is also easy to use), but sadly I didn't have a
-//! copy of that function in my mingw install (maybe it was broken?). Instead,
-//! this takes the route of using StackWalk64 in order to walk the stack.
-
-#![allow(deprecated)] // dynamic_lib
-
-use crate::io;
-use crate::mem;
-use crate::ptr;
-use crate::sys::c;
-use crate::sys::dynamic_lib::DynamicLibrary;
-use crate::sys_common::backtrace::Frame;
-
-use libc::c_void;
-
-macro_rules! sym {
- ($lib:expr, $e:expr, $t:ident) => (
- $lib.symbol($e).map(|f| unsafe {
- $crate::mem::transmute::<usize, $t>(f)
- })
- )
-}
-
-mod printing;
-
-#[cfg(target_env = "gnu")]
-#[path = "backtrace_gnu.rs"]
-pub mod gnu;
-
-pub use self::printing::{foreach_symbol_fileline, resolve_symname};
-use self::printing::{load_printing_fns_64, load_printing_fns_ex};
-
-pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
- let dbghelp = DynamicLibrary::open("dbghelp.dll")?;
-
- // Fetch the symbols necessary from dbghelp.dll
- let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
- let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;
-
- // StackWalkEx might not be present and we'll fall back to StackWalk64
- let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) {
- Ok(StackWalkEx) => {
- StackWalkVariant::StackWalkEx(StackWalkEx, load_printing_fns_ex(&dbghelp)?)
- }
- Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) {
- Ok(StackWalk64) => {
- StackWalkVariant::StackWalk64(StackWalk64, load_printing_fns_64(&dbghelp)?)
- }
- Err(..) => return Err(e),
- },
- };
-
- // Allocate necessary structures for doing the stack walk
- let process = unsafe { c::GetCurrentProcess() };
-
- let backtrace_context = BacktraceContext {
- handle: process,
- SymCleanup,
- StackWalkVariant: sw_var,
- dbghelp,
- };
-
- // Initialize this process's symbols
- let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) };
- if ret != c::TRUE {
- return Ok((0, backtrace_context));
- }
-
- // And now that we're done with all the setup, do the stack walking!
- match backtrace_context.StackWalkVariant {
- StackWalkVariant::StackWalkEx(StackWalkEx, _) => {
- set_frames(StackWalkEx, frames).map(|i| (i, backtrace_context))
- }
-
- StackWalkVariant::StackWalk64(StackWalk64, _) => {
- set_frames(StackWalk64, frames).map(|i| (i, backtrace_context))
- }
- }
-}
-
-fn set_frames<W: StackWalker>(StackWalk: W, frames: &mut [Frame]) -> io::Result<usize> {
- let process = unsafe { c::GetCurrentProcess() };
- let thread = unsafe { c::GetCurrentProcess() };
- let mut context: c::CONTEXT = unsafe { mem::zeroed() };
- unsafe { c::RtlCaptureContext(&mut context) };
- let mut frame = W::Item::new();
- let image = frame.init(&context);
-
- let mut i = 0;
- while i < frames.len()
- && StackWalk.walk(image, process, thread, &mut frame, &mut context) == c::TRUE
- {
- let addr = frame.get_addr();
- frames[i] = Frame {
- symbol_addr: addr,
- exact_position: addr,
- inline_context: frame.get_inline_context(),
- };
-
- i += 1
- }
- Ok(i)
-}
-
-type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL;
-type SymCleanupFn = unsafe extern "system" fn(c::HANDLE) -> c::BOOL;
-
-type StackWalkExFn = unsafe extern "system" fn(
- c::DWORD,
- c::HANDLE,
- c::HANDLE,
- *mut c::STACKFRAME_EX,
- *mut c::CONTEXT,
- *mut c_void,
- *mut c_void,
- *mut c_void,
- *mut c_void,
- c::DWORD,
-) -> c::BOOL;
-
-type StackWalk64Fn = unsafe extern "system" fn(
- c::DWORD,
- c::HANDLE,
- c::HANDLE,
- *mut c::STACKFRAME64,
- *mut c::CONTEXT,
- *mut c_void,
- *mut c_void,
- *mut c_void,
- *mut c_void,
-) -> c::BOOL;
-
-trait StackWalker {
- type Item: StackFrame;
-
- fn walk(
- &self,
- _: c::DWORD,
- _: c::HANDLE,
- _: c::HANDLE,
- _: &mut Self::Item,
- _: &mut c::CONTEXT
- ) -> c::BOOL;
-}
-
-impl StackWalker for StackWalkExFn {
- type Item = c::STACKFRAME_EX;
- fn walk(
- &self,
- image: c::DWORD,
- process: c::HANDLE,
- thread: c::HANDLE,
- frame: &mut Self::Item,
- context: &mut c::CONTEXT,
- ) -> c::BOOL {
- unsafe {
- self(
- image,
- process,
- thread,
- frame,
- context,
- ptr::null_mut(),
- ptr::null_mut(),
- ptr::null_mut(),
- ptr::null_mut(),
- 0,
- )
- }
- }
-}
-
-impl StackWalker for StackWalk64Fn {
- type Item = c::STACKFRAME64;
- fn walk(
- &self,
- image: c::DWORD,
- process: c::HANDLE,
- thread: c::HANDLE,
- frame: &mut Self::Item,
- context: &mut c::CONTEXT,
- ) -> c::BOOL {
- unsafe {
- self(
- image,
- process,
- thread,
- frame,
- context,
- ptr::null_mut(),
- ptr::null_mut(),
- ptr::null_mut(),
- ptr::null_mut(),
- )
- }
- }
-}
-
-trait StackFrame {
- fn new() -> Self;
- fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD;
- fn get_addr(&self) -> *const u8;
- fn get_inline_context(&self) -> u32;
-}
-
-impl StackFrame for c::STACKFRAME_EX {
- fn new() -> c::STACKFRAME_EX {
- unsafe { mem::zeroed() }
- }
-
- #[cfg(target_arch = "x86")]
- fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
- self.AddrPC.Offset = ctx.Eip as u64;
- self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
- self.AddrStack.Offset = ctx.Esp as u64;
- self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
- self.AddrFrame.Offset = ctx.Ebp as u64;
- 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;
- self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
- self.AddrStack.Offset = ctx.Rsp as u64;
- self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
- self.AddrFrame.Offset = ctx.Rbp as u64;
- self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
- c::IMAGE_FILE_MACHINE_AMD64
- }
-
- #[cfg(target_arch = "arm")]
- 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.R11 as u64;
- self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
- c::IMAGE_FILE_MACHINE_ARMNT
- }
-
- #[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
- }
-
- fn get_inline_context(&self) -> u32 {
- self.InlineFrameContext
- }
-}
-
-impl StackFrame for c::STACKFRAME64 {
- fn new() -> c::STACKFRAME64 {
- unsafe { mem::zeroed() }
- }
-
- #[cfg(target_arch = "x86")]
- fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
- self.AddrPC.Offset = ctx.Eip as u64;
- self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
- self.AddrStack.Offset = ctx.Esp as u64;
- self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
- self.AddrFrame.Offset = ctx.Ebp as u64;
- 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;
- self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
- self.AddrStack.Offset = ctx.Rsp as u64;
- self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
- self.AddrFrame.Offset = ctx.Rbp as u64;
- self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
- c::IMAGE_FILE_MACHINE_AMD64
- }
-
- #[cfg(target_arch = "arm")]
- 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.R11 as u64;
- self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
- c::IMAGE_FILE_MACHINE_ARMNT
- }
-
- #[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
- }
-
- fn get_inline_context(&self) -> u32 {
- 0
- }
-}
-
-enum StackWalkVariant {
- StackWalkEx(StackWalkExFn, printing::PrintingFnsEx),
- StackWalk64(StackWalk64Fn, printing::PrintingFns64),
-}
-
-pub struct BacktraceContext {
- handle: c::HANDLE,
- SymCleanup: SymCleanupFn,
- // Only used in printing for msvc and not gnu
- // The gnu version is effectively a ZST dummy.
- #[allow(dead_code)]
- StackWalkVariant: StackWalkVariant,
- // keeping DynamycLibrary loaded until its functions no longer needed
- #[allow(dead_code)]
- dbghelp: DynamicLibrary,
-}
-
-impl Drop for BacktraceContext {
- fn drop(&mut self) {
- unsafe {
- (self.SymCleanup)(self.handle);
- }
- }
-}
+++ /dev/null
-#[cfg(target_env = "msvc")]
-#[path = "msvc.rs"]
-mod printing;
-
-#[cfg(target_env = "gnu")]
-mod printing {
- pub use crate::sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
-
- // dummy functions to mirror those present in msvc version.
- use crate::sys::dynamic_lib::DynamicLibrary;
- use crate::io;
- pub struct PrintingFnsEx {}
- pub struct PrintingFns64 {}
- pub fn load_printing_fns_ex(_: &DynamicLibrary) -> io::Result<PrintingFnsEx> {
- Ok(PrintingFnsEx{})
- }
- pub fn load_printing_fns_64(_: &DynamicLibrary) -> io::Result<PrintingFns64> {
- Ok(PrintingFns64{})
- }
-}
-
-pub use self::printing::{foreach_symbol_fileline, resolve_symname};
-pub use self::printing::{load_printing_fns_ex, load_printing_fns_64,
- PrintingFnsEx, PrintingFns64};
+++ /dev/null
-use crate::ffi::CStr;
-use crate::io;
-use crate::mem;
-use crate::sys::backtrace::BacktraceContext;
-use crate::sys::backtrace::StackWalkVariant;
-use crate::sys::c;
-use crate::sys::dynamic_lib::DynamicLibrary;
-use crate::sys_common::backtrace::Frame;
-
-use libc::{c_char, c_ulong};
-
-// Structs holding printing functions and loaders for them
-// Two versions depending on whether dbghelp.dll has StackWalkEx or not
-// (the former being in newer Windows versions, the older being in Win7 and before)
-pub struct PrintingFnsEx {
- resolve_symname: SymFromInlineContextFn,
- sym_get_line: SymGetLineFromInlineContextFn,
-}
-pub struct PrintingFns64 {
- resolve_symname: SymFromAddrFn,
- sym_get_line: SymGetLineFromAddr64Fn,
-}
-
-pub fn load_printing_fns_ex(dbghelp: &DynamicLibrary) -> io::Result<PrintingFnsEx> {
- Ok(PrintingFnsEx {
- resolve_symname: sym!(dbghelp, "SymFromInlineContext", SymFromInlineContextFn)?,
- sym_get_line: sym!(
- dbghelp,
- "SymGetLineFromInlineContext",
- SymGetLineFromInlineContextFn
- )?,
- })
-}
-pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result<PrintingFns64> {
- Ok(PrintingFns64 {
- resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?,
- sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn)?,
- })
-}
-
-type SymFromAddrFn =
- unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
-type SymFromInlineContextFn =
- unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
-
-type SymGetLineFromAddr64Fn =
- unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL;
-type SymGetLineFromInlineContextFn = unsafe extern "system" fn(
- c::HANDLE,
- u64,
- c::ULONG,
- u64,
- *mut c::DWORD,
- *mut c::IMAGEHLP_LINE64,
-) -> c::BOOL;
-
-/// Converts a pointer to symbol to its string value.
-pub fn resolve_symname<F>(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()>
-where
- F: FnOnce(Option<&str>) -> io::Result<()>,
-{
- match context.StackWalkVariant {
- StackWalkVariant::StackWalkEx(_, ref fns) => resolve_symname_internal(
- |process: c::HANDLE,
- symbol_address: u64,
- inline_context: c::ULONG,
- info: *mut c::SYMBOL_INFO| unsafe {
- let mut displacement = 0u64;
- (fns.resolve_symname)(
- process,
- symbol_address,
- inline_context,
- &mut displacement,
- info,
- )
- },
- frame,
- callback,
- context,
- ),
- StackWalkVariant::StackWalk64(_, ref fns) => resolve_symname_internal(
- |process: c::HANDLE,
- symbol_address: u64,
- _inline_context: c::ULONG,
- info: *mut c::SYMBOL_INFO| unsafe {
- let mut displacement = 0u64;
- (fns.resolve_symname)(process, symbol_address, &mut displacement, info)
- },
- frame,
- callback,
- context,
- ),
- }
-}
-
-fn resolve_symname_internal<F, R>(
- mut symbol_resolver: R,
- frame: Frame,
- callback: F,
- context: &BacktraceContext,
-) -> io::Result<()>
-where
- F: FnOnce(Option<&str>) -> io::Result<()>,
- R: FnMut(c::HANDLE, u64, c::ULONG, *mut c::SYMBOL_INFO) -> c::BOOL,
-{
- unsafe {
- let mut info: c::SYMBOL_INFO = mem::zeroed();
- info.MaxNameLen = c::MAX_SYM_NAME as c_ulong;
- // the struct size in C. the value is different to
- // `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81)
- // due to struct alignment.
- info.SizeOfStruct = 88;
-
- let ret = symbol_resolver(
- context.handle,
- frame.symbol_addr as u64,
- frame.inline_context,
- &mut info,
- );
- let valid_range = if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize {
- if info.Size != 0 {
- (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize
- } else {
- true
- }
- } else {
- false
- };
- let symname = if valid_range {
- let ptr = info.Name.as_ptr() as *const c_char;
- CStr::from_ptr(ptr).to_str().ok()
- } else {
- None
- };
- callback(symname)
- }
-}
-
-pub fn foreach_symbol_fileline<F>(
- frame: Frame,
- callback: F,
- context: &BacktraceContext,
-) -> io::Result<bool>
-where
- F: FnMut(&[u8], u32) -> io::Result<()>,
-{
- match context.StackWalkVariant {
- StackWalkVariant::StackWalkEx(_, ref fns) => foreach_symbol_fileline_iternal(
- |process: c::HANDLE,
- frame_address: u64,
- inline_context: c::ULONG,
- line: *mut c::IMAGEHLP_LINE64| unsafe {
- let mut displacement = 0u32;
- (fns.sym_get_line)(
- process,
- frame_address,
- inline_context,
- 0,
- &mut displacement,
- line,
- )
- },
- frame,
- callback,
- context,
- ),
- StackWalkVariant::StackWalk64(_, ref fns) => foreach_symbol_fileline_iternal(
- |process: c::HANDLE,
- frame_address: u64,
- _inline_context: c::ULONG,
- line: *mut c::IMAGEHLP_LINE64| unsafe {
- let mut displacement = 0u32;
- (fns.sym_get_line)(process, frame_address, &mut displacement, line)
- },
- frame,
- callback,
- context,
- ),
- }
-}
-
-fn foreach_symbol_fileline_iternal<F, G>(
- mut line_getter: G,
- frame: Frame,
- mut callback: F,
- context: &BacktraceContext,
-) -> io::Result<bool>
-where
- F: FnMut(&[u8], u32) -> io::Result<()>,
- G: FnMut(c::HANDLE, u64, c::ULONG, *mut c::IMAGEHLP_LINE64) -> c::BOOL,
-{
- unsafe {
- let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
- line.SizeOfStruct = mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
-
- let ret = line_getter(
- context.handle,
- frame.exact_position as u64,
- frame.inline_context,
- &mut line,
- );
- if ret == c::TRUE {
- let name = CStr::from_ptr(line.Filename).to_bytes();
- callback(name, line.LineNumber as u32)?;
- }
- Ok(false)
- }
-}
#![unstable(issue = "0", feature = "windows_c")]
use crate::os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort, c_char};
-#[cfg(target_arch = "x86_64")]
-use crate::os::raw::c_ulonglong;
use crate::ptr;
use libc::{wchar_t, size_t, c_void};
pub type CHAR = c_char;
pub type ULONG_PTR = usize;
pub type ULONG = c_ulong;
-#[cfg(target_arch = "x86_64")]
-pub type ULONGLONG = u64;
-#[cfg(target_arch = "x86_64")]
-pub type DWORDLONG = ULONGLONG;
pub type LPBOOL = *mut BOOL;
pub type LPBYTE = *mut BYTE;
pub const FIONBIO: c_ulong = 0x8004667e;
-#[cfg(target_arch = "arm")]
-const ARM_MAX_BREAKPOINTS: usize = 8;
-#[cfg(target_arch = "arm")]
-const ARM_MAX_WATCHPOINTS: usize = 1;
-
#[repr(C)]
#[derive(Copy)]
pub struct WIN32_FIND_DATAW {
pub const WAIT_TIMEOUT: DWORD = 258;
pub const WAIT_FAILED: DWORD = 0xFFFFFFFF;
-#[cfg(target_env = "msvc")]
-#[cfg(feature = "backtrace")]
-pub const MAX_SYM_NAME: usize = 2000;
-#[cfg(target_arch = "x86")]
-#[cfg(feature = "backtrace")]
-pub const IMAGE_FILE_MACHINE_I386: DWORD = 0x014c;
-#[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;
-#[cfg(target_arch = "arm")]
-#[cfg(feature = "backtrace")]
-pub const IMAGE_FILE_MACHINE_ARMNT: DWORD = 0x01c4;
-
pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
pub hEvent: HANDLE,
}
-#[repr(C)]
-#[cfg(target_env = "msvc")]
-#[cfg(feature = "backtrace")]
-pub struct SYMBOL_INFO {
- pub SizeOfStruct: c_ulong,
- pub TypeIndex: c_ulong,
- pub Reserved: [u64; 2],
- pub Index: c_ulong,
- pub Size: c_ulong,
- pub ModBase: u64,
- pub Flags: c_ulong,
- pub Value: u64,
- pub Address: u64,
- pub Register: c_ulong,
- pub Scope: c_ulong,
- pub Tag: c_ulong,
- pub NameLen: c_ulong,
- pub MaxNameLen: c_ulong,
- // note that windows has this as 1, but it basically just means that
- // the name is inline at the end of the struct. For us, we just bump
- // the struct size up to MAX_SYM_NAME.
- pub Name: [c_char; MAX_SYM_NAME],
-}
-
-#[repr(C)]
-#[cfg(target_env = "msvc")]
-#[cfg(feature = "backtrace")]
-pub struct IMAGEHLP_LINE64 {
- pub SizeOfStruct: u32,
- pub Key: *const c_void,
- pub LineNumber: u32,
- pub Filename: *const c_char,
- pub Address: u64,
-}
-
#[repr(C)]
#[allow(dead_code)] // we only use some variants
pub enum ADDRESS_MODE {
AddrModeFlat,
}
-#[repr(C)]
-#[cfg(feature = "backtrace")]
-pub struct ADDRESS64 {
- pub Offset: u64,
- pub Segment: u16,
- pub Mode: ADDRESS_MODE,
-}
-
-#[repr(C)]
-#[cfg(feature = "backtrace")]
-pub struct STACKFRAME_EX {
- pub AddrPC: ADDRESS64,
- pub AddrReturn: ADDRESS64,
- pub AddrFrame: ADDRESS64,
- pub AddrStack: ADDRESS64,
- pub AddrBStore: ADDRESS64,
- pub FuncTableEntry: *mut c_void,
- pub Params: [u64; 4],
- pub Far: BOOL,
- pub Virtual: BOOL,
- pub Reserved: [u64; 3],
- pub KdHelp: KDHELP64,
- pub StackFrameSize: DWORD,
- pub InlineFrameContext: DWORD,
-}
-
-#[repr(C)]
-#[cfg(feature = "backtrace")]
-pub struct STACKFRAME64 {
- pub AddrPC: ADDRESS64,
- pub AddrReturn: ADDRESS64,
- pub AddrFrame: ADDRESS64,
- pub AddrStack: ADDRESS64,
- pub AddrBStore: ADDRESS64,
- pub FuncTableEntry: *mut c_void,
- pub Params: [u64; 4],
- pub Far: BOOL,
- pub Virtual: BOOL,
- pub Reserved: [u64; 3],
- pub KdHelp: KDHELP64,
-}
-
-#[repr(C)]
-#[cfg(feature = "backtrace")]
-pub struct KDHELP64 {
- pub Thread: u64,
- pub ThCallbackStack: DWORD,
- pub ThCallbackBStore: DWORD,
- pub NextCallback: DWORD,
- pub FramePointer: DWORD,
- pub KiCallUserMode: u64,
- pub KeUserCallbackDispatcher: u64,
- pub SystemRangeStart: u64,
- pub KiUserExceptionDispatcher: u64,
- pub StackBase: u64,
- pub StackLimit: u64,
- pub Reserved: [u64; 5],
-}
-
-#[cfg(target_arch = "x86")]
-#[repr(C)]
-pub struct CONTEXT {
- pub ContextFlags: DWORD,
- pub Dr0: DWORD,
- pub Dr1: DWORD,
- pub Dr2: DWORD,
- pub Dr3: DWORD,
- pub Dr6: DWORD,
- pub Dr7: DWORD,
- pub FloatSave: FLOATING_SAVE_AREA,
- pub SegGs: DWORD,
- pub SegFs: DWORD,
- pub SegEs: DWORD,
- pub SegDs: DWORD,
- pub Edi: DWORD,
- pub Esi: DWORD,
- pub Ebx: DWORD,
- pub Edx: DWORD,
- pub Ecx: DWORD,
- pub Eax: DWORD,
- pub Ebp: DWORD,
- pub Eip: DWORD,
- pub SegCs: DWORD,
- pub EFlags: DWORD,
- pub Esp: DWORD,
- pub SegSs: DWORD,
- pub ExtendedRegisters: [u8; 512],
-}
-
-#[cfg(target_arch = "x86")]
-#[repr(C)]
-pub struct FLOATING_SAVE_AREA {
- pub ControlWord: DWORD,
- pub StatusWord: DWORD,
- pub TagWord: DWORD,
- pub ErrorOffset: DWORD,
- pub ErrorSelector: DWORD,
- pub DataOffset: DWORD,
- pub DataSelector: DWORD,
- pub RegisterArea: [u8; 80],
- pub Cr0NpxState: DWORD,
-}
-
-#[cfg(target_arch = "x86_64")]
-#[repr(C, align(16))]
-pub struct CONTEXT {
- pub P1Home: DWORDLONG,
- pub P2Home: DWORDLONG,
- pub P3Home: DWORDLONG,
- pub P4Home: DWORDLONG,
- pub P5Home: DWORDLONG,
- pub P6Home: DWORDLONG,
-
- pub ContextFlags: DWORD,
- pub MxCsr: DWORD,
-
- pub SegCs: WORD,
- pub SegDs: WORD,
- pub SegEs: WORD,
- pub SegFs: WORD,
- pub SegGs: WORD,
- pub SegSs: WORD,
- pub EFlags: DWORD,
-
- pub Dr0: DWORDLONG,
- pub Dr1: DWORDLONG,
- pub Dr2: DWORDLONG,
- pub Dr3: DWORDLONG,
- pub Dr6: DWORDLONG,
- pub Dr7: DWORDLONG,
-
- pub Rax: DWORDLONG,
- pub Rcx: DWORDLONG,
- pub Rdx: DWORDLONG,
- pub Rbx: DWORDLONG,
- pub Rsp: DWORDLONG,
- pub Rbp: DWORDLONG,
- pub Rsi: DWORDLONG,
- pub Rdi: DWORDLONG,
- pub R8: DWORDLONG,
- pub R9: DWORDLONG,
- pub R10: DWORDLONG,
- pub R11: DWORDLONG,
- pub R12: DWORDLONG,
- pub R13: DWORDLONG,
- pub R14: DWORDLONG,
- pub R15: DWORDLONG,
-
- pub Rip: DWORDLONG,
-
- pub FltSave: FLOATING_SAVE_AREA,
-
- pub VectorRegister: [M128A; 26],
- pub VectorControl: DWORDLONG,
-
- pub DebugControl: DWORDLONG,
- pub LastBranchToRip: DWORDLONG,
- pub LastBranchFromRip: DWORDLONG,
- pub LastExceptionToRip: DWORDLONG,
- pub LastExceptionFromRip: DWORDLONG,
-}
-
-#[cfg(target_arch = "x86_64")]
-#[repr(C, align(16))]
-pub struct M128A {
- pub Low: c_ulonglong,
- pub High: c_longlong
-}
-
-#[cfg(target_arch = "x86_64")]
-#[repr(C, align(16))]
-pub struct FLOATING_SAVE_AREA {
- _Dummy: [u8; 512] // FIXME: Fill this out
-}
-
-#[cfg(target_arch = "arm")]
-#[repr(C)]
-pub struct CONTEXT {
- pub ContextFlags: ULONG,
- pub R0: ULONG,
- pub R1: ULONG,
- pub R2: ULONG,
- pub R3: ULONG,
- pub R4: ULONG,
- pub R5: ULONG,
- pub R6: ULONG,
- pub R7: ULONG,
- pub R8: ULONG,
- pub R9: ULONG,
- pub R10: ULONG,
- pub R11: ULONG,
- pub R12: ULONG,
- pub Sp: ULONG,
- pub Lr: ULONG,
- pub Pc: ULONG,
- pub Cpsr: ULONG,
- pub Fpscr: ULONG,
- pub Padding: ULONG,
- pub D: [u64; 32],
- pub Bvr: [ULONG; ARM_MAX_BREAKPOINTS],
- pub Bcr: [ULONG; ARM_MAX_BREAKPOINTS],
- pub Wvr: [ULONG; ARM_MAX_WATCHPOINTS],
- pub Wcr: [ULONG; ARM_MAX_WATCHPOINTS],
- pub Padding2: [ULONG; 2]
-}
-
-// FIXME(#43348): This structure is used for backtrace only, and a fake
-// definition is provided here only to allow rustdoc to pass type-check. This
-// 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(rustdoc, not(any(target_arch = "x86_64", target_arch = "x86",
- target_arch = "aarch64", target_arch = "arm"))))]
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,
pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW)
-> BOOL;
pub fn FindClose(findFile: HANDLE) -> BOOL;
- #[cfg(feature = "backtrace")]
- pub fn RtlCaptureContext(ctx: *mut CONTEXT);
pub fn getsockopt(s: SOCKET,
level: c_int,
optname: c_int,
res: *mut *mut ADDRINFOA) -> c_int;
pub fn freeaddrinfo(res: *mut ADDRINFOA);
- #[cfg(feature = "backtrace")]
- pub fn LoadLibraryW(name: LPCWSTR) -> HMODULE;
- #[cfg(feature = "backtrace")]
- pub fn FreeLibrary(handle: HMODULE) -> BOOL;
pub fn GetProcAddress(handle: HMODULE,
name: LPCSTR) -> *mut c_void;
pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
panic!("rwlocks not available")
}
}
-
-#[cfg(all(target_env = "gnu", feature = "backtrace"))]
-mod gnu {
- use super::*;
-
- pub const PROCESS_QUERY_INFORMATION: DWORD = 0x0400;
-
- pub const CP_ACP: UINT = 0;
-
- pub const WC_NO_BEST_FIT_CHARS: DWORD = 0x00000400;
-
- extern "system" {
- pub fn OpenProcess(dwDesiredAccess: DWORD,
- bInheritHandle: BOOL,
- dwProcessId: DWORD) -> HANDLE;
- }
-
- compat_fn! {
- kernel32:
-
- pub fn QueryFullProcessImageNameW(_hProcess: HANDLE,
- _dwFlags: DWORD,
- _lpExeName: LPWSTR,
- _lpdwSize: LPDWORD) -> BOOL {
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
- }
- }
-}
-
-#[cfg(all(target_env = "gnu", feature = "backtrace"))]
-pub use self::gnu::*;
+++ /dev/null
-use crate::os::windows::prelude::*;
-
-use crate::ffi::{CString, OsStr};
-use crate::io;
-use crate::sys::c;
-
-pub struct DynamicLibrary {
- handle: c::HMODULE,
-}
-
-impl DynamicLibrary {
- pub fn open(filename: &str) -> io::Result<DynamicLibrary> {
- let filename = OsStr::new(filename)
- .encode_wide()
- .chain(Some(0))
- .collect::<Vec<_>>();
- let result = unsafe {
- c::LoadLibraryW(filename.as_ptr())
- };
- if result.is_null() {
- Err(io::Error::last_os_error())
- } else {
- Ok(DynamicLibrary { handle: result })
- }
- }
-
- pub fn symbol(&self, symbol: &str) -> io::Result<usize> {
- let symbol = CString::new(symbol)?;
- unsafe {
- match c::GetProcAddress(self.handle, symbol.as_ptr()) as usize {
- 0 => Err(io::Error::last_os_error()),
- n => Ok(n),
- }
- }
- }
-}
-
-impl Drop for DynamicLibrary {
- fn drop(&mut self) {
- unsafe {
- c::FreeLibrary(self.handle);
- }
- }
-}
pub mod alloc;
pub mod args;
-#[cfg(feature = "backtrace")]
-pub mod backtrace;
pub mod c;
pub mod cmath;
pub mod condvar;
-#[cfg(feature = "backtrace")]
-pub mod dynamic_lib;
pub mod env;
pub mod ext;
pub mod fast_thread_local;
/// supported platforms.
use crate::env;
-use crate::io::prelude::*;
use crate::io;
+use crate::io::prelude::*;
+use crate::mem;
use crate::path::{self, Path};
use crate::ptr;
-use crate::str;
use crate::sync::atomic::{self, Ordering};
use crate::sys::mutex::Mutex;
-use rustc_demangle::demangle;
-
-pub use crate::sys::backtrace::{
- unwind_backtrace,
- resolve_symname,
- foreach_symbol_fileline,
- BacktraceContext
-};
-
-#[cfg(target_pointer_width = "64")]
-pub const HEX_WIDTH: usize = 18;
-
-#[cfg(target_pointer_width = "32")]
-pub const HEX_WIDTH: usize = 10;
-
-/// Represents an item in the backtrace list. See `unwind_backtrace` for how
-/// it is created.
-#[derive(Debug, Copy, Clone)]
-pub struct Frame {
- /// Exact address of the call that failed.
- pub exact_position: *const u8,
- /// Address of the enclosing function.
- pub symbol_addr: *const u8,
- /// Which inlined function is this frame referring to
- pub inline_context: u32,
-}
+use backtrace::{BytesOrWideString, Frame, Symbol};
+
+pub const HEX_WIDTH: usize = 2 + 2 * mem::size_of::<usize>();
/// Max number of frames to print.
const MAX_NB_FRAMES: usize = 100;
// test mode immediately return here to optimize away any references to the
// libbacktrace symbols
if cfg!(test) {
- return Ok(())
+ return Ok(());
}
// Use a lock to prevent mixed output in multithreading context.
}
fn _print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
- let mut frames = [Frame {
- exact_position: ptr::null(),
- symbol_addr: ptr::null(),
- inline_context: 0,
- }; MAX_NB_FRAMES];
- let (nb_frames, context) = unwind_backtrace(&mut frames)?;
- let (skipped_before, skipped_after) =
- filter_frames(&frames[..nb_frames], format, &context);
- if skipped_before + skipped_after > 0 {
- writeln!(w, "note: Some details are omitted, \
- run with `RUST_BACKTRACE=full` for a verbose backtrace.")?;
- }
writeln!(w, "stack backtrace:")?;
- let filtered_frames = &frames[..nb_frames - skipped_after];
- for (index, frame) in filtered_frames.iter().skip(skipped_before).enumerate() {
- resolve_symname(*frame, |symname| {
- output(w, index, *frame, symname, format)
- }, &context)?;
- let has_more_filenames = foreach_symbol_fileline(*frame, |file, line| {
- output_fileline(w, file, line, format)
- }, &context)?;
- if has_more_filenames {
- w.write_all(b" <... and possibly more>")?;
- }
- }
-
- Ok(())
-}
-
-/// Returns a number of frames to remove at the beginning and at the end of the
-/// backtrace, according to the backtrace format.
-fn filter_frames(frames: &[Frame],
- format: PrintFormat,
- context: &BacktraceContext) -> (usize, usize)
-{
- if format == PrintFormat::Full {
- return (0, 0);
- }
-
- let skipped_before = 0;
-
- let skipped_after = frames.len() - frames.iter().position(|frame| {
- let mut is_marker = false;
- let _ = resolve_symname(*frame, |symname| {
- if let Some(mangled_symbol_name) = symname {
- // Use grep to find the concerned functions
- if mangled_symbol_name.contains("__rust_begin_short_backtrace") {
- is_marker = true;
- }
+ let mut printer = Printer::new(format, w);
+ unsafe {
+ backtrace::trace_unsynchronized(|frame| {
+ let mut hit = false;
+ backtrace::resolve_frame_unsynchronized(frame, |symbol| {
+ hit = true;
+ printer.output(frame, Some(symbol));
+ });
+ if !hit {
+ printer.output(frame, None);
}
- Ok(())
- }, context);
- is_marker
- }).unwrap_or(frames.len());
-
- if skipped_before + skipped_after >= frames.len() {
- // Avoid showing completely empty backtraces
- return (0, 0);
+ !printer.done
+ });
}
-
- (skipped_before, skipped_after)
+ if printer.skipped {
+ writeln!(
+ w,
+ "note: Some details are omitted, \
+ run with `RUST_BACKTRACE=full` for a verbose backtrace."
+ )?;
+ }
+ Ok(())
}
-
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
#[inline(never)]
pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
- where F: FnOnce() -> T, F: Send, T: Send
+where
+ F: FnOnce() -> T,
+ F: Send,
+ T: Send,
{
f()
}
_ => return Some(PrintFormat::Full),
}
- let val = env::var_os("RUST_BACKTRACE").and_then(|x|
+ let val = env::var_os("RUST_BACKTRACE").and_then(|x| {
if &x == "0" {
None
} else if &x == "full" {
} else {
Some(PrintFormat::Short)
}
+ });
+ ENABLED.store(
+ match val {
+ Some(v) => v as isize,
+ None => 1,
+ },
+ Ordering::SeqCst,
);
- ENABLED.store(match val {
- Some(v) => v as isize,
- None => 1,
- }, Ordering::SeqCst);
val
}
-/// Prints the symbol of the backtrace frame.
-///
-/// These output functions should now be used everywhere to ensure consistency.
-/// You may want to also use `output_fileline`.
-fn output(w: &mut dyn Write, idx: usize, frame: Frame,
- s: Option<&str>, format: PrintFormat) -> io::Result<()> {
- // Remove the `17: 0x0 - <unknown>` line.
- if format == PrintFormat::Short && frame.exact_position == ptr::null() {
- return Ok(());
+struct Printer<'a, 'b> {
+ format: PrintFormat,
+ done: bool,
+ skipped: bool,
+ idx: usize,
+ out: &'a mut (dyn Write + 'b),
+}
+
+impl<'a, 'b> Printer<'a, 'b> {
+ fn new(format: PrintFormat, out: &'a mut (dyn Write + 'b)) -> Printer<'a, 'b> {
+ Printer { format, done: false, skipped: false, idx: 0, out }
}
- match format {
- PrintFormat::Full => write!(w,
- " {:2}: {:2$?} - ",
- idx,
- frame.exact_position,
- HEX_WIDTH)?,
- PrintFormat::Short => write!(w, " {:2}: ", idx)?,
+
+ /// Prints the symbol of the backtrace frame.
+ ///
+ /// These output functions should now be used everywhere to ensure consistency.
+ /// You may want to also use `output_fileline`.
+ fn output(&mut self, frame: &Frame, symbol: Option<&Symbol>) {
+ if self.idx > MAX_NB_FRAMES {
+ self.done = true;
+ self.skipped = true;
+ return;
+ }
+ if self._output(frame, symbol).is_err() {
+ self.done = true;
+ }
+ self.idx += 1;
}
- match s {
- Some(string) => {
- let symbol = demangle(string);
- match format {
- PrintFormat::Full => write!(w, "{}", symbol)?,
- // strip the trailing hash if short mode
- PrintFormat::Short => write!(w, "{:#}", symbol)?,
+
+ fn _output(&mut self, frame: &Frame, symbol: Option<&Symbol>) -> io::Result<()> {
+ if self.format == PrintFormat::Short {
+ if let Some(sym) = symbol.and_then(|s| s.name()).and_then(|s| s.as_str()) {
+ if sym.contains("__rust_begin_short_backtrace") {
+ self.skipped = true;
+ self.done = true;
+ return Ok(());
+ }
+ }
+
+ // Remove the `17: 0x0 - <unknown>` line.
+ if self.format == PrintFormat::Short && frame.ip() == ptr::null_mut() {
+ self.skipped = true;
+ return Ok(());
}
}
- None => w.write_all(b"<unknown>")?,
- }
- w.write_all(b"\n")
-}
-/// Prints the filename and line number of the backtrace frame.
-///
-/// See also `output`.
-#[allow(dead_code)]
-fn output_fileline(w: &mut dyn Write,
- file: &[u8],
- line: u32,
- format: PrintFormat) -> io::Result<()> {
- // prior line: " ##: {:2$} - func"
- w.write_all(b"")?;
- match format {
- PrintFormat::Full => write!(w,
- " {:1$}",
- "",
- HEX_WIDTH)?,
- PrintFormat::Short => write!(w, " ")?,
- }
+ match self.format {
+ PrintFormat::Full => {
+ write!(self.out, " {:2}: {:2$?} - ", self.idx, frame.ip(), HEX_WIDTH)?
+ }
+ PrintFormat::Short => write!(self.out, " {:2}: ", self.idx)?,
+ }
- let file = str::from_utf8(file).unwrap_or("<unknown>");
- let file_path = Path::new(file);
- let mut already_printed = false;
- if format == PrintFormat::Short && file_path.is_absolute() {
- if let Ok(cwd) = env::current_dir() {
- if let Ok(stripped) = file_path.strip_prefix(&cwd) {
- if let Some(s) = stripped.to_str() {
- write!(w, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?;
- already_printed = true;
+ match symbol.and_then(|s| s.name()) {
+ Some(symbol) => {
+ match self.format {
+ PrintFormat::Full => write!(self.out, "{}", symbol)?,
+ // strip the trailing hash if short mode
+ PrintFormat::Short => write!(self.out, "{:#}", symbol)?,
}
}
+ None => self.out.write_all(b"<unknown>")?,
}
- }
- if !already_printed {
- write!(w, " at {}:{}", file, line)?;
+ self.out.write_all(b"\n")?;
+ if let Some(sym) = symbol {
+ self.output_fileline(sym)?;
+ }
+ Ok(())
}
- w.write_all(b"\n")
+ /// Prints the filename and line number of the backtrace frame.
+ ///
+ /// See also `output`.
+ fn output_fileline(&mut self, symbol: &Symbol) -> io::Result<()> {
+ #[cfg(windows)]
+ let path_buf;
+ let file = match symbol.filename_raw() {
+ #[cfg(unix)]
+ Some(BytesOrWideString::Bytes(bytes)) => {
+ use crate::os::unix::prelude::*;
+ Path::new(crate::ffi::OsStr::from_bytes(bytes))
+ }
+ #[cfg(not(unix))]
+ Some(BytesOrWideString::Bytes(bytes)) => {
+ Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>"))
+ }
+ #[cfg(windows)]
+ Some(BytesOrWideString::Wide(wide)) => {
+ use crate::os::windows::prelude::*;
+ path_buf = crate::ffi::OsString::from_wide(wide);
+ Path::new(&path_buf)
+ }
+ #[cfg(not(windows))]
+ Some(BytesOrWideString::Wide(_wide)) => {
+ Path::new("<unknown>")
+ }
+ None => return Ok(()),
+ };
+ let line = match symbol.lineno() {
+ Some(line) => line,
+ None => return Ok(()),
+ };
+ // prior line: " ##: {:2$} - func"
+ self.out.write_all(b"")?;
+ match self.format {
+ PrintFormat::Full => write!(self.out, " {:1$}", "", HEX_WIDTH)?,
+ PrintFormat::Short => write!(self.out, " ")?,
+ }
+
+ let mut already_printed = false;
+ if self.format == PrintFormat::Short && file.is_absolute() {
+ if let Ok(cwd) = env::current_dir() {
+ if let Ok(stripped) = file.strip_prefix(&cwd) {
+ if let Some(s) = stripped.to_str() {
+ write!(self.out, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?;
+ already_printed = true;
+ }
+ }
+ }
+ }
+ if !already_printed {
+ write!(self.out, " at {}:{}", file.display(), line)?;
+ }
+
+ self.out.write_all(b"\n")
+ }
}
+++ /dev/null
-use backtrace_sys::backtrace_state;
-
-use crate::ffi::CStr;
-use crate::io;
-use crate::mem;
-use crate::ptr;
-use crate::sys::backtrace::BacktraceContext;
-use crate::sys_common::backtrace::Frame;
-
-pub fn foreach_symbol_fileline<F>(frame: Frame,
- mut f: F,
- _: &BacktraceContext) -> io::Result<bool>
-where F: FnMut(&[u8], u32) -> io::Result<()>
-{
- // pcinfo may return an arbitrary number of file:line pairs,
- // in the order of stack trace (i.e., inlined calls first).
- // in order to avoid allocation, we stack-allocate a fixed size of entries.
- const FILELINE_SIZE: usize = 32;
- let mut fileline_buf = [(ptr::null(), !0); FILELINE_SIZE];
- let ret;
- let fileline_count = {
- let state = unsafe { init_state() };
- if state.is_null() {
- return Err(io::Error::new(
- io::ErrorKind::Other,
- "failed to allocate libbacktrace state")
- )
- }
- let mut fileline_win: &mut [FileLine] = &mut fileline_buf;
- let fileline_addr = &mut fileline_win as *mut &mut [FileLine];
- ret = unsafe {
- backtrace_sys::backtrace_pcinfo(
- state,
- frame.exact_position as libc::uintptr_t,
- pcinfo_cb,
- error_cb,
- fileline_addr as *mut libc::c_void,
- )
- };
- FILELINE_SIZE - fileline_win.len()
- };
- if ret == 0 {
- for &(file, line) in &fileline_buf[..fileline_count] {
- if file.is_null() { continue; } // just to be sure
- let file = unsafe { CStr::from_ptr(file).to_bytes() };
- f(file, line)?;
- }
- Ok(fileline_count == FILELINE_SIZE)
- } else {
- Ok(false)
- }
-}
-
-/// Converts a pointer to symbol to its string value.
-pub fn resolve_symname<F>(frame: Frame,
- callback: F,
- _: &BacktraceContext) -> io::Result<()>
- where F: FnOnce(Option<&str>) -> io::Result<()>
-{
- let symname = {
- let state = unsafe { init_state() };
- if state.is_null() {
- return Err(io::Error::new(
- io::ErrorKind::Other,
- "failed to allocate libbacktrace state")
- )
- }
- let mut data: *const libc::c_char = ptr::null();
- let data_addr = &mut data as *mut *const libc::c_char;
- let ret = unsafe {
- backtrace_sys::backtrace_syminfo(
- state,
- frame.symbol_addr as libc::uintptr_t,
- syminfo_cb,
- error_cb,
- data_addr as *mut libc::c_void,
- )
- };
- if ret == 0 || data.is_null() {
- None
- } else {
- unsafe {
- CStr::from_ptr(data).to_str().ok()
- }
- }
- };
- callback(symname)
-}
-
-////////////////////////////////////////////////////////////////////////
-// helper callbacks
-////////////////////////////////////////////////////////////////////////
-
-type FileLine = (*const libc::c_char, u32);
-
-extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
- _errnum: libc::c_int) {
- // do nothing for now
-}
-extern fn syminfo_cb(data: *mut libc::c_void,
- _pc: libc::uintptr_t,
- symname: *const libc::c_char,
- _symval: libc::uintptr_t,
- _symsize: libc::uintptr_t) {
- let slot = data as *mut *const libc::c_char;
- unsafe { *slot = symname; }
-}
-extern fn pcinfo_cb(data: *mut libc::c_void,
- _pc: libc::uintptr_t,
- filename: *const libc::c_char,
- lineno: libc::c_int,
- _function: *const libc::c_char) -> libc::c_int {
- if !filename.is_null() {
- let slot = data as *mut &mut [FileLine];
- let buffer = unsafe {ptr::read(slot)};
-
- // if the buffer is not full, add file:line to the buffer
- // and adjust the buffer for next possible calls to pcinfo_cb.
- if !buffer.is_empty() {
- buffer[0] = (filename, lineno as u32);
- unsafe { ptr::write(slot, &mut buffer[1..]); }
- }
- }
-
- 0
-}
-
-// The libbacktrace API supports creating a state, but it does not
-// support destroying a state. I personally take this to mean that a
-// state is meant to be created and then live forever.
-//
-// I would love to register an at_exit() handler which cleans up this
-// state, but libbacktrace provides no way to do so.
-//
-// With these constraints, this function has a statically cached state
-// that is calculated the first time this is requested. Remember that
-// backtracing all happens serially (one global lock).
-//
-// Things don't work so well on not-Linux since libbacktrace can't track
-// down that executable this is. We at one point used env::current_exe but
-// it turns out that there are some serious security issues with that
-// approach.
-//
-// Specifically, on certain platforms like BSDs, a malicious actor can cause
-// an arbitrary file to be placed at the path returned by current_exe.
-// libbacktrace does not behave defensively in the presence of ill-formed
-// DWARF information, and has been demonstrated to segfault in at least one
-// case. There is no evidence at the moment to suggest that a more carefully
-// constructed file can't cause arbitrary code execution. As a result of all
-// of this, we don't hint libbacktrace with the path to the current process.
-unsafe fn init_state() -> *mut backtrace_state {
- static mut STATE: *mut backtrace_state = ptr::null_mut();
- if !STATE.is_null() { return STATE }
-
- let filename = match crate::sys::backtrace::gnu::get_executable_filename() {
- Ok((filename, file)) => {
- // filename is purposely leaked here since libbacktrace requires
- // it to stay allocated permanently, file is also leaked so that
- // the file stays locked
- let filename_ptr = filename.as_ptr();
- mem::forget(filename);
- mem::forget(file);
- filename_ptr
- },
- Err(_) => ptr::null(),
- };
-
- STATE = backtrace_sys::backtrace_create_state(
- filename,
- 0,
- error_cb,
- ptr::null_mut(),
- );
- STATE
-}
+++ /dev/null
-#![allow(missing_docs)]
-#![allow(non_camel_case_types)]
-#![allow(non_snake_case)]
-
-pub mod libbacktrace;
}
}
-#[cfg(feature = "backtrace")]
-#[cfg(any(all(unix, not(target_os = "emscripten")),
- all(windows, target_env = "gnu"),
- target_os = "redox"))]
-pub mod gnu;
-
// common error constructors
/// A trait for viewing representations from std types
use crate::print::pprust;
use crate::ptr::P;
use crate::source_map::{dummy_spanned, respan, Spanned};
-use crate::symbol::{kw, Symbol};
+use crate::symbol::{kw, sym, Symbol};
use crate::tokenstream::TokenStream;
use crate::ThinVec;
}
}
+ pub fn to_symbol(&self) -> Symbol {
+ match *self {
+ IntTy::Isize => sym::isize,
+ IntTy::I8 => sym::i8,
+ IntTy::I16 => sym::i16,
+ IntTy::I32 => sym::i32,
+ IntTy::I64 => sym::i64,
+ IntTy::I128 => sym::i128,
+ }
+ }
+
pub fn val_to_string(&self, val: i128) -> String {
// Cast to a `u128` so we can correctly print `INT128_MIN`. All integral types
// are parsed as `u128`, so we wouldn't want to print an extra negative
}
}
+ pub fn to_symbol(&self) -> Symbol {
+ match *self {
+ UintTy::Usize => sym::usize,
+ UintTy::U8 => sym::u8,
+ UintTy::U16 => sym::u16,
+ UintTy::U32 => sym::u32,
+ UintTy::U64 => sym::u64,
+ UintTy::U128 => sym::u128,
+ }
+ }
+
pub fn val_to_string(&self, val: u128) -> String {
format!("{}{}", val, self.ty_to_string())
}
}
diagnostic.map(|d| {
- span_err!(d, attr.span, E0633, "malformed `#[unwind]` attribute");
+ struct_span_err!(d, attr.span, E0633, "malformed `unwind` attribute input")
+ .span_label(attr.span, "invalid argument")
+ .span_suggestions(
+ attr.span,
+ "the allowed arguments are `allowed` and `aborts`",
+ (vec!["allowed", "aborts"]).into_iter()
+ .map(|s| format!("#[unwind({})]", s)),
+ Applicability::MachineApplicable,
+ ).emit();
});
}
}
pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T>
where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
{
- let mut parser = Parser::new(sess, self.tokens.clone(), None, false, false);
+ let mut parser = Parser::new(
+ sess,
+ self.tokens.clone(),
+ None,
+ false,
+ false,
+ Some("attribute"),
+ );
let result = f(&mut parser)?;
if parser.token != token::Eof {
parser.unexpected()?;
if !attr.check_name(sym::cfg_attr) {
return vec![attr];
}
+ if attr.tokens.len() == 0 {
+ self.sess.span_diagnostic
+ .struct_span_err(
+ attr.span,
+ "malformed `cfg_attr` attribute input",
+ ).span_suggestion(
+ attr.span,
+ "missing condition and attribute",
+ "#[cfg_attr(condition, attribute, other_attribute, ...)]".to_owned(),
+ Applicability::HasPlaceholders,
+ ).note("for more information, visit \
+ <https://doc.rust-lang.org/reference/conditional-compilation.html\
+ #the-cfg_attr-attribute>")
+ .emit();
+ return Vec::new();
+ }
let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| {
parser.expect(&token::OpenDelim(token::Paren))?;
use crate::parse::token;
use crate::ptr::P;
use crate::symbol::{kw, sym, Ident, Symbol};
-use crate::ThinVec;
+use crate::{ThinVec, MACRO_ARGUMENTS};
use crate::tokenstream::{self, TokenStream};
use errors::{DiagnosticBuilder, DiagnosticId};
}
pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree]) -> parser::Parser<'a> {
- parse::stream_to_parser(self.parse_sess, tts.iter().cloned().collect())
+ parse::stream_to_parser(self.parse_sess, tts.iter().cloned().collect(), MACRO_ARGUMENTS)
}
pub fn source_map(&self) -> &'a SourceMap { self.parse_sess.source_map() }
pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
pub fn ident_of(&self, st: &str) -> ast::Ident {
ast::Ident::from_str(st)
}
- pub fn std_path(&self, components: &[&str]) -> Vec<ast::Ident> {
+ pub fn std_path(&self, components: &[Symbol]) -> Vec<ast::Ident> {
let def_site = DUMMY_SP.apply_mark(self.current_expansion.mark);
iter::once(Ident::new(kw::DollarCrate, def_site))
- .chain(components.iter().map(|s| self.ident_of(s)))
+ .chain(components.iter().map(|&s| Ident::with_empty_ctxt(s)))
.collect()
}
pub fn name_of(&self, st: &str) -> ast::Name {
use crate::source_map::{dummy_spanned, respan, Spanned};
use crate::ext::base::ExtCtxt;
use crate::ptr::P;
-use crate::symbol::{Symbol, kw};
+use crate::symbol::{kw, sym, Symbol};
use crate::ThinVec;
use rustc_target::spec::abi::Abi;
-use syntax_pos::{Pos, Span, DUMMY_SP};
+use syntax_pos::{Pos, Span};
pub trait AstBuilder {
// paths
ty: P<ast::Ty>,
mutbl: ast::Mutability) -> P<ast::Ty>;
- fn ty_option(&self, ty: P<ast::Ty>) -> P<ast::Ty>;
fn ty_infer(&self, sp: Span) -> P<ast::Ty>;
fn typaram(&self,
ast::TyKind::Ptr(self.ty_mt(ty, mutbl)))
}
- fn ty_option(&self, ty: P<ast::Ty>) -> P<ast::Ty> {
- self.ty_path(
- self.path_all(DUMMY_SP,
- true,
- self.std_path(&["option", "Option"]),
- vec![ast::GenericArg::Type(ty)],
- Vec::new()))
- }
-
fn ty_infer(&self, span: Span) -> P<ast::Ty> {
self.ty(span, ast::TyKind::Infer)
}
self.expr(sp, ast::ExprKind::Array(exprs))
}
fn expr_vec_ng(&self, sp: Span) -> P<ast::Expr> {
- self.expr_call_global(sp, self.std_path(&["vec", "Vec", "new"]),
+ self.expr_call_global(sp, self.std_path(&[sym::vec, sym::Vec, sym::new]),
Vec::new())
}
fn expr_vec_slice(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
fn expr_some(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
- let some = self.std_path(&["option", "Option", "Some"]);
+ let some = self.std_path(&[sym::option, sym::Option, sym::Some]);
self.expr_call_global(sp, some, vec![expr])
}
fn expr_none(&self, sp: Span) -> P<ast::Expr> {
- let none = self.std_path(&["option", "Option", "None"]);
+ let none = self.std_path(&[sym::option, sym::Option, sym::None]);
let none = self.path_global(sp, none);
self.expr_path(none)
}
let expr_loc_ptr = self.expr_addr_of(span, expr_loc_tuple);
self.expr_call_global(
span,
- self.std_path(&["rt", "begin_panic"]),
+ self.std_path(&[sym::rt, sym::begin_panic]),
vec![
self.expr_str(span, msg),
expr_loc_ptr])
}
fn expr_ok(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
- let ok = self.std_path(&["result", "Result", "Ok"]);
+ let ok = self.std_path(&[sym::result, sym::Result, sym::Ok]);
self.expr_call_global(sp, ok, vec![expr])
}
fn expr_err(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
- let err = self.std_path(&["result", "Result", "Err"]);
+ let err = self.std_path(&[sym::result, sym::Result, sym::Err]);
self.expr_call_global(sp, err, vec![expr])
}
fn expr_try(&self, sp: Span, head: P<ast::Expr>) -> P<ast::Expr> {
- let ok = self.std_path(&["result", "Result", "Ok"]);
+ let ok = self.std_path(&[sym::result, sym::Result, sym::Ok]);
let ok_path = self.path_global(sp, ok);
- let err = self.std_path(&["result", "Result", "Err"]);
+ let err = self.std_path(&[sym::result, sym::Result, sym::Err]);
let err_path = self.path_global(sp, err);
let binding_variable = self.ident_of("__try_var");
}
fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
- let some = self.std_path(&["option", "Option", "Some"]);
+ let some = self.std_path(&[sym::option, sym::Option, sym::Some]);
let path = self.path_global(span, some);
self.pat_tuple_struct(span, path, vec![pat])
}
fn pat_none(&self, span: Span) -> P<ast::Pat> {
- let some = self.std_path(&["option", "Option", "None"]);
+ let some = self.std_path(&[sym::option, sym::Option, sym::None]);
let path = self.path_global(span, some);
self.pat_path(span, path)
}
fn pat_ok(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
- let some = self.std_path(&["result", "Result", "Ok"]);
+ let some = self.std_path(&[sym::result, sym::Result, sym::Ok]);
let path = self.path_global(span, some);
self.pat_tuple_struct(span, path, vec![pat])
}
fn pat_err(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
- let some = self.std_path(&["result", "Result", "Err"]);
+ let some = self.std_path(&[sym::result, sym::Result, sym::Err]);
let path = self.path_global(span, some);
self.pat_tuple_struct(span, path, vec![pat])
}
use crate::ext::build::AstBuilder;
use crate::parse::parser::PathStyle;
use crate::symbol::{Symbol, sym};
+use crate::errors::Applicability;
use syntax_pos::Span;
return true;
}
if !attr.is_meta_item_list() {
- cx.span_err(attr.span,
- "attribute must be of the form `#[derive(Trait1, Trait2, ...)]`");
+ cx.struct_span_err(attr.span, "malformed `derive` attribute input")
+ .span_suggestion(
+ attr.span,
+ "missing traits to be derived",
+ "#[derive(Trait1, Trait2, ...)]".to_owned(),
+ Applicability::HasPlaceholders,
+ ).emit();
return false;
}
call_site: span,
def_site: None,
format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
- allow_internal_unstable: Some(vec![
- Symbol::intern("rustc_attrs"),
- Symbol::intern("structural_match"),
- ].into()),
+ allow_internal_unstable: Some(vec![sym::rustc_attrs, sym::structural_match].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
edition: cx.parse_sess.edition,
attrs.push(cx.attribute(span, meta));
}
if names.contains(&Symbol::intern("Copy")) {
- let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
+ let meta = cx.meta_word(span, sym::rustc_copy_clone_marker);
attrs.push(cx.attribute(span, meta));
}
});
}
BuiltinDerive(func) => {
expn_info.allow_internal_unstable = Some(vec![
- Symbol::intern("rustc_attrs"),
+ sym::rustc_attrs,
Symbol::intern("derive_clone_copy"),
Symbol::intern("derive_eq"),
Symbol::intern("libstd_sys_internals"), // RustcDeserialize and RustcSerialize
use crate::parse::parser::{Parser, PathStyle};
use crate::parse::token::{self, DocComment, Nonterminal, Token};
use crate::print::pprust;
-use crate::symbol::kw;
+use crate::symbol::{kw, sym, Symbol};
use crate::tokenstream::{DelimSpan, TokenStream};
use errors::FatalError;
TokenTree::MetaVarDecl(_, _, id) => {
// Built-in nonterminals never start with these tokens,
// so we can eliminate them from consideration.
- if may_begin_with(&*id.as_str(), token) {
+ if may_begin_with(id.name, token) {
bb_items.push(item);
}
}
recurse_into_modules: bool,
) -> NamedParseResult {
// Create a parser that can be used for the "black box" parts.
- let mut parser = Parser::new(sess, tts, directory, recurse_into_modules, true);
+ let mut parser = Parser::new(
+ sess,
+ tts,
+ directory,
+ recurse_into_modules,
+ true,
+ crate::MACRO_ARGUMENTS,
+ );
// A queue of possible matcher positions. We initialize it with the matcher position in which
// the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop` then
let match_cur = item.match_cur;
item.push_match(
match_cur,
- MatchedNonterminal(Lrc::new(parse_nt(&mut parser, span, &ident.as_str()))),
+ MatchedNonterminal(Lrc::new(parse_nt(&mut parser, span, ident.name))),
);
item.idx += 1;
item.match_cur += 1;
///
/// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with that
/// token. Be conservative (return true) if not sure.
-fn may_begin_with(name: &str, token: &Token) -> bool {
+fn may_begin_with(name: Symbol, token: &Token) -> bool {
/// Checks whether the non-terminal may contain a single (non-keyword) identifier.
fn may_be_ident(nt: &token::Nonterminal) -> bool {
match *nt {
}
match name {
- "expr" => token.can_begin_expr(),
- "ty" => token.can_begin_type(),
- "ident" => get_macro_ident(token).is_some(),
- "literal" => token.can_begin_literal_or_bool(),
- "vis" => match *token {
+ sym::expr => token.can_begin_expr(),
+ sym::ty => token.can_begin_type(),
+ sym::ident => get_macro_ident(token).is_some(),
+ sym::literal => token.can_begin_literal_or_bool(),
+ sym::vis => match *token {
// The follow-set of :vis + "priv" keyword + interpolated
Token::Comma | Token::Ident(..) | Token::Interpolated(_) => true,
_ => token.can_begin_type(),
},
- "block" => match *token {
+ sym::block => match *token {
Token::OpenDelim(token::Brace) => true,
Token::Interpolated(ref nt) => match **nt {
token::NtItem(_)
},
_ => false,
},
- "path" | "meta" => match *token {
+ sym::path | sym::meta => match *token {
Token::ModSep | Token::Ident(..) => true,
Token::Interpolated(ref nt) => match **nt {
token::NtPath(_) | token::NtMeta(_) => true,
},
_ => false,
},
- "pat" => match *token {
+ sym::pat => match *token {
Token::Ident(..) | // box, ref, mut, and other identifiers (can stricten)
Token::OpenDelim(token::Paren) | // tuple pattern
Token::OpenDelim(token::Bracket) | // slice pattern
Token::Interpolated(ref nt) => may_be_ident(nt),
_ => false,
},
- "lifetime" => match *token {
+ sym::lifetime => match *token {
Token::Lifetime(_) => true,
Token::Interpolated(ref nt) => match **nt {
token::NtLifetime(_) | token::NtTT(_) => true,
/// # Returns
///
/// The parsed non-terminal.
-fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
- if name == "tt" {
+fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: Symbol) -> Nonterminal {
+ if name == sym::tt {
return token::NtTT(p.parse_token_tree());
}
// check at the beginning and the parser checks after each bump
p.process_potential_macro_variable();
match name {
- "item" => match panictry!(p.parse_item()) {
+ sym::item => match panictry!(p.parse_item()) {
Some(i) => token::NtItem(i),
None => {
p.fatal("expected an item keyword").emit();
FatalError.raise();
}
},
- "block" => token::NtBlock(panictry!(p.parse_block())),
- "stmt" => match panictry!(p.parse_stmt()) {
+ sym::block => token::NtBlock(panictry!(p.parse_block())),
+ sym::stmt => match panictry!(p.parse_stmt()) {
Some(s) => token::NtStmt(s),
None => {
p.fatal("expected a statement").emit();
FatalError.raise();
}
},
- "pat" => token::NtPat(panictry!(p.parse_pat(None))),
- "expr" => token::NtExpr(panictry!(p.parse_expr())),
- "literal" => token::NtLiteral(panictry!(p.parse_literal_maybe_minus())),
- "ty" => token::NtTy(panictry!(p.parse_ty())),
+ sym::pat => token::NtPat(panictry!(p.parse_pat(None))),
+ sym::expr => token::NtExpr(panictry!(p.parse_expr())),
+ sym::literal => token::NtLiteral(panictry!(p.parse_literal_maybe_minus())),
+ sym::ty => token::NtTy(panictry!(p.parse_ty())),
// this could be handled like a token, since it is one
- "ident" => if let Some((ident, is_raw)) = get_macro_ident(&p.token) {
+ sym::ident => if let Some((ident, is_raw)) = get_macro_ident(&p.token) {
let span = p.span;
p.bump();
token::NtIdent(Ident::new(ident.name, span), is_raw)
p.fatal(&format!("expected ident, found {}", &token_str)).emit();
FatalError.raise()
}
- "path" => token::NtPath(panictry!(p.parse_path(PathStyle::Type))),
- "meta" => token::NtMeta(panictry!(p.parse_meta_item())),
- "vis" => token::NtVis(panictry!(p.parse_visibility(true))),
- "lifetime" => if p.check_lifetime() {
+ sym::path => token::NtPath(panictry!(p.parse_path(PathStyle::Type))),
+ sym::meta => token::NtMeta(panictry!(p.parse_meta_item())),
+ sym::vis => token::NtVis(panictry!(p.parse_visibility(true))),
+ sym::lifetime => if p.check_lifetime() {
token::NtLifetime(p.expect_lifetime().ident)
} else {
let token_str = pprust::token_to_string(&p.token);
path: Cow::from(cx.current_expansion.module.directory.as_path()),
ownership: cx.current_expansion.directory_ownership,
};
- let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false);
+ let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false, None);
p.root_module_name = cx.current_expansion.module.mod_path.last()
.map(|id| id.as_str().to_string());
future this will become a hard error. Please use `allow_internal_unstable(\
foo, bar)` to only allow the `foo` and `bar` features",
);
- vec![Symbol::intern("allow_internal_unstable_backcompat_hack")].into()
+ vec![sym::allow_internal_unstable_backcompat_hack].into()
})
);
let allow_internal_unsafe = attr::contains_name(&def.attrs, sym::allow_internal_unsafe);
use crate::symbol::{Symbol, kw, sym};
use crate::tokenstream::TokenTree;
-use errors::{DiagnosticBuilder, Handler};
+use errors::{Applicability, DiagnosticBuilder, Handler};
use rustc_data_structures::fx::FxHashMap;
use rustc_target::spec::abi::Abi;
use syntax_pos::{Span, DUMMY_SP};
Normal,
template!(
Word,
- List: r#"/*opt*/ since = "version", /*opt*/ note = "reason"#,
+ List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
NameValueStr: "reason"
),
Ungated
match attr.parse_meta(self.context.parse_sess) {
Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) {
+ let error_msg = format!("malformed `{}` attribute input", name);
let mut msg = "attribute must be of the form ".to_owned();
+ let mut suggestions = vec![];
let mut first = true;
if template.word {
first = false;
- msg.push_str(&format!("`#[{}{}]`", name, ""));
+ let code = format!("#[{}]", name);
+ msg.push_str(&format!("`{}`", &code));
+ suggestions.push(code);
}
if let Some(descr) = template.list {
if !first {
msg.push_str(" or ");
}
first = false;
- msg.push_str(&format!("`#[{}({})]`", name, descr));
+ let code = format!("#[{}({})]", name, descr);
+ msg.push_str(&format!("`{}`", &code));
+ suggestions.push(code);
}
if let Some(descr) = template.name_value_str {
if !first {
msg.push_str(" or ");
}
- msg.push_str(&format!("`#[{} = \"{}\"]`", name, descr));
+ let code = format!("#[{} = \"{}\"]", name, descr);
+ msg.push_str(&format!("`{}`", &code));
+ suggestions.push(code);
}
if should_warn(name) {
self.context.parse_sess.buffer_lint(
&msg,
);
} else {
- self.context.parse_sess.span_diagnostic.span_err(meta.span, &msg);
+ self.context.parse_sess.span_diagnostic.struct_span_err(meta.span, &error_msg)
+ .span_suggestions(
+ meta.span,
+ if suggestions.len() == 1 {
+ "must be of the form"
+ } else {
+ "the following are the possible correct uses"
+ },
+ suggestions.into_iter(),
+ Applicability::HasPlaceholders,
+ ).emit();
}
}
Err(mut err) => err.emit(),
let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed");
if let Some(reason) = reason {
err.span_note(span, reason);
+ } else {
+ err.span_label(span, "feature has been removed");
}
err.emit();
}
None => continue,
};
+ let bad_input = |span| {
+ struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input")
+ };
+
for mi in list {
let name = match mi.ident() {
Some(ident) if mi.is_word() => ident.name,
- _ => {
- span_err!(span_handler, mi.span(), E0556,
- "malformed feature, expected just one word");
+ Some(ident) => {
+ bad_input(mi.span()).span_suggestion(
+ mi.span(),
+ "expected just one word",
+ format!("{}", ident.name),
+ Applicability::MaybeIncorrect,
+ ).emit();
+ continue
+ }
+ None => {
+ bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit();
continue
}
};
use ast::AttrId;
use syntax_pos::edition::Edition;
+const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments");
+
// A variant of 'try!' that panics on an Err. This is used as a crutch on the
// way towards a non-panic!-prone parser. It should be used for fatal parsing
// errors; eventually we plan to convert all code using panictry to just use
use crate::ast;
use crate::ast::{
- BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind, VariantData,
+ BlockCheckMode, BinOpKind, Expr, ExprKind, Item, ItemKind, Pat, PatKind, PathSegment, QSelf,
+ Ty, TyKind, VariantData,
};
-use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType};
-use crate::parse::token;
-use crate::parse::PResult;
-use crate::parse::Parser;
+use crate::parse::{SeqSep, token, PResult, Parser};
+use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType};
use crate::print::pprust;
use crate::ptr::P;
use crate::source_map::Spanned;
-use crate::symbol::kw;
+use crate::symbol::{kw, sym};
use crate::ThinVec;
-use errors::{Applicability, DiagnosticBuilder};
-use log::debug;
-use syntax_pos::Span;
+use crate::util::parser::AssocOp;
+use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
+use syntax_pos::{Span, DUMMY_SP, MultiSpan};
+use log::{debug, trace};
+
+pub enum Error {
+ FileNotFoundForModule {
+ mod_name: String,
+ default_path: String,
+ secondary_path: String,
+ dir_path: String,
+ },
+ DuplicatePaths {
+ mod_name: String,
+ default_path: String,
+ secondary_path: String,
+ },
+ UselessDocComment,
+ InclusiveRangeWithNoEnd,
+}
+
+impl Error {
+ fn span_err<S: Into<MultiSpan>>(
+ self,
+ sp: S,
+ handler: &errors::Handler,
+ ) -> DiagnosticBuilder<'_> {
+ match self {
+ Error::FileNotFoundForModule {
+ ref mod_name,
+ ref default_path,
+ ref secondary_path,
+ ref dir_path,
+ } => {
+ let mut err = struct_span_err!(
+ handler,
+ sp,
+ E0583,
+ "file not found for module `{}`",
+ mod_name,
+ );
+ err.help(&format!(
+ "name the file either {} or {} inside the directory \"{}\"",
+ default_path,
+ secondary_path,
+ dir_path,
+ ));
+ err
+ }
+ Error::DuplicatePaths { ref mod_name, ref default_path, ref secondary_path } => {
+ let mut err = struct_span_err!(
+ handler,
+ sp,
+ E0584,
+ "file for module `{}` found at both {} and {}",
+ mod_name,
+ default_path,
+ secondary_path,
+ );
+ err.help("delete or rename one of them to remove the ambiguity");
+ err
+ }
+ Error::UselessDocComment => {
+ let mut err = struct_span_err!(
+ handler,
+ sp,
+ E0585,
+ "found a documentation comment that doesn't document anything",
+ );
+ err.help("doc comments must come before what they document, maybe a comment was \
+ intended with `//`?");
+ err
+ }
+ Error::InclusiveRangeWithNoEnd => {
+ let mut err = struct_span_err!(
+ handler,
+ sp,
+ E0586,
+ "inclusive range with no end",
+ );
+ err.help("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)");
+ err
+ }
+ }
+ }
+}
pub trait RecoverQPath: Sized + 'static {
const PATH_STYLE: PathStyle = PathStyle::Expr;
}
impl<'a> Parser<'a> {
+ pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> {
+ self.span_fatal(self.span, m)
+ }
+
+ pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
+ self.sess.span_diagnostic.struct_span_fatal(sp, m)
+ }
+
+ pub fn span_fatal_err<S: Into<MultiSpan>>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> {
+ err.span_err(sp, self.diagnostic())
+ }
+
+ pub fn bug(&self, m: &str) -> ! {
+ self.sess.span_diagnostic.span_bug(self.span, m)
+ }
+
+ pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) {
+ self.sess.span_diagnostic.span_err(sp, m)
+ }
+
+ crate fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
+ self.sess.span_diagnostic.struct_span_err(sp, m)
+ }
+
+ crate fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> ! {
+ self.sess.span_diagnostic.span_bug(sp, m)
+ }
+
+ crate fn cancel(&self, err: &mut DiagnosticBuilder<'_>) {
+ self.sess.span_diagnostic.cancel(err)
+ }
+
+ crate fn diagnostic(&self) -> &'a errors::Handler {
+ &self.sess.span_diagnostic
+ }
+
+ crate fn expected_ident_found(&self) -> DiagnosticBuilder<'a> {
+ let mut err = self.struct_span_err(
+ self.span,
+ &format!("expected identifier, found {}", self.this_token_descr()),
+ );
+ if let token::Ident(ident, false) = &self.token {
+ if ident.is_raw_guess() {
+ err.span_suggestion(
+ self.span,
+ "you can escape reserved keywords to use them as identifiers",
+ format!("r#{}", ident),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ if let Some(token_descr) = self.token_descr() {
+ err.span_label(self.span, format!("expected identifier, found {}", token_descr));
+ } else {
+ err.span_label(self.span, "expected identifier");
+ if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) {
+ err.span_suggestion(
+ self.span,
+ "remove this comma",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ err
+ }
+
+ pub fn expected_one_of_not_found(
+ &mut self,
+ edible: &[token::Token],
+ inedible: &[token::Token],
+ ) -> PResult<'a, bool /* recovered */> {
+ fn tokens_to_string(tokens: &[TokenType]) -> String {
+ let mut i = tokens.iter();
+ // This might be a sign we need a connect method on Iterator.
+ let b = i.next()
+ .map_or(String::new(), |t| t.to_string());
+ i.enumerate().fold(b, |mut b, (i, a)| {
+ if tokens.len() > 2 && i == tokens.len() - 2 {
+ b.push_str(", or ");
+ } else if tokens.len() == 2 && i == tokens.len() - 2 {
+ b.push_str(" or ");
+ } else {
+ b.push_str(", ");
+ }
+ b.push_str(&a.to_string());
+ b
+ })
+ }
+
+ let mut expected = edible.iter()
+ .map(|x| TokenType::Token(x.clone()))
+ .chain(inedible.iter().map(|x| TokenType::Token(x.clone())))
+ .chain(self.expected_tokens.iter().cloned())
+ .collect::<Vec<_>>();
+ expected.sort_by_cached_key(|x| x.to_string());
+ expected.dedup();
+ let expect = tokens_to_string(&expected[..]);
+ let actual = self.this_token_to_string();
+ let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
+ let short_expect = if expected.len() > 6 {
+ format!("{} possible tokens", expected.len())
+ } else {
+ expect.clone()
+ };
+ (format!("expected one of {}, found `{}`", expect, actual),
+ (self.sess.source_map().next_point(self.prev_span),
+ format!("expected one of {} here", short_expect)))
+ } else if expected.is_empty() {
+ (format!("unexpected token: `{}`", actual),
+ (self.prev_span, "unexpected token after this".to_string()))
+ } else {
+ (format!("expected {}, found `{}`", expect, actual),
+ (self.sess.source_map().next_point(self.prev_span),
+ format!("expected {} here", expect)))
+ };
+ self.last_unexpected_token_span = Some(self.span);
+ let mut err = self.fatal(&msg_exp);
+ if self.token.is_ident_named(sym::and) {
+ err.span_suggestion_short(
+ self.span,
+ "use `&&` instead of `and` for the boolean operator",
+ "&&".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ if self.token.is_ident_named(sym::or) {
+ err.span_suggestion_short(
+ self.span,
+ "use `||` instead of `or` for the boolean operator",
+ "||".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ let sp = if self.token == token::Token::Eof {
+ // This is EOF, don't want to point at the following char, but rather the last token
+ self.prev_span
+ } else {
+ label_sp
+ };
+ match self.recover_closing_delimiter(&expected.iter().filter_map(|tt| match tt {
+ TokenType::Token(t) => Some(t.clone()),
+ _ => None,
+ }).collect::<Vec<_>>(), err) {
+ Err(e) => err = e,
+ Ok(recovered) => {
+ return Ok(recovered);
+ }
+ }
+
+ let is_semi_suggestable = expected.iter().any(|t| match t {
+ TokenType::Token(token::Semi) => true, // we expect a `;` here
+ _ => false,
+ }) && ( // a `;` would be expected before the current keyword
+ self.token.is_keyword(kw::Break) ||
+ self.token.is_keyword(kw::Continue) ||
+ self.token.is_keyword(kw::For) ||
+ self.token.is_keyword(kw::If) ||
+ self.token.is_keyword(kw::Let) ||
+ self.token.is_keyword(kw::Loop) ||
+ self.token.is_keyword(kw::Match) ||
+ self.token.is_keyword(kw::Return) ||
+ self.token.is_keyword(kw::While)
+ );
+ let cm = self.sess.source_map();
+ match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) {
+ (Ok(ref a), Ok(ref b)) if a.line != b.line && is_semi_suggestable => {
+ // The spans are in different lines, expected `;` and found `let` or `return`.
+ // High likelihood that it is only a missing `;`.
+ err.span_suggestion_short(
+ label_sp,
+ "a semicolon may be missing here",
+ ";".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ err.emit();
+ return Ok(true);
+ }
+ (Ok(ref a), Ok(ref b)) if a.line == b.line => {
+ // When the spans are in the same line, it means that the only content between
+ // them is whitespace, point at the found token in that case:
+ //
+ // X | () => { syntax error };
+ // | ^^^^^ expected one of 8 possible tokens here
+ //
+ // instead of having:
+ //
+ // X | () => { syntax error };
+ // | -^^^^^ unexpected token
+ // | |
+ // | expected one of 8 possible tokens here
+ err.span_label(self.span, label_exp);
+ }
+ _ if self.prev_span == syntax_pos::DUMMY_SP => {
+ // Account for macro context where the previous span might not be
+ // available to avoid incorrect output (#54841).
+ err.span_label(self.span, "unexpected token");
+ }
+ _ => {
+ err.span_label(sp, label_exp);
+ err.span_label(self.span, "unexpected token");
+ }
+ }
+ Err(err)
+ }
+
+ /// Eats and discards tokens until one of `kets` is encountered. Respects token trees,
+ /// passes through any errors encountered. Used for error recovery.
+ crate fn eat_to_tokens(&mut self, kets: &[&token::Token]) {
+ let handler = self.diagnostic();
+
+ if let Err(ref mut err) = self.parse_seq_to_before_tokens(
+ kets,
+ SeqSep::none(),
+ TokenExpectType::Expect,
+ |p| Ok(p.parse_token_tree()),
+ ) {
+ handler.cancel(err);
+ }
+ }
+
+ /// This function checks if there are trailing angle brackets and produces
+ /// a diagnostic to suggest removing them.
+ ///
+ /// ```ignore (diagnostic)
+ /// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
+ /// ^^ help: remove extra angle brackets
+ /// ```
+ crate fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: token::Token) {
+ // This function is intended to be invoked after parsing a path segment where there are two
+ // cases:
+ //
+ // 1. A specific token is expected after the path segment.
+ // eg. `x.foo(`, `x.foo::<u32>(` (parenthesis - method call),
+ // `Foo::`, or `Foo::<Bar>::` (mod sep - continued path).
+ // 2. No specific token is expected after the path segment.
+ // eg. `x.foo` (field access)
+ //
+ // This function is called after parsing `.foo` and before parsing the token `end` (if
+ // present). This includes any angle bracket arguments, such as `.foo::<u32>` or
+ // `Foo::<Bar>`.
+
+ // We only care about trailing angle brackets if we previously parsed angle bracket
+ // arguments. This helps stop us incorrectly suggesting that extra angle brackets be
+ // removed in this case:
+ //
+ // `x.foo >> (3)` (where `x.foo` is a `u32` for example)
+ //
+ // This case is particularly tricky as we won't notice it just looking at the tokens -
+ // it will appear the same (in terms of upcoming tokens) as below (since the `::<u32>` will
+ // have already been parsed):
+ //
+ // `x.foo::<u32>>>(3)`
+ let parsed_angle_bracket_args = segment.args
+ .as_ref()
+ .map(|args| args.is_angle_bracketed())
+ .unwrap_or(false);
+
+ debug!(
+ "check_trailing_angle_brackets: parsed_angle_bracket_args={:?}",
+ parsed_angle_bracket_args,
+ );
+ if !parsed_angle_bracket_args {
+ return;
+ }
+
+ // Keep the span at the start so we can highlight the sequence of `>` characters to be
+ // removed.
+ let lo = self.span;
+
+ // We need to look-ahead to see if we have `>` characters without moving the cursor forward
+ // (since we might have the field access case and the characters we're eating are
+ // actual operators and not trailing characters - ie `x.foo >> 3`).
+ let mut position = 0;
+
+ // We can encounter `>` or `>>` tokens in any order, so we need to keep track of how
+ // many of each (so we can correctly pluralize our error messages) and continue to
+ // advance.
+ let mut number_of_shr = 0;
+ let mut number_of_gt = 0;
+ while self.look_ahead(position, |t| {
+ trace!("check_trailing_angle_brackets: t={:?}", t);
+ if *t == token::BinOp(token::BinOpToken::Shr) {
+ number_of_shr += 1;
+ true
+ } else if *t == token::Gt {
+ number_of_gt += 1;
+ true
+ } else {
+ false
+ }
+ }) {
+ position += 1;
+ }
+
+ // If we didn't find any trailing `>` characters, then we have nothing to error about.
+ debug!(
+ "check_trailing_angle_brackets: number_of_gt={:?} number_of_shr={:?}",
+ number_of_gt, number_of_shr,
+ );
+ if number_of_gt < 1 && number_of_shr < 1 {
+ return;
+ }
+
+ // Finally, double check that we have our end token as otherwise this is the
+ // second case.
+ if self.look_ahead(position, |t| {
+ trace!("check_trailing_angle_brackets: t={:?}", t);
+ *t == end
+ }) {
+ // Eat from where we started until the end token so that parsing can continue
+ // as if we didn't have those extra angle brackets.
+ self.eat_to_tokens(&[&end]);
+ let span = lo.until(self.span);
+
+ let plural = number_of_gt > 1 || number_of_shr >= 1;
+ self.diagnostic()
+ .struct_span_err(
+ span,
+ &format!("unmatched angle bracket{}", if plural { "s" } else { "" }),
+ )
+ .span_suggestion(
+ span,
+ &format!("remove extra angle bracket{}", if plural { "s" } else { "" }),
+ String::new(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ }
+ }
+
+ /// Produce an error if comparison operators are chained (RFC #558).
+ /// We only need to check lhs, not rhs, because all comparison ops
+ /// have same precedence and are left-associative
+ crate fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) {
+ debug_assert!(outer_op.is_comparison(),
+ "check_no_chained_comparison: {:?} is not comparison",
+ outer_op);
+ match lhs.node {
+ ExprKind::Binary(op, _, _) if op.node.is_comparison() => {
+ // respan to include both operators
+ let op_span = op.span.to(self.span);
+ let mut err = self.diagnostic().struct_span_err(op_span,
+ "chained comparison operators require parentheses");
+ if op.node == BinOpKind::Lt &&
+ *outer_op == AssocOp::Less || // Include `<` to provide this recommendation
+ *outer_op == AssocOp::Greater // even in a case like the following:
+ { // Foo<Bar<Baz<Qux, ()>>>
+ err.help(
+ "use `::<...>` instead of `<...>` if you meant to specify type arguments");
+ err.help("or use `(...)` if you meant to specify fn arguments");
+ }
+ err.emit();
+ }
+ _ => {}
+ }
+ }
+
crate fn maybe_report_ambiguous_plus(
&mut self,
allow_plus: bool,
let mut path = ast::Path {
segments: Vec::new(),
- span: syntax_pos::DUMMY_SP,
+ span: DUMMY_SP,
};
self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
path.span = ty_span.to(self.prev_span);
}
}
+ /// Create a `DiagnosticBuilder` for an unexpected token `t` and try to recover if it is a
+ /// closing delimiter.
+ pub fn unexpected_try_recover(
+ &mut self,
+ t: &token::Token,
+ ) -> PResult<'a, bool /* recovered */> {
+ let token_str = pprust::token_to_string(t);
+ let this_token_str = self.this_token_descr();
+ let (prev_sp, sp) = match (&self.token, self.subparser_name) {
+ // Point at the end of the macro call when reaching end of macro arguments.
+ (token::Token::Eof, Some(_)) => {
+ let sp = self.sess.source_map().next_point(self.span);
+ (sp, sp)
+ }
+ // We don't want to point at the following span after DUMMY_SP.
+ // This happens when the parser finds an empty TokenStream.
+ _ if self.prev_span == DUMMY_SP => (self.span, self.span),
+ // EOF, don't want to point at the following char, but rather the last token.
+ (token::Token::Eof, None) => (self.prev_span, self.span),
+ _ => (self.sess.source_map().next_point(self.prev_span), self.span),
+ };
+ let msg = format!(
+ "expected `{}`, found {}",
+ token_str,
+ match (&self.token, self.subparser_name) {
+ (token::Token::Eof, Some(origin)) => format!("end of {}", origin),
+ _ => this_token_str,
+ },
+ );
+ let mut err = self.struct_span_err(sp, &msg);
+ let label_exp = format!("expected `{}`", token_str);
+ match self.recover_closing_delimiter(&[t.clone()], err) {
+ Err(e) => err = e,
+ Ok(recovered) => {
+ return Ok(recovered);
+ }
+ }
+ let cm = self.sess.source_map();
+ match (cm.lookup_line(prev_sp.lo()), cm.lookup_line(sp.lo())) {
+ (Ok(ref a), Ok(ref b)) if a.line == b.line => {
+ // When the spans are in the same line, it means that the only content
+ // between them is whitespace, point only at the found token.
+ err.span_label(sp, label_exp);
+ }
+ _ => {
+ err.span_label(prev_sp, label_exp);
+ err.span_label(sp, "unexpected token");
+ }
+ }
+ Err(err)
+ }
+
/// Consume alternative await syntaxes like `await <expr>`, `await? <expr>`, `await(<expr>)`
/// and `await { <expr> }`.
crate fn parse_incorrect_await_syntax(
}
}
+ crate fn check_for_for_in_in_typo(&mut self, in_span: Span) {
+ if self.eat_keyword(kw::In) {
+ // a common typo: `for _ in in bar {}`
+ let mut err = self.sess.span_diagnostic.struct_span_err(
+ self.prev_span,
+ "expected iterable, found keyword `in`",
+ );
+ err.span_suggestion_short(
+ in_span.until(self.prev_span),
+ "remove the duplicated `in`",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ err.emit();
+ }
+ }
+
+ crate fn expected_semi_or_open_brace(&mut self) -> PResult<'a, ast::TraitItem> {
+ let token_str = self.this_token_descr();
+ let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str));
+ err.span_label(self.span, "expected `;` or `{`");
+ Err(err)
+ }
+
+ crate fn eat_incorrect_doc_comment(&mut self, applied_to: &str) {
+ if let token::DocComment(_) = self.token {
+ let mut err = self.diagnostic().struct_span_err(
+ self.span,
+ &format!("documentation comments cannot be applied to {}", applied_to),
+ );
+ err.span_label(self.span, "doc comments are not allowed here");
+ err.emit();
+ self.bump();
+ } else if self.token == token::Pound && self.look_ahead(1, |t| {
+ *t == token::OpenDelim(token::Bracket)
+ }) {
+ let lo = self.span;
+ // Skip every token until next possible arg.
+ while self.token != token::CloseDelim(token::Bracket) {
+ self.bump();
+ }
+ let sp = lo.to(self.span);
+ self.bump();
+ let mut err = self.diagnostic().struct_span_err(
+ sp,
+ &format!("attributes cannot be applied to {}", applied_to),
+ );
+ err.span_label(sp, "attributes are not allowed here");
+ err.emit();
+ }
+ }
+
+ crate fn argument_without_type(
+ &mut self,
+ err: &mut DiagnosticBuilder<'_>,
+ pat: P<ast::Pat>,
+ require_name: bool,
+ is_trait_item: bool,
+ ) {
+ // If we find a pattern followed by an identifier, it could be an (incorrect)
+ // C-style parameter declaration.
+ if self.check_ident() && self.look_ahead(1, |t| {
+ *t == token::Comma || *t == token::CloseDelim(token::Paren)
+ }) {
+ let ident = self.parse_ident().unwrap();
+ let span = pat.span.with_hi(ident.span.hi());
+
+ err.span_suggestion(
+ span,
+ "declare the type after the parameter binding",
+ String::from("<identifier>: <type>"),
+ Applicability::HasPlaceholders,
+ );
+ } else if require_name && is_trait_item {
+ if let PatKind::Ident(_, ident, _) = pat.node {
+ err.span_suggestion(
+ pat.span,
+ "explicitly ignore parameter",
+ format!("_: {}", ident),
+ Applicability::MachineApplicable,
+ );
+ }
+
+ err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)");
+ }
+ }
+
+ crate fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> {
+ let pat = self.parse_pat(Some("argument name"))?;
+ self.expect(&token::Colon)?;
+ let ty = self.parse_ty()?;
+
+ let mut err = self.diagnostic().struct_span_err_with_code(
+ pat.span,
+ "patterns aren't allowed in methods without bodies",
+ DiagnosticId::Error("E0642".into()),
+ );
+ err.span_suggestion_short(
+ pat.span,
+ "give this argument a name or use an underscore to ignore it",
+ "_".to_owned(),
+ Applicability::MachineApplicable,
+ );
+ err.emit();
+
+ // Pretend the pattern is `_`, to avoid duplicate errors from AST validation.
+ let pat = P(Pat {
+ node: PatKind::Wild,
+ span: pat.span,
+ id: ast::DUMMY_NODE_ID
+ });
+ Ok((pat, ty))
+ }
+
+ crate fn recover_bad_self_arg(
+ &mut self,
+ mut arg: ast::Arg,
+ is_trait_item: bool,
+ ) -> PResult<'a, ast::Arg> {
+ let sp = arg.pat.span;
+ arg.ty.node = TyKind::Err;
+ let mut err = self.struct_span_err(sp, "unexpected `self` parameter in function");
+ if is_trait_item {
+ err.span_label(sp, "must be the first associated function parameter");
+ } else {
+ err.span_label(sp, "not valid as function parameter");
+ err.note("`self` is only valid as the first parameter of an associated function");
+ }
+ err.emit();
+ Ok(arg)
+ }
+
crate fn consume_block(&mut self, delim: token::DelimToken) {
let mut brace_depth = 0;
loop {
}
}
+ crate fn expected_expression_found(&self) -> DiagnosticBuilder<'a> {
+ let (span, msg) = match (&self.token, self.subparser_name) {
+ (&token::Token::Eof, Some(origin)) => {
+ let sp = self.sess.source_map().next_point(self.span);
+ (sp, format!("expected expression, found end of {}", origin))
+ }
+ _ => (self.span, format!(
+ "expected expression, found {}",
+ self.this_token_descr(),
+ )),
+ };
+ let mut err = self.struct_span_err(span, &msg);
+ let sp = self.sess.source_map().start_point(self.span);
+ if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
+ self.sess.expr_parentheses_needed(&mut err, *sp, None);
+ }
+ err.span_label(span, "expected expression");
+ err
+ }
}
use crate::ast::{self, Ident};
use crate::parse::ParseSess;
use crate::parse::token::{self, Token};
-use crate::symbol::Symbol;
+use crate::symbol::{sym, Symbol};
use crate::parse::unescape;
use crate::parse::unescape_error_reporting::{emit_unescape_error, push_escaped_char};
}
_ => {
// just a 0
- return (token::Integer, self.name_from(start_bpos));
+ return (token::Integer, sym::integer(0));
}
}
} else if c.is_digit(10) {
/// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
pub fn to_lit_token(&self) -> token::Lit {
let (kind, symbol, suffix) = match *self {
- LitKind::Str(string, ast::StrStyle::Cooked) => {
- let escaped = string.as_str().escape_default().to_string();
- (token::Str, Symbol::intern(&escaped), None)
+ LitKind::Str(symbol, ast::StrStyle::Cooked) => {
+ // Don't re-intern unless the escaped string is different.
+ let s = &symbol.as_str();
+ let escaped = s.escape_default().to_string();
+ let symbol = if escaped == *s { symbol } else { Symbol::intern(&escaped) };
+ (token::Str, symbol, None)
}
- LitKind::Str(string, ast::StrStyle::Raw(n)) => {
- (token::StrRaw(n), string, None)
+ LitKind::Str(symbol, ast::StrStyle::Raw(n)) => {
+ (token::StrRaw(n), symbol, None)
}
LitKind::ByteStr(ref bytes) => {
let string = bytes.iter().cloned().flat_map(ascii::escape_default)
}
LitKind::Int(n, ty) => {
let suffix = match ty {
- ast::LitIntType::Unsigned(ty) => Some(Symbol::intern(ty.ty_to_string())),
- ast::LitIntType::Signed(ty) => Some(Symbol::intern(ty.ty_to_string())),
+ ast::LitIntType::Unsigned(ty) => Some(ty.to_symbol()),
+ ast::LitIntType::Signed(ty) => Some(ty.to_symbol()),
ast::LitIntType::Unsuffixed => None,
};
- (token::Integer, Symbol::intern(&n.to_string()), suffix)
+ (token::Integer, sym::integer(n), suffix)
}
LitKind::Float(symbol, ty) => {
- (token::Float, symbol, Some(Symbol::intern(ty.ty_to_string())))
+ (token::Float, symbol, Some(ty.to_symbol()))
}
LitKind::FloatUnsuffixed(symbol) => {
(token::Float, symbol, None)
) -> Result<Parser<'_>, Vec<Diagnostic>> {
let end_pos = source_file.end_pos;
let (stream, unclosed_delims) = maybe_file_to_stream(sess, source_file, None)?;
- let mut parser = stream_to_parser(sess, stream);
+ let mut parser = stream_to_parser(sess, stream, None);
parser.unclosed_delims = unclosed_delims;
if parser.token == token::Eof && parser.span.is_dummy() {
parser.span = Span::new(end_pos, end_pos, parser.span.ctxt());
// must preserve old name for now, because quote! from the *existing*
// compiler expands into it
pub fn new_parser_from_tts(sess: &ParseSess, tts: Vec<TokenTree>) -> Parser<'_> {
- stream_to_parser(sess, tts.into_iter().collect())
+ stream_to_parser(sess, tts.into_iter().collect(), crate::MACRO_ARGUMENTS)
}
}
/// Given stream and the `ParseSess`, produces a parser.
-pub fn stream_to_parser(sess: &ParseSess, stream: TokenStream) -> Parser<'_> {
- Parser::new(sess, stream, None, true, false)
+pub fn stream_to_parser<'a>(
+ sess: &'a ParseSess,
+ stream: TokenStream,
+ subparser_name: Option<&'static str>,
+) -> Parser<'a> {
+ Parser::new(sess, stream, None, true, false, subparser_name)
}
/// Given stream, the `ParseSess` and the base directory, produces a parser.
/// The main usage of this function is outside of rustc, for those who uses
/// libsyntax as a library. Please do not remove this function while refactoring
/// just because it is not used in rustc codebase!
-pub fn stream_to_parser_with_base_dir<'a>(sess: &'a ParseSess,
- stream: TokenStream,
- base_dir: Directory<'a>) -> Parser<'a> {
- Parser::new(sess, stream, Some(base_dir), true, false)
+pub fn stream_to_parser_with_base_dir<'a>(
+ sess: &'a ParseSess,
+ stream: TokenStream,
+ base_dir: Directory<'a>,
+) -> Parser<'a> {
+ Parser::new(sess, stream, Some(base_dir), true, false, None)
}
/// A sequence separator.
use crate::ThinVec;
use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
use crate::symbol::{kw, sym, Symbol};
+use crate::parse::diagnostics::Error;
use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError};
use rustc_target::spec::abi::{self, Abi};
-use syntax_pos::{
- Span, MultiSpan, BytePos, FileName,
- hygiene::CompilerDesugaringKind,
-};
-use log::{debug, trace};
+use syntax_pos::{Span, BytePos, DUMMY_SP, FileName, hygiene::CompilerDesugaringKind};
+use log::debug;
use std::borrow::Cow;
use std::cmp;
/// into modules, and sub-parsers have new values for this name.
pub root_module_name: Option<String>,
crate expected_tokens: Vec<TokenType>,
- token_cursor: TokenCursor,
+ crate token_cursor: TokenCursor,
desugar_doc_comments: bool,
/// Whether we should configure out of line modules as we parse.
pub cfg_mods: bool,
/// it gets removed from here. Every entry left at the end gets emitted as an independent
/// error.
crate unclosed_delims: Vec<UnmatchedBrace>,
- last_unexpected_token_span: Option<Span>,
+ crate last_unexpected_token_span: Option<Span>,
+ /// If present, this `Parser` is not parsing Rust code but rather a macro call.
+ crate subparser_name: Option<&'static str>,
}
impl<'a> Drop for Parser<'a> {
}
#[derive(Clone)]
-struct TokenCursor {
- frame: TokenCursorFrame,
- stack: Vec<TokenCursorFrame>,
+crate struct TokenCursor {
+ crate frame: TokenCursorFrame,
+ crate stack: Vec<TokenCursorFrame>,
}
#[derive(Clone)]
-struct TokenCursorFrame {
- delim: token::DelimToken,
- span: DelimSpan,
- open_delim: bool,
- tree_cursor: tokenstream::Cursor,
- close_delim: bool,
- last_token: LastToken,
+crate struct TokenCursorFrame {
+ crate delim: token::DelimToken,
+ crate span: DelimSpan,
+ crate open_delim: bool,
+ crate tree_cursor: tokenstream::Cursor,
+ crate close_delim: bool,
+ crate last_token: LastToken,
}
/// This is used in `TokenCursorFrame` above to track tokens that are consumed
/// You can find some more example usage of this in the `collect_tokens` method
/// on the parser.
#[derive(Clone)]
-enum LastToken {
+crate enum LastToken {
Collecting(Vec<TreeAndJoint>),
Was(Option<TreeAndJoint>),
}
self.frame = frame;
continue
} else {
- return TokenAndSpan { tok: token::Eof, sp: syntax_pos::DUMMY_SP }
+ return TokenAndSpan { tok: token::Eof, sp: DUMMY_SP }
};
match self.frame.last_token {
warn: bool,
}
-pub enum Error {
- FileNotFoundForModule {
- mod_name: String,
- default_path: String,
- secondary_path: String,
- dir_path: String,
- },
- DuplicatePaths {
- mod_name: String,
- default_path: String,
- secondary_path: String,
- },
- UselessDocComment,
- InclusiveRangeWithNoEnd,
-}
-
-impl Error {
- fn span_err<S: Into<MultiSpan>>(self,
- sp: S,
- handler: &errors::Handler) -> DiagnosticBuilder<'_> {
- match self {
- Error::FileNotFoundForModule { ref mod_name,
- ref default_path,
- ref secondary_path,
- ref dir_path } => {
- let mut err = struct_span_err!(handler, sp, E0583,
- "file not found for module `{}`", mod_name);
- err.help(&format!("name the file either {} or {} inside the directory \"{}\"",
- default_path,
- secondary_path,
- dir_path));
- err
- }
- Error::DuplicatePaths { ref mod_name, ref default_path, ref secondary_path } => {
- let mut err = struct_span_err!(handler, sp, E0584,
- "file for module `{}` found at both {} and {}",
- mod_name,
- default_path,
- secondary_path);
- err.help("delete or rename one of them to remove the ambiguity");
- err
- }
- Error::UselessDocComment => {
- let mut err = struct_span_err!(handler, sp, E0585,
- "found a documentation comment that doesn't document anything");
- err.help("doc comments must come before what they document, maybe a comment was \
- intended with `//`?");
- err
- }
- Error::InclusiveRangeWithNoEnd => {
- let mut err = struct_span_err!(handler, sp, E0586,
- "inclusive range with no end");
- err.help("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)");
- err
- }
- }
- }
-}
-
#[derive(Debug)]
enum LhsExpr {
NotYetParsed,
}
#[derive(Copy, Clone, Debug)]
-enum TokenExpectType {
+crate enum TokenExpectType {
Expect,
NoExpect,
}
impl<'a> Parser<'a> {
- pub fn new(sess: &'a ParseSess,
- tokens: TokenStream,
- directory: Option<Directory<'a>>,
- recurse_into_file_modules: bool,
- desugar_doc_comments: bool)
- -> Self {
+ pub fn new(
+ sess: &'a ParseSess,
+ tokens: TokenStream,
+ directory: Option<Directory<'a>>,
+ recurse_into_file_modules: bool,
+ desugar_doc_comments: bool,
+ subparser_name: Option<&'static str>,
+ ) -> Self {
let mut parser = Parser {
sess,
token: token::Whitespace,
- span: syntax_pos::DUMMY_SP,
- prev_span: syntax_pos::DUMMY_SP,
+ span: DUMMY_SP,
+ prev_span: DUMMY_SP,
meta_var_span: None,
prev_token_kind: PrevTokenKind::Other,
restrictions: Restrictions::empty(),
max_angle_bracket_count: 0,
unclosed_delims: Vec::new(),
last_unexpected_token_span: None,
+ subparser_name,
};
let tok = parser.next_tok();
pprust::token_to_string(&self.token)
}
- fn token_descr(&self) -> Option<&'static str> {
+ crate fn token_descr(&self) -> Option<&'static str> {
Some(match &self.token {
t if t.is_special_ident() => "reserved identifier",
t if t.is_used_keyword() => "keyword",
}
/// Expects and consumes the token `t`. Signals an error if the next token is not `t`.
- pub fn expect(&mut self, t: &token::Token) -> PResult<'a, bool /* recovered */> {
+ pub fn expect(&mut self, t: &token::Token) -> PResult<'a, bool /* recovered */> {
if self.expected_tokens.is_empty() {
if self.token == *t {
self.bump();
Ok(false)
} else {
- let token_str = pprust::token_to_string(t);
- let this_token_str = self.this_token_descr();
- let mut err = self.fatal(&format!("expected `{}`, found {}",
- token_str,
- this_token_str));
-
- let sp = if self.token == token::Token::Eof {
- // EOF, don't want to point at the following char, but rather the last token
- self.prev_span
- } else {
- self.sess.source_map().next_point(self.prev_span)
- };
- let label_exp = format!("expected `{}`", token_str);
- match self.recover_closing_delimiter(&[t.clone()], err) {
- Err(e) => err = e,
- Ok(recovered) => {
- return Ok(recovered);
- }
- }
- let cm = self.sess.source_map();
- match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) {
- (Ok(ref a), Ok(ref b)) if a.line == b.line => {
- // When the spans are in the same line, it means that the only content
- // between them is whitespace, point only at the found token.
- err.span_label(self.span, label_exp);
- }
- _ => {
- err.span_label(sp, label_exp);
- err.span_label(self.span, "unexpected token");
- }
- }
- Err(err)
+ self.unexpected_try_recover(t)
}
} else {
self.expect_one_of(slice::from_ref(t), &[])
edible: &[token::Token],
inedible: &[token::Token],
) -> PResult<'a, bool /* recovered */> {
- fn tokens_to_string(tokens: &[TokenType]) -> String {
- let mut i = tokens.iter();
- // This might be a sign we need a connect method on Iterator.
- let b = i.next()
- .map_or(String::new(), |t| t.to_string());
- i.enumerate().fold(b, |mut b, (i, a)| {
- if tokens.len() > 2 && i == tokens.len() - 2 {
- b.push_str(", or ");
- } else if tokens.len() == 2 && i == tokens.len() - 2 {
- b.push_str(" or ");
- } else {
- b.push_str(", ");
- }
- b.push_str(&a.to_string());
- b
- })
- }
if edible.contains(&self.token) {
self.bump();
Ok(false)
} else if self.last_unexpected_token_span == Some(self.span) {
FatalError.raise();
} else {
- let mut expected = edible.iter()
- .map(|x| TokenType::Token(x.clone()))
- .chain(inedible.iter().map(|x| TokenType::Token(x.clone())))
- .chain(self.expected_tokens.iter().cloned())
- .collect::<Vec<_>>();
- expected.sort_by_cached_key(|x| x.to_string());
- expected.dedup();
- let expect = tokens_to_string(&expected[..]);
- let actual = self.this_token_to_string();
- let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
- let short_expect = if expected.len() > 6 {
- format!("{} possible tokens", expected.len())
- } else {
- expect.clone()
- };
- (format!("expected one of {}, found `{}`", expect, actual),
- (self.sess.source_map().next_point(self.prev_span),
- format!("expected one of {} here", short_expect)))
- } else if expected.is_empty() {
- (format!("unexpected token: `{}`", actual),
- (self.prev_span, "unexpected token after this".to_string()))
- } else {
- (format!("expected {}, found `{}`", expect, actual),
- (self.sess.source_map().next_point(self.prev_span),
- format!("expected {} here", expect)))
- };
- self.last_unexpected_token_span = Some(self.span);
- let mut err = self.fatal(&msg_exp);
- if self.token.is_ident_named("and") {
- err.span_suggestion_short(
- self.span,
- "use `&&` instead of `and` for the boolean operator",
- "&&".to_string(),
- Applicability::MaybeIncorrect,
- );
- }
- if self.token.is_ident_named("or") {
- err.span_suggestion_short(
- self.span,
- "use `||` instead of `or` for the boolean operator",
- "||".to_string(),
- Applicability::MaybeIncorrect,
- );
- }
- let sp = if self.token == token::Token::Eof {
- // This is EOF, don't want to point at the following char, but rather the last token
- self.prev_span
- } else {
- label_sp
- };
- match self.recover_closing_delimiter(&expected.iter().filter_map(|tt| match tt {
- TokenType::Token(t) => Some(t.clone()),
- _ => None,
- }).collect::<Vec<_>>(), err) {
- Err(e) => err = e,
- Ok(recovered) => {
- return Ok(recovered);
- }
- }
-
- let is_semi_suggestable = expected.iter().any(|t| match t {
- TokenType::Token(token::Semi) => true, // we expect a `;` here
- _ => false,
- }) && ( // a `;` would be expected before the current keyword
- self.token.is_keyword(kw::Break) ||
- self.token.is_keyword(kw::Continue) ||
- self.token.is_keyword(kw::For) ||
- self.token.is_keyword(kw::If) ||
- self.token.is_keyword(kw::Let) ||
- self.token.is_keyword(kw::Loop) ||
- self.token.is_keyword(kw::Match) ||
- self.token.is_keyword(kw::Return) ||
- self.token.is_keyword(kw::While)
- );
- let cm = self.sess.source_map();
- match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) {
- (Ok(ref a), Ok(ref b)) if a.line != b.line && is_semi_suggestable => {
- // The spans are in different lines, expected `;` and found `let` or `return`.
- // High likelihood that it is only a missing `;`.
- err.span_suggestion_short(
- label_sp,
- "a semicolon may be missing here",
- ";".to_string(),
- Applicability::MaybeIncorrect,
- );
- err.emit();
- return Ok(true);
- }
- (Ok(ref a), Ok(ref b)) if a.line == b.line => {
- // When the spans are in the same line, it means that the only content between
- // them is whitespace, point at the found token in that case:
- //
- // X | () => { syntax error };
- // | ^^^^^ expected one of 8 possible tokens here
- //
- // instead of having:
- //
- // X | () => { syntax error };
- // | -^^^^^ unexpected token
- // | |
- // | expected one of 8 possible tokens here
- err.span_label(self.span, label_exp);
- }
- _ if self.prev_span == syntax_pos::DUMMY_SP => {
- // Account for macro context where the previous span might not be
- // available to avoid incorrect output (#54841).
- err.span_label(self.span, "unexpected token");
- }
- _ => {
- err.span_label(sp, label_exp);
- err.span_label(self.span, "unexpected token");
- }
- }
- Err(err)
+ self.expected_one_of_not_found(edible, inedible)
}
}
/// Returns the span of expr, if it was not interpolated or the span of the interpolated token.
- fn interpolated_or_expr_span(&self,
- expr: PResult<'a, P<Expr>>)
- -> PResult<'a, (Span, P<Expr>)> {
+ fn interpolated_or_expr_span(
+ &self,
+ expr: PResult<'a, P<Expr>>,
+ ) -> PResult<'a, (Span, P<Expr>)> {
expr.map(|e| {
if self.prev_token_kind == PrevTokenKind::Interpolated {
(self.prev_span, e)
})
}
- fn expected_ident_found(&self) -> DiagnosticBuilder<'a> {
- let mut err = self.struct_span_err(self.span,
- &format!("expected identifier, found {}",
- self.this_token_descr()));
- if let token::Ident(ident, false) = &self.token {
- if ident.is_raw_guess() {
- err.span_suggestion(
- self.span,
- "you can escape reserved keywords to use them as identifiers",
- format!("r#{}", ident),
- Applicability::MaybeIncorrect,
- );
- }
- }
- if let Some(token_descr) = self.token_descr() {
- err.span_label(self.span, format!("expected identifier, found {}", token_descr));
- } else {
- err.span_label(self.span, "expected identifier");
- if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) {
- err.span_suggestion(
- self.span,
- "remove this comma",
- String::new(),
- Applicability::MachineApplicable,
- );
- }
- }
- err
- }
-
pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> {
self.parse_ident_common(true)
}
}
}
- fn check_ident(&mut self) -> bool {
+ crate fn check_ident(&mut self) -> bool {
if self.token.is_ident() {
true
} else {
}
}
- /// Eats and discards tokens until one of `kets` is encountered. Respects token trees,
- /// passes through any errors encountered. Used for error recovery.
- fn eat_to_tokens(&mut self, kets: &[&token::Token]) {
- let handler = self.diagnostic();
-
- if let Err(ref mut err) = self.parse_seq_to_before_tokens(kets,
- SeqSep::none(),
- TokenExpectType::Expect,
- |p| Ok(p.parse_token_tree())) {
- handler.cancel(err);
- }
- }
-
/// Parses a sequence, including the closing delimiter. The function
/// `f` must consume tokens until reaching the next separator or
/// closing bracket.
self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f)
}
- fn parse_seq_to_before_tokens<T, F>(
+ crate fn parse_seq_to_before_tokens<T, F>(
&mut self,
kets: &[&token::Token],
sep: SeqSep,
None => self.look_ahead_span(dist - 1),
}
}
- pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> {
- self.sess.span_diagnostic.struct_span_fatal(self.span, m)
- }
- pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
- self.sess.span_diagnostic.struct_span_fatal(sp, m)
- }
- fn span_fatal_err<S: Into<MultiSpan>>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> {
- err.span_err(sp, self.diagnostic())
- }
- fn bug(&self, m: &str) -> ! {
- self.sess.span_diagnostic.span_bug(self.span, m)
- }
- fn span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) {
- self.sess.span_diagnostic.span_err(sp, m)
- }
- crate fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
- self.sess.span_diagnostic.struct_span_err(sp, m)
- }
- crate fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> ! {
- self.sess.span_diagnostic.span_bug(sp, m)
- }
-
- fn cancel(&self, err: &mut DiagnosticBuilder<'_>) {
- self.sess.span_diagnostic.cancel(err)
- }
-
- crate fn diagnostic(&self) -> &'a errors::Handler {
- &self.sess.span_diagnostic
- }
/// Is the current token one of the keywords that signals a bare function type?
fn token_is_bare_fn_keyword(&mut self) -> bool {
Some(body)
}
_ => {
- let token_str = self.this_token_descr();
- let mut err = self.fatal(&format!("expected `;` or `{{`, found {}",
- token_str));
- err.span_label(self.span, "expected `;` or `{`");
- return Err(err);
+ return self.expected_semi_or_open_brace();
}
}
}
_ => {
- let token_str = self.this_token_descr();
- let mut err = self.fatal(&format!("expected `;` or `{{`, found {}",
- token_str));
- err.span_label(self.span, "expected `;` or `{`");
- return Err(err);
+ return self.expected_semi_or_open_brace();
}
};
(ident, ast::TraitItemKind::Method(sig, body), generics)
/// Skips unexpected attributes and doc comments in this position and emits an appropriate
/// error.
- fn eat_incorrect_doc_comment(&mut self, applied_to: &str) {
- if let token::DocComment(_) = self.token {
- let mut err = self.diagnostic().struct_span_err(
- self.span,
- &format!("documentation comments cannot be applied to {}", applied_to),
- );
- err.span_label(self.span, "doc comments are not allowed here");
- err.emit();
- self.bump();
- } else if self.token == token::Pound && self.look_ahead(1, |t| {
- *t == token::OpenDelim(token::Bracket)
- }) {
- let lo = self.span;
- // Skip every token until next possible arg.
- while self.token != token::CloseDelim(token::Bracket) {
- self.bump();
- }
- let sp = lo.to(self.span);
- self.bump();
- let mut err = self.diagnostic().struct_span_err(
- sp,
- &format!("attributes cannot be applied to {}", applied_to),
- );
- err.span_label(sp, "attributes are not allowed here");
- err.emit();
- }
- }
-
/// This version of parse arg doesn't necessarily require identifier names.
- fn parse_arg_general(&mut self, require_name: bool, is_trait_item: bool,
- allow_c_variadic: bool) -> PResult<'a, Arg> {
- if let Ok(Some(_)) = self.parse_self_arg() {
- let mut err = self.struct_span_err(self.prev_span,
- "unexpected `self` argument in function");
- err.span_label(self.prev_span,
- "`self` is only valid as the first argument of an associated function");
- return Err(err);
+ fn parse_arg_general(
+ &mut self,
+ require_name: bool,
+ is_trait_item: bool,
+ allow_c_variadic: bool,
+ ) -> PResult<'a, Arg> {
+ if let Ok(Some(arg)) = self.parse_self_arg() {
+ return self.recover_bad_self_arg(arg, is_trait_item);
}
let (pat, ty) = if require_name || self.is_named_argument() {
- debug!("parse_arg_general parse_pat (require_name:{})",
- require_name);
+ debug!("parse_arg_general parse_pat (require_name:{})", require_name);
self.eat_incorrect_doc_comment("method arguments");
let pat = self.parse_pat(Some("argument name"))?;
if let Err(mut err) = self.expect(&token::Colon) {
- // If we find a pattern followed by an identifier, it could be an (incorrect)
- // C-style parameter declaration.
- if self.check_ident() && self.look_ahead(1, |t| {
- *t == token::Comma || *t == token::CloseDelim(token::Paren)
- }) {
- let ident = self.parse_ident().unwrap();
- let span = pat.span.with_hi(ident.span.hi());
-
- err.span_suggestion(
- span,
- "declare the type after the parameter binding",
- String::from("<identifier>: <type>"),
- Applicability::HasPlaceholders,
- );
- } else if require_name && is_trait_item {
- if let PatKind::Ident(_, ident, _) = pat.node {
- err.span_suggestion(
- pat.span,
- "explicitly ignore parameter",
- format!("_: {}", ident),
- Applicability::MachineApplicable,
- );
- }
-
- err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)");
- }
-
+ self.argument_without_type(&mut err, pat, require_name, is_trait_item);
return Err(err);
}
// Recover from attempting to parse the argument as a type without pattern.
err.cancel();
mem::replace(self, parser_snapshot_before_ty);
- let pat = self.parse_pat(Some("argument name"))?;
- self.expect(&token::Colon)?;
- let ty = self.parse_ty()?;
-
- let mut err = self.diagnostic().struct_span_err_with_code(
- pat.span,
- "patterns aren't allowed in methods without bodies",
- DiagnosticId::Error("E0642".into()),
- );
- err.span_suggestion_short(
- pat.span,
- "give this argument a name or use an underscore to ignore it",
- "_".to_owned(),
- Applicability::MachineApplicable,
- );
- err.emit();
-
- // Pretend the pattern is `_`, to avoid duplicate errors from AST validation.
- let pat = P(Pat {
- node: PatKind::Wild,
- span: pat.span,
- id: ast::DUMMY_NODE_ID
- });
- (pat, ty)
+ self.recover_arg_parse()?
}
}
};
Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID, source: ast::ArgSource::Normal })
}
- /// Parses a single function argument.
- crate fn parse_arg(&mut self) -> PResult<'a, Arg> {
- self.parse_arg_general(true, false, false)
- }
-
/// Parses an argument in a lambda header (e.g., `|arg, arg|`).
fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> {
let pat = self.parse_pat(Some("argument name"))?;
path = self.parse_path(PathStyle::Type)?;
path_span = path_lo.to(self.prev_span);
} else {
- path = ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP };
+ path = ast::Path { segments: Vec::new(), span: DUMMY_SP };
path_span = self.span.to(self.span);
}
}
Err(mut err) => {
self.cancel(&mut err);
- let msg = format!("expected expression, found {}",
- self.this_token_descr());
- let mut err = self.fatal(&msg);
- let sp = self.sess.source_map().start_point(self.span);
- if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow()
- .get(&sp)
- {
- self.sess.expr_parentheses_needed(&mut err, *sp, None);
- }
- err.span_label(self.span, "expected expression");
- return Err(err);
+ return Err(self.expected_expression_found());
}
}
}
})
}
- /// This function checks if there are trailing angle brackets and produces
- /// a diagnostic to suggest removing them.
- ///
- /// ```ignore (diagnostic)
- /// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
- /// ^^ help: remove extra angle brackets
- /// ```
- fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: token::Token) {
- // This function is intended to be invoked after parsing a path segment where there are two
- // cases:
- //
- // 1. A specific token is expected after the path segment.
- // eg. `x.foo(`, `x.foo::<u32>(` (parenthesis - method call),
- // `Foo::`, or `Foo::<Bar>::` (mod sep - continued path).
- // 2. No specific token is expected after the path segment.
- // eg. `x.foo` (field access)
- //
- // This function is called after parsing `.foo` and before parsing the token `end` (if
- // present). This includes any angle bracket arguments, such as `.foo::<u32>` or
- // `Foo::<Bar>`.
-
- // We only care about trailing angle brackets if we previously parsed angle bracket
- // arguments. This helps stop us incorrectly suggesting that extra angle brackets be
- // removed in this case:
- //
- // `x.foo >> (3)` (where `x.foo` is a `u32` for example)
- //
- // This case is particularly tricky as we won't notice it just looking at the tokens -
- // it will appear the same (in terms of upcoming tokens) as below (since the `::<u32>` will
- // have already been parsed):
- //
- // `x.foo::<u32>>>(3)`
- let parsed_angle_bracket_args = segment.args
- .as_ref()
- .map(|args| args.is_angle_bracketed())
- .unwrap_or(false);
-
- debug!(
- "check_trailing_angle_brackets: parsed_angle_bracket_args={:?}",
- parsed_angle_bracket_args,
- );
- if !parsed_angle_bracket_args {
- return;
- }
-
- // Keep the span at the start so we can highlight the sequence of `>` characters to be
- // removed.
- let lo = self.span;
-
- // We need to look-ahead to see if we have `>` characters without moving the cursor forward
- // (since we might have the field access case and the characters we're eating are
- // actual operators and not trailing characters - ie `x.foo >> 3`).
- let mut position = 0;
-
- // We can encounter `>` or `>>` tokens in any order, so we need to keep track of how
- // many of each (so we can correctly pluralize our error messages) and continue to
- // advance.
- let mut number_of_shr = 0;
- let mut number_of_gt = 0;
- while self.look_ahead(position, |t| {
- trace!("check_trailing_angle_brackets: t={:?}", t);
- if *t == token::BinOp(token::BinOpToken::Shr) {
- number_of_shr += 1;
- true
- } else if *t == token::Gt {
- number_of_gt += 1;
- true
- } else {
- false
- }
- }) {
- position += 1;
- }
-
- // If we didn't find any trailing `>` characters, then we have nothing to error about.
- debug!(
- "check_trailing_angle_brackets: number_of_gt={:?} number_of_shr={:?}",
- number_of_gt, number_of_shr,
- );
- if number_of_gt < 1 && number_of_shr < 1 {
- return;
- }
-
- // Finally, double check that we have our end token as otherwise this is the
- // second case.
- if self.look_ahead(position, |t| {
- trace!("check_trailing_angle_brackets: t={:?}", t);
- *t == end
- }) {
- // Eat from where we started until the end token so that parsing can continue
- // as if we didn't have those extra angle brackets.
- self.eat_to_tokens(&[&end]);
- let span = lo.until(self.span);
-
- let plural = number_of_gt > 1 || number_of_shr >= 1;
- self.diagnostic()
- .struct_span_err(
- span,
- &format!("unmatched angle bracket{}", if plural { "s" } else { "" }),
- )
- .span_suggestion(
- span,
- &format!("remove extra angle bracket{}", if plural { "s" } else { "" }),
- String::new(),
- Applicability::MachineApplicable,
- )
- .emit();
- }
- }
-
fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
let mut e = e0;
let mut hi;
let (span, e) = self.interpolated_or_expr_span(e)?;
(lo.to(span), ExprKind::Box(e))
}
- token::Ident(..) if self.token.is_ident_named("not") => {
+ token::Ident(..) if self.token.is_ident_named(sym::not) => {
// `not` is just an ordinary identifier in Rust-the-language,
// but as `rustc`-the-compiler, we can issue clever diagnostics
// for confused users who really want to say `!`
}
}
- /// Produce an error if comparison operators are chained (RFC #558).
- /// We only need to check lhs, not rhs, because all comparison ops
- /// have same precedence and are left-associative
- fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) {
- debug_assert!(outer_op.is_comparison(),
- "check_no_chained_comparison: {:?} is not comparison",
- outer_op);
- match lhs.node {
- ExprKind::Binary(op, _, _) if op.node.is_comparison() => {
- // respan to include both operators
- let op_span = op.span.to(self.span);
- let mut err = self.diagnostic().struct_span_err(op_span,
- "chained comparison operators require parentheses");
- if op.node == BinOpKind::Lt &&
- *outer_op == AssocOp::Less || // Include `<` to provide this recommendation
- *outer_op == AssocOp::Greater // even in a case like the following:
- { // Foo<Bar<Baz<Qux, ()>>>
- err.help(
- "use `::<...>` instead of `<...>` if you meant to specify type arguments");
- err.help("or use `(...)` if you meant to specify fn arguments");
- }
- err.emit();
- }
- _ => {}
- }
- }
-
/// Parse prefix-forms of range notation: `..expr`, `..`, `..=expr`
fn parse_prefix_range_expr(&mut self,
already_parsed_attrs: Option<ThinVec<Attribute>>)
hi = x.span;
x
})?)
- } else {
+ } else {
None
};
let limits = if tok == token::DotDot {
err.emit();
}
let in_span = self.prev_span;
- if self.eat_keyword(kw::In) {
- // a common typo: `for _ in in bar {}`
- let mut err = self.sess.span_diagnostic.struct_span_err(
- self.prev_span,
- "expected iterable, found keyword `in`",
- );
- err.span_suggestion_short(
- in_span.until(self.prev_span),
- "remove the duplicated `in`",
- String::new(),
- Applicability::MachineApplicable,
- );
- err.emit();
- }
+ self.check_for_for_in_in_typo(in_span);
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
let do_not_suggest_help =
self.token.is_keyword(kw::In) || self.token == token::Colon;
- if self.token.is_ident_named("and") {
+ if self.token.is_ident_named(sym::and) {
e.span_suggestion_short(
self.span,
"use `&&` instead of `and` for the boolean operator",
Applicability::MaybeIncorrect,
);
}
- if self.token.is_ident_named("or") {
+ if self.token.is_ident_named(sym::or) {
e.span_suggestion_short(
self.span,
"use `||` instead of `or` for the boolean operator",
where_clause: WhereClause {
id: ast::DUMMY_NODE_ID,
predicates: Vec::new(),
- span: syntax_pos::DUMMY_SP,
+ span: DUMMY_SP,
},
span: span_lo.to(self.prev_span),
})
let mut where_clause = WhereClause {
id: ast::DUMMY_NODE_ID,
predicates: Vec::new(),
- span: syntax_pos::DUMMY_SP,
+ span: DUMMY_SP,
};
if !self.eat_keyword(kw::Where) {
VisibilityKind::Inherited => {}
_ => {
let is_macro_rules: bool = match self.token {
- token::Ident(sid, _) => sid.name == Symbol::intern("macro_rules"),
+ token::Ident(sid, _) => sid.name == sym::macro_rules,
_ => false,
};
let mut err = if is_macro_rules {
let (constness, unsafety, mut asyncness, abi) = self.parse_fn_front_matter()?;
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
- let mut decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?;
+ let mut decl = self.parse_fn_decl_with_self(|p| {
+ p.parse_arg_general(true, true, false)
+ })?;
generics.where_clause = self.parse_where_clause()?;
self.construct_async_arguments(&mut asyncness, &mut decl);
*at_end = true;
Ident::with_empty_ctxt(sym::warn_directory_ownership)),
tokens: TokenStream::empty(),
is_sugared_doc: false,
- span: syntax_pos::DUMMY_SP,
+ span: DUMMY_SP,
};
attr::mark_known(&attr);
attrs.push(attr);
Ok((id, ItemKind::Mod(module), Some(attrs)))
} else {
let placeholder = ast::Mod {
- inner: syntax_pos::DUMMY_SP,
+ inner: DUMMY_SP,
items: Vec::new(),
inline: false
};
/// Returns `true` if the token is a identifier whose name is the given
/// string slice.
- crate fn is_ident_named(&self, name: &str) -> bool {
+ crate fn is_ident_named(&self, name: Symbol) -> bool {
match self.ident() {
- Some((ident, _)) => ident.as_str() == name,
+ Some((ident, _)) => ident.name == name,
None => false
}
}
call_site: DUMMY_SP,
def_site: None,
format: MacroAttribute(Symbol::intern("std_inject")),
- allow_internal_unstable: Some(vec![
- Symbol::intern("prelude_import"),
- ].into()),
+ allow_internal_unstable: Some(vec![sym::prelude_import].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
edition,
krate.module.items.insert(0, P(ast::Item {
attrs: vec![ast::Attribute {
style: ast::AttrStyle::Outer,
- path: ast::Path::from_ident(ast::Ident::new(Symbol::intern("prelude_import"), span)),
+ path: ast::Path::from_ident(ast::Ident::new(sym::prelude_import, span)),
tokens: TokenStream::empty(),
id: attr::mk_attr_id(),
is_sugared_doc: false,
mark.set_expn_info(ExpnInfo {
call_site: DUMMY_SP,
def_site: None,
- format: MacroAttribute(Symbol::intern("test_case")),
- allow_internal_unstable: Some(vec![
- Symbol::intern("main"),
- Symbol::intern("test"),
- Symbol::intern("rustc_attrs"),
- ].into()),
+ format: MacroAttribute(sym::test_case),
+ allow_internal_unstable: Some(vec![sym::main, sym::test, sym::rustc_attrs].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
edition: sess.edition,
let call_test_main = ecx.stmt_expr(call_test_main);
// #![main]
- let main_meta = ecx.meta_word(sp, Symbol::intern("main"));
+ let main_meta = ecx.meta_word(sp, sym::main);
let main_attr = ecx.attribute(sp, main_meta);
// extern crate test as test_gensym
let test_extern_stmt = ecx.stmt_item(sp, ecx.item(sp,
test_id,
vec![],
- ast::ItemKind::ExternCrate(Some(Symbol::intern("test")))
+ ast::ItemKind::ExternCrate(Some(sym::test))
));
// pub fn main() { ... }
Delimited(DelimSpan, DelimToken, TokenStream),
}
+// Ensure all fields of `TokenTree` is `Send` and `Sync`.
+#[cfg(parallel_compiler)]
+fn _dummy()
+where
+ Span: Send + Sync,
+ token::Token: Send + Sync,
+ DelimSpan: Send + Sync,
+ DelimToken: Send + Sync,
+ TokenStream: Send + Sync,
+{}
+
+// These are safe since we ensure that they hold for all fields in the `_dummy` function.
+//
+// These impls are only here because the compiler takes forever to compute the Send and Sync
+// bounds without them.
+// FIXME: Remove these impls when the compiler can compute the bounds quickly again.
+// See https://github.com/rust-lang/rust/issues/60846
+#[cfg(parallel_compiler)]
+unsafe impl Send for TokenTree {}
+#[cfg(parallel_compiler)]
+unsafe impl Sync for TokenTree {}
+
impl TokenTree {
/// Use this token tree as a matcher to parse given tts.
pub fn parse(cx: &base::ExtCtxt<'_>, mtch: &[quoted::TokenTree], tts: TokenStream)
use syntax::feature_gate;
use syntax::parse::{self, token};
use syntax::ptr::P;
-use syntax::symbol::{Symbol, sym};
+use syntax::symbol::{kw, sym, Symbol};
use syntax::ast::AsmDialect;
use syntax_pos::Span;
use syntax::tokenstream;
})
.unwrap_or(tts.len());
let mut p = cx.new_parser_from_tts(&tts[first_colon..]);
- let mut asm = Symbol::intern("");
+ let mut asm = kw::Invalid;
let mut asm_str_style = None;
let mut outputs = Vec::new();
let mut inputs = Vec::new();
if p2.token != token::Eof {
let mut extra_tts = p2.parse_all_token_trees()?;
extra_tts.extend(tts[first_colon..].iter().cloned());
- p = parse::stream_to_parser(cx.parse_sess, extra_tts.into_iter().collect());
+ p = parse::stream_to_parser(
+ cx.parse_sess,
+ extra_tts.into_iter().collect(),
+ Some("inline assembly"),
+ );
}
asm = s;
use syntax::parse::parser::Parser;
use syntax::print::pprust;
use syntax::ptr::P;
-use syntax::symbol::Symbol;
+use syntax::symbol::{sym, Symbol};
use syntax::tokenstream::{TokenStream, TokenTree};
use syntax_pos::{Span, DUMMY_SP};
let sp = sp.apply_mark(cx.current_expansion.mark);
let panic_call = Mac_ {
- path: Path::from_ident(Ident::new(Symbol::intern("panic"), sp)),
+ path: Path::from_ident(Ident::new(sym::panic, sp)),
tts: custom_message.unwrap_or_else(|| {
TokenStream::from(TokenTree::Token(
DUMMY_SP,
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;
-use syntax::symbol::{Symbol, kw, sym};
+use syntax::symbol::{kw, sym, Symbol};
use syntax_pos::Span;
pub fn expand_deriving_clone(cx: &mut ExtCtxt<'_>,
_ => cx.span_bug(span, "#[derive(Clone)] on trait item or impl item"),
}
- let inline = cx.meta_word(span, Symbol::intern("inline"));
+ let inline = cx.meta_word(span, sym::inline);
let attrs = vec![cx.attribute(span, inline)];
let trait_def = TraitDef {
span,
// set the expn ID so we can use the unstable struct.
let span = span.with_ctxt(cx.backtrace());
let assert_path = cx.path_all(span, true,
- cx.std_path(&["clone", helper_name]),
+ cx.std_path(&[sym::clone, Symbol::intern(helper_name)]),
vec![GenericArg::Type(ty)], vec![]);
stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path)));
}
-> P<Expr> {
let ctor_path;
let all_fields;
- let fn_path = cx.std_path(&["clone", "Clone", "clone"]);
+ let fn_path = cx.std_path(&[sym::clone, sym::Clone, sym::clone]);
let subcall = |cx: &mut ExtCtxt<'_>, field: &FieldInfo<'_>| {
let args = vec![cx.expr_addr_of(field.span, field.self_.clone())];
cx.expr_call_global(field.span, fn_path.clone(), args)
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;
-use syntax::symbol::Symbol;
+use syntax::symbol::{sym, Symbol};
use syntax_pos::Span;
pub fn expand_deriving_eq(cx: &mut ExtCtxt<'_>,
mitem: &MetaItem,
item: &Annotatable,
push: &mut dyn FnMut(Annotatable)) {
- let inline = cx.meta_word(span, Symbol::intern("inline"));
- let hidden = cx.meta_list_item_word(span, Symbol::intern("hidden"));
- let doc = cx.meta_list(span, Symbol::intern("doc"), vec![hidden]);
+ let inline = cx.meta_word(span, sym::inline);
+ let hidden = cx.meta_list_item_word(span, sym::hidden);
+ let doc = cx.meta_list(span, sym::doc, vec![hidden]);
let attrs = vec![cx.attribute(span, inline), cx.attribute(span, doc)];
let trait_def = TraitDef {
span,
// set the expn ID so we can use the unstable struct.
let span = span.with_ctxt(cx.backtrace());
let assert_path = cx.path_all(span, true,
- cx.std_path(&["cmp", helper_name]),
+ cx.std_path(&[sym::cmp, Symbol::intern(helper_name)]),
vec![GenericArg::Type(ty)], vec![]);
stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path)));
}
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;
-use syntax::symbol::Symbol;
+use syntax::symbol::sym;
use syntax_pos::Span;
pub fn expand_deriving_ord(cx: &mut ExtCtxt<'_>,
mitem: &MetaItem,
item: &Annotatable,
push: &mut dyn FnMut(Annotatable)) {
- let inline = cx.meta_word(span, Symbol::intern("inline"));
+ let inline = cx.meta_word(span, sym::inline);
let attrs = vec![cx.attribute(span, inline)];
let trait_def = TraitDef {
span,
pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
let test_id = cx.ident_of("cmp").gensym();
- let equals_path = cx.path_global(span, cx.std_path(&["cmp", "Ordering", "Equal"]));
+ let equals_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
- let cmp_path = cx.std_path(&["cmp", "Ord", "cmp"]);
+ let cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]);
// Builds:
//
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;
-use syntax::symbol::Symbol;
+use syntax::symbol::sym;
use syntax_pos::Span;
pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt<'_>,
macro_rules! md {
($name:expr, $f:ident) => { {
- let inline = cx.meta_word(span, Symbol::intern("inline"));
+ let inline = cx.meta_word(span, sym::inline);
let attrs = vec![cx.attribute(span, inline)];
MethodDef {
name: $name,
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;
-use syntax::symbol::Symbol;
+use syntax::symbol::{sym, Symbol};
use syntax_pos::Span;
pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt<'_>,
push: &mut dyn FnMut(Annotatable)) {
macro_rules! md {
($name:expr, $op:expr, $equal:expr) => { {
- let inline = cx.meta_word(span, Symbol::intern("inline"));
+ let inline = cx.meta_word(span, sym::inline);
let attrs = vec![cx.attribute(span, inline)];
MethodDef {
name: $name,
vec![Box::new(ordering_ty)],
PathKind::Std));
- let inline = cx.meta_word(span, Symbol::intern("inline"));
+ let inline = cx.meta_word(span, sym::inline);
let attrs = vec![cx.attribute(span, inline)];
let partial_cmp_def = MethodDef {
pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
let test_id = cx.ident_of("cmp").gensym();
- let ordering = cx.path_global(span, cx.std_path(&["cmp", "Ordering", "Equal"]));
+ let ordering = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
let ordering_expr = cx.expr_path(ordering.clone());
let equals_expr = cx.expr_some(span, ordering_expr);
- let partial_cmp_path = cx.std_path(&["cmp", "PartialOrd", "partial_cmp"]);
+ let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);
// Builds:
//
span: Span,
substr: &Substructure<'_>) -> P<Expr> {
let ordering_path = |cx: &mut ExtCtxt<'_>, name: &str| {
- cx.expr_path(cx.path_global(span, cx.std_path(&["cmp", "Ordering", name])))
+ cx.expr_path(cx.path_global(
+ span, cx.std_path(&[sym::cmp, sym::Ordering, Symbol::intern(name)])))
};
let par_cmp = |cx: &mut ExtCtxt<'_>, span, self_f: P<Expr>, other_fs: &[P<Expr>], default| {
};
// `PartialOrd::partial_cmp(self.fi, other.fi)`
- let cmp_path = cx.expr_path(cx.path_global(span, cx.std_path(&["cmp",
- "PartialOrd",
- "partial_cmp"])));
+ let cmp_path = cx.expr_path(cx.path_global(span, cx.std_path(&[sym::cmp,
+ sym::PartialOrd,
+ sym::partial_cmp])));
let cmp = cx.expr_call(span,
cmp_path,
vec![cx.expr_addr_of(span, self_f),
let default = ordering_path(cx, default);
// `Option::unwrap_or(_, Ordering::Equal)`
- let unwrap_path = cx.expr_path(cx.path_global(span, cx.std_path(&["option",
- "Option",
- "unwrap_or"])));
+ let unwrap_path = cx.expr_path(cx.path_global(span, cx.std_path(&[sym::option,
+ sym::Option,
+ sym::unwrap_or])));
cx.expr_call(span, unwrap_path, vec![cmp, default])
};
// `Ordering::then_with(Option::unwrap_or(..), ..)`
let then_with_path = cx.expr_path(cx.path_global(span,
- cx.std_path(&["cmp",
- "Ordering",
- "then_with"])));
+ cx.std_path(&[sym::cmp,
+ sym::Ordering,
+ sym::then_with])));
cx.expr_call(span, then_with_path, vec![par_cmp, cx.lambda0(span, subexpr)])
},
|cx, args| {
let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
let msg = "proc-macro derive produced unparseable tokens";
- let mut parser = parse::stream_to_parser(ecx.parse_sess, stream);
+ let mut parser = parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
let mut items = vec![];
loop {
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;
+use syntax::symbol::sym;
use syntax_pos::{DUMMY_SP, Span};
pub fn expand_deriving_debug(cx: &mut ExtCtxt<'_>,
let expr = cx.expr_method_call(span,
builder_expr.clone(),
- Ident::from_str("field"),
+ Ident::with_empty_ctxt(sym::field),
vec![field]);
// Use `let _ = expr;` to avoid triggering the
let field = cx.expr_addr_of(field.span, field);
let expr = cx.expr_method_call(span,
builder_expr.clone(),
- Ident::from_str("field"),
+ Ident::with_empty_ctxt(sym::field),
vec![name, field]);
stmts.push(stmt_let_undescore(cx, span, expr));
}
use syntax::ext::base::{Annotatable, DummyResult, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;
-use syntax::symbol::Symbol;
+use syntax::symbol::{kw, sym};
use syntax::span_err;
use syntax_pos::Span;
mitem: &MetaItem,
item: &Annotatable,
push: &mut dyn FnMut(Annotatable)) {
- let inline = cx.meta_word(span, Symbol::intern("inline"));
+ let inline = cx.meta_word(span, sym::inline);
let attrs = vec![cx.attribute(span, inline)];
let trait_def = TraitDef {
span,
trait_span: Span,
substr: &Substructure<'_>)
-> P<Expr> {
- let default_ident = cx.std_path(&["default", "Default", "default"]);
+ // Note that `kw::Default` is "default" and `sym::Default` is "Default"!
+ let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]);
let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new());
return match *substr.fields {
let self_type = cx.ty_path(path);
let attr = cx.attribute(self.span,
- cx.meta_word(self.span,
- Symbol::intern("automatically_derived")));
+ cx.meta_word(self.span, sym::automatically_derived));
// Just mark it now since we know that it'll end up used downstream
attr::mark_used(&attr);
let opt_trait_ref = Some(trait_ref);
let unused_qual = {
let word = cx.meta_list_item_word(self.span, Symbol::intern("unused_qualifications"));
- cx.attribute(self.span, cx.meta_list(self.span, Symbol::intern("allow"), vec![word]))
+ cx.attribute(self.span, cx.meta_list(self.span, sym::allow, vec![word]))
};
let mut a = vec![attr, unused_qual];
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;
+use syntax::symbol::sym;
use syntax_pos::Span;
pub fn expand_deriving_hash(cx: &mut ExtCtxt<'_>,
};
let call_hash = |span, thing_expr| {
let hash_path = {
- let strs = cx.std_path(&["hash", "Hash", "hash"]);
+ let strs = cx.std_path(&[sym::hash, sym::Hash, sym::hash]);
cx.expr_path(cx.path_global(span, strs))
};
span = span.with_ctxt(cx.backtrace());
} else { // Avoid instability errors with user defined curstom derives, cc #36316
let mut info = cx.current_expansion.mark.expn_info().unwrap();
- info.allow_internal_unstable = Some(vec![Symbol::intern("core_intrinsics")].into());
+ info.allow_internal_unstable = Some(vec![sym::core_intrinsics].into());
let mark = Mark::fresh(Mark::root());
mark.set_expn_info(info);
span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
}
- let path = cx.std_path(&["intrinsics", intrinsic]);
+ let path = cx.std_path(&[sym::intrinsics, Symbol::intern(intrinsic)]);
let call = cx.expr_call_global(span, path, args);
cx.expr_block(P(ast::Block {
let lt = cx.lifetime(sp, Ident::with_empty_ctxt(kw::StaticLifetime));
cx.expr_path(cx.path_all(sp,
true,
- cx.std_path(&["option", "Option", "None"]),
+ cx.std_path(&[sym::option, sym::Option, sym::None]),
vec![GenericArg::Type(cx.ty_rptr(sp,
cx.ty_ident(sp,
Ident::with_empty_ctxt(sym::str)),
}
Ok(s) => {
cx.expr_call_global(sp,
- cx.std_path(&["option", "Option", "Some"]),
+ cx.std_path(&[sym::option, sym::Option, sym::Some]),
vec![cx.expr_str(sp, Symbol::intern(&s))])
}
};
}
fn rtpath(ecx: &ExtCtxt<'_>, s: &str) -> Vec<ast::Ident> {
- ecx.std_path(&["fmt", "rt", "v1", s])
+ ecx.std_path(&[sym::fmt, sym::rt, sym::v1, Symbol::intern(s)])
}
fn build_count(&self, c: parse::Count<'_>) -> P<ast::Expr> {
("new_v1_formatted", vec![pieces, args_slice, fmt])
};
- let path = self.ecx.std_path(&["fmt", "Arguments", fn_name]);
+ let path = self.ecx.std_path(&[sym::fmt, sym::Arguments, Symbol::intern(fn_name)]);
self.ecx.expr_call_global(self.macsp, path, fn_args)
}
}
}
Count => {
- let path = ecx.std_path(&["fmt", "ArgumentV1", "from_usize"]);
+ let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::from_usize]);
return ecx.expr_call_global(macsp, path, vec![arg]);
}
};
- let path = ecx.std_path(&["fmt", trait_, "fmt"]);
+ let path = ecx.std_path(&[sym::fmt, Symbol::intern(trait_), sym::fmt]);
let format_fn = ecx.path_global(sp, path);
- let path = ecx.std_path(&["fmt", "ArgumentV1", "new"]);
+ let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::new]);
ecx.expr_call_global(macsp, path, vec![arg, ecx.expr_path(format_fn)])
}
}
use rustc_data_structures::sync::Lrc;
use syntax::ast;
use syntax::ext::base::{MacroExpanderFn, NormalTT, NamedSyntaxExtension, MultiModifier};
-use syntax::symbol::Symbol;
use syntax::edition::Edition;
+use syntax::symbol::{sym, Symbol};
pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
user_exts: Vec<NamedSyntaxExtension>,
assert: assert::expand_assert,
}
- register(Symbol::intern("test_case"), MultiModifier(Box::new(test_case::expand)));
- register(Symbol::intern("test"), MultiModifier(Box::new(test::expand_test)));
- register(Symbol::intern("bench"), MultiModifier(Box::new(test::expand_bench)));
+ register(sym::test_case, MultiModifier(Box::new(test_case::expand)));
+ register(sym::test, MultiModifier(Box::new(test::expand_test)));
+ register(sym::bench, MultiModifier(Box::new(test::expand_bench)));
// format_args uses `unstable` things internally.
register(Symbol::intern("format_args"),
NormalTT {
expander: Box::new(format::expand_format_args),
def_info: None,
- allow_internal_unstable: Some(vec![
- Symbol::intern("fmt_internals"),
- ].into()),
+ allow_internal_unstable: Some(vec![sym::fmt_internals].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
unstable_feature: None,
edition,
});
- register(Symbol::intern("format_args_nl"),
+ register(sym::format_args_nl,
NormalTT {
expander: Box::new(format::expand_format_args_nl),
def_info: None,
- allow_internal_unstable: Some(vec![
- Symbol::intern("fmt_internals"),
- ].into()),
+ allow_internal_unstable: Some(vec![sym::fmt_internals].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
unstable_feature: None,
mark.set_expn_info(ExpnInfo {
call_site: DUMMY_SP,
def_site: None,
- format: MacroAttribute(Symbol::intern("proc_macro")),
+ format: MacroAttribute(sym::proc_macro),
allow_internal_unstable: Some(vec![
- Symbol::intern("rustc_attrs"),
+ sym::rustc_attrs,
Symbol::intern("proc_macro_internals"),
].into()),
allow_internal_unsafe: false,
ast::Mutability::Immutable,
cx.expr_vec_slice(span, decls),
).map(|mut i| {
- let attr = cx.meta_word(span, Symbol::intern("rustc_proc_macro_decls"));
+ let attr = cx.meta_word(span, sym::rustc_proc_macro_decls);
i.attrs.push(cx.attribute(span, attr));
i.vis = respan(span, ast::VisibilityKind::Public);
i
use syntax::parse::{self, token, ParseSess};
use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
use syntax_pos::hygiene::{SyntaxContext, Transparency};
-use syntax_pos::symbol::{kw, Symbol};
+use syntax_pos::symbol::{kw, sym, Symbol};
use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
trait FromInternal<T> {
escaped.extend(ch.escape_debug());
}
let stream = vec![
- Ident(ast::Ident::new(Symbol::intern("doc"), span), false),
+ Ident(ast::Ident::new(sym::doc, span), false),
Eq,
Token::lit(token::Str, Symbol::intern(&escaped), None),
]
mark.set_expn_info(ExpnInfo {
call_site: DUMMY_SP,
def_site: None,
- format: MacroAttribute(Symbol::intern("test")),
- allow_internal_unstable: Some(vec![
- Symbol::intern("rustc_attrs"),
- Symbol::intern("test"),
- ].into()),
+ format: MacroAttribute(sym::test),
+ allow_internal_unstable: Some(vec![sym::rustc_attrs, sym::test].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
edition: cx.parse_sess.edition,
let mut test_const = cx.item(sp, ast::Ident::new(item.ident.name, sp).gensym(),
vec![
// #[cfg(test)]
- cx.attribute(attr_sp, cx.meta_list(attr_sp, Symbol::intern("cfg"), vec![
- cx.meta_list_item_word(attr_sp, Symbol::intern("test"))
+ cx.attribute(attr_sp, cx.meta_list(attr_sp, sym::cfg, vec![
+ cx.meta_list_item_word(attr_sp, sym::test)
])),
// #[rustc_test_marker]
- cx.attribute(attr_sp, cx.meta_word(attr_sp, Symbol::intern("rustc_test_marker"))),
+ cx.attribute(attr_sp, cx.meta_word(attr_sp, sym::rustc_test_marker)),
],
// const $ident: test::TestDescAndFn =
ast::ItemKind::Const(cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))),
let test_extern = cx.item(sp,
test_id,
vec![],
- ast::ItemKind::ExternCrate(Some(Symbol::intern("test")))
+ ast::ItemKind::ExternCrate(Some(sym::test))
);
log::debug!("Synthetic test item:\n{}\n", pprust::item_to_string(&test_const));
use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::ast;
use syntax::source_map::respan;
-use syntax::symbol::{Symbol, sym};
+use syntax::symbol::sym;
use syntax_pos::{DUMMY_SP, Span};
use syntax::source_map::{ExpnInfo, MacroAttribute};
use syntax::feature_gate;
mark.set_expn_info(ExpnInfo {
call_site: DUMMY_SP,
def_site: None,
- format: MacroAttribute(Symbol::intern("test_case")),
- allow_internal_unstable: Some(vec![
- Symbol::intern("test"),
- Symbol::intern("rustc_attrs"),
- ].into()),
+ format: MacroAttribute(sym::test_case),
+ allow_internal_unstable: Some(vec![sym::test, sym::rustc_attrs].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
edition: ecx.parse_sess.edition,
item.ident = item.ident.gensym();
item.attrs.push(
ecx.attribute(sp,
- ecx.meta_word(sp, Symbol::intern("rustc_test_marker")))
+ ecx.meta_word(sp, sym::rustc_test_marker))
);
item
});
use rustc_macros::symbols;
use serialize::{Decodable, Decoder, Encodable, Encoder};
-use std::fmt;
-use std::str;
use std::cmp::{PartialEq, Ordering, PartialOrd, Ord};
+use std::fmt;
use std::hash::{Hash, Hasher};
+use std::str;
use crate::hygiene::SyntaxContext;
use crate::{Span, DUMMY_SP, GLOBALS};
// Symbols that can be referred to with syntax_pos::sym::*. The symbol is
// the stringified identifier unless otherwise specified (e.g.
// `proc_dash_macro` represents "proc-macro").
+ //
+ // As well as the symbols listed, there are symbols for the the strings
+ // "0", "1", ..., "9", which are accessible via `sym::integer`.
Symbols {
aarch64_target_feature,
abi,
allow_internal_unstable,
allow_internal_unstable_backcompat_hack,
always,
+ and,
any,
arbitrary_self_types,
+ Arguments,
+ ArgumentV1,
arm_target_feature,
asm,
associated_consts,
automatically_derived,
avx512_target_feature,
await_macro,
+ begin_panic,
+ bench,
bin,
bind_by_move_pattern_guards,
block,
cfg_target_thread_local,
cfg_target_vendor,
clone,
+ Clone,
clone_closures,
clone_from,
closure_to_fn_coercion,
+ cmp,
cmpxchg16b_target_feature,
cold,
compile_error,
const_raw_ptr_to_usize_cast,
const_transmute,
contents,
+ context,
convert,
copy_closures,
core,
custom_test_frameworks,
c_variadic,
decl_macro,
+ Default,
default_lib_allocator,
default_type_parameter_fallback,
default_type_params,
deny,
deprecated,
+ deref,
+ deref_mut,
derive,
doc,
doc_alias,
enable,
err,
Err,
+ Equal,
except,
exclusive_range_pattern,
exhaustive_integer_patterns,
existential_type,
expected,
export_name,
+ expr,
extern_absolute_paths,
external_doc,
extern_crate_item_prelude,
f64,
feature,
ffi_returns_twice,
+ field,
field_init_shorthand,
file,
+ fmt,
+ fmt_internals,
fn_must_use,
forbid,
format_args_nl,
from_error,
from_generator,
from_ok,
+ from_usize,
fundamental,
future,
Future,
+ FxHashSet,
+ FxHashMap,
gen_future,
generators,
generic_associated_types,
global_allocator,
global_asm,
globs,
+ hash,
+ Hash,
+ HashSet,
+ HashMap,
hexagon_target_feature,
hidden,
homogeneous_aggregate,
impl_header_lifetime_elision,
impl_trait_in_bindings,
import_shadowing,
+ index,
+ index_mut,
in_band_lifetimes,
include,
inclusive_range_syntax,
issue,
issue_5723_bootstrap,
issue_tracker_base_url,
+ item,
item_like_imports,
iter,
Iterator,
lang,
lang_items,
lib,
+ lifetime,
link,
linkage,
link_args,
link_name,
link_section,
lint_reasons,
+ literal,
local_inner_macros,
log_syntax,
loop_break_value,
negate_unsigned,
never,
never_type,
+ new,
next,
__next,
nll,
option,
Option,
opt_out_copy,
+ or,
+ Ord,
+ Ordering,
Output,
overlapping_marker_traits,
packed,
+ panic,
panic_handler,
panic_impl,
panic_implementation,
panic_runtime,
+ partial_cmp,
+ PartialOrd,
passes,
+ pat,
path,
pattern_parentheses,
Pending,
proc_dash_macro: "proc-macro",
proc_macro,
proc_macro_attribute,
+ proc_macro_def_site,
proc_macro_derive,
proc_macro_expr,
proc_macro_gen,
Result,
Return,
rlib,
+ rt,
rtm_target_feature,
rust,
rust_2015_preview,
rust_2018_preview,
rust_begin_unwind,
+ rustc,
rustc_allocator_nounwind,
rustc_allow_const_fn_ptr,
rustc_args_required_const,
static_recursion,
std,
str,
+ stmt,
stmt_expr_attributes,
stop_after_dataflow,
struct_field_attributes,
struct_inherit,
structural_match,
struct_variant,
+ sty,
suggestion,
target_feature,
target_has_atomic,
test,
test_2018_feature,
test_accepted_feature,
+ test_case,
test_removed_feature,
test_runner,
+ then_with,
thread_local,
tool_attributes,
tool_lints,
Try,
try_blocks,
try_trait,
+ tt,
tuple_indexing,
+ Ty,
ty,
+ TyCtxt,
+ TyKind,
type_alias_enum_variants,
type_ascription,
type_length_limit,
untagged_unions,
unwind,
unwind_attributes,
+ unwrap_or,
used,
use_extern_macros,
use_nested_groups,
usize,
v1,
val,
+ vec,
+ Vec,
vis,
visible_private_types,
volatile,
}
impl Interner {
- fn prefill(init: &[&str]) -> Self {
- let mut this = Interner::default();
- this.names.reserve(init.len());
- this.strings.reserve(init.len());
-
- // We can't allocate empty strings in the arena, so handle this here.
- assert!(kw::Invalid.as_u32() == 0 && init[0].is_empty());
- this.names.insert("", kw::Invalid);
- this.strings.push("");
-
- for string in &init[1..] {
- this.intern(string);
+ fn prefill(init: &[&'static str]) -> Self {
+ let symbols = (0 .. init.len() as u32).map(Symbol::new);
+ Interner {
+ strings: init.to_vec(),
+ names: init.iter().copied().zip(symbols).collect(),
+ ..Default::default()
}
- this
}
pub fn intern(&mut self, string: &str) -> Symbol {
// This module has a very short name because it's used a lot.
pub mod sym {
+ use std::convert::TryInto;
use super::Symbol;
+
symbols!();
+
+ // Get the symbol for an integer. The first few non-negative integers each
+ // have a static symbol and therefore are fast.
+ pub fn integer<N: TryInto<usize> + Copy + ToString>(n: N) -> Symbol {
+ if let Result::Ok(idx) = n.try_into() {
+ if let Option::Some(&sym) = digits_array.get(idx) {
+ return sym;
+ }
+ }
+ Symbol::intern(&n.to_string())
+ }
}
impl Symbol {
#![unstable(feature = "test", issue = "27812")]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
#![feature(asm)]
-#![feature(fnbox)]
#![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc, rustc_private))]
#![feature(nll)]
#![feature(set_stdio)]
use std::any::Any;
use std::borrow::Cow;
-use std::boxed::FnBox;
use std::cmp;
use std::collections::BTreeMap;
use std::env;
pub enum TestFn {
StaticTestFn(fn()),
StaticBenchFn(fn(&mut Bencher)),
- DynTestFn(Box<dyn FnBox() + Send>),
+ DynTestFn(Box<dyn FnOnce() + Send>),
DynBenchFn(Box<dyn TDynBenchFn + 'static>),
}
desc: TestDesc,
monitor_ch: Sender<MonitorMsg>,
nocapture: bool,
- testfn: Box<dyn FnBox() + Send>,
+ testfn: Box<dyn FnOnce() + Send>,
concurrency: Concurrent,
) {
// Buffer for capturing standard I/O
# source tarball for a stable release you'll likely see `1.x.0` for rustc and
# `0.x.0` for Cargo where they were released on `date`.
-date: 2019-04-11
+date: 2019-05-23
rustc: beta
cargo: beta
// StorageDead(_2);
// StorageLive(_4);
// _4 = move _1;
-// _3 = const std::mem::drop(move _4) -> [return: bb5, unwind: bb7];
+// _3 = const std::mem::drop::<std::boxed::Box<S>>(move _4) -> [return: bb5, unwind: bb7];
// }
//
// bb5: {
--- /dev/null
+// compile-flags: -Z mir-opt-level=0
+
+fn main() {
+ let x = b"foo";
+ let y = [5u8, b'x'];
+}
+
+// END RUST SOURCE
+// START rustc.main.EraseRegions.after.mir
+// ...
+// _1 = const b"foo";
+// ...
+// _2 = [const 5u8, const 120u8];
+// ...
+// END rustc.main.EraseRegions.after.mir
// ...
// bb0: {
// ...
-// _0 = const X::y(move _2) -> bb1;
+// _0 = const <dyn X as X>::y(move _2) -> bb1;
// }
// ...
// END rustc.test.Inline.after.mir
// ...
// bb0: {
// ...
-// _0 = const X::y(move _2) -> bb1;
+// _0 = const <dyn X as X>::y(move _2) -> bb1;
// }
// ...
// END rustc.test2.Inline.after.mir
// StorageDead(_3);
// StorageLive(_6);
// _6 = &_2;
-// _5 = const std::mem::drop(move _6) -> [return: bb19, unwind: bb4];
+// _5 = const std::mem::drop::<&i32>(move _6) -> [return: bb19, unwind: bb4];
// }
// bb19: {
// StorageDead(_6);
// Test that we don't ICE when trying to dump MIR for unusual item types and
// that we don't create filenames containing `<` and `>`
+// ignore-tidy-linelength
struct A;
// }
// bb7: {
// _2 = &mut (*_1);
-// _3 = const std::ops::Drop::drop(move _2) -> [return: bb6, unwind: bb5];
+// _3 = const <std::vec::Vec<i32> as std::ops::Drop>::drop(move _2) -> [return: bb6, unwind: bb5];
// }
// END rustc.ptr-real_drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir
+++ /dev/null
-#![feature(async_await)]
-#![allow(unused_parens)]
-
-// edition:2018
-// pp-exact
-
-fn main() { let _a = (async { }); }
--- /dev/null
+# needs-matching-clang
+
+# This test makes sure that cross-language inlining can be used in conjunction
+# with profile-guided optimization. The test only tests that the whole workflow
+# can be executed without anything crashing. It does not test whether PGO or
+# xLTO have any specific effect on the generated code.
+
+-include ../tools.mk
+
+COMMON_FLAGS=-Copt-level=3 -Ccodegen-units=1
+
+# LLVM doesn't support instrumenting binaries that use SEH:
+# https://bugs.llvm.org/show_bug.cgi?id=41279
+#
+# Things work fine with -Cpanic=abort though.
+ifdef IS_MSVC
+COMMON_FLAGS+= -Cpanic=abort
+endif
+
+all: cpp-executable rust-executable
+
+cpp-executable:
+ $(RUSTC) -Clinker-plugin-lto=on \
+ -Zpgo-gen="$(TMPDIR)"/cpp-profdata \
+ -o "$(TMPDIR)"/librustlib-xlto.a \
+ $(COMMON_FLAGS) \
+ ./rustlib.rs
+ $(CLANG) -flto=thin \
+ -fprofile-generate="$(TMPDIR)"/cpp-profdata \
+ -fuse-ld=lld \
+ -L "$(TMPDIR)" \
+ -lrustlib-xlto \
+ -o "$(TMPDIR)"/cmain \
+ -O3 \
+ ./cmain.c
+ $(TMPDIR)/cmain
+ # Postprocess the profiling data so it can be used by the compiler
+ "$(LLVM_BIN_DIR)"/llvm-profdata merge \
+ -o "$(TMPDIR)"/cpp-profdata/merged.profdata \
+ "$(TMPDIR)"/cpp-profdata/default_*.profraw
+ $(RUSTC) -Clinker-plugin-lto=on \
+ -Zpgo-use="$(TMPDIR)"/cpp-profdata/merged.profdata \
+ -o "$(TMPDIR)"/librustlib-xlto.a \
+ $(COMMON_FLAGS) \
+ ./rustlib.rs
+ $(CLANG) -flto=thin \
+ -fprofile-use="$(TMPDIR)"/cpp-profdata/merged.profdata \
+ -fuse-ld=lld \
+ -L "$(TMPDIR)" \
+ -lrustlib-xlto \
+ -o "$(TMPDIR)"/cmain \
+ -O3 \
+ ./cmain.c
+
+rust-executable:
+ exit
+ $(CLANG) ./clib.c -fprofile-generate="$(TMPDIR)"/rs-profdata -flto=thin -c -o $(TMPDIR)/clib.o -O3
+ (cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o)
+ $(RUSTC) -Clinker-plugin-lto=on \
+ -Zpgo-gen="$(TMPDIR)"/rs-profdata \
+ -L$(TMPDIR) \
+ $(COMMON_FLAGS) \
+ -Clinker=$(CLANG) \
+ -Clink-arg=-fuse-ld=lld \
+ -o $(TMPDIR)/rsmain \
+ ./main.rs
+ $(TMPDIR)/rsmain
+ # Postprocess the profiling data so it can be used by the compiler
+ "$(LLVM_BIN_DIR)"/llvm-profdata merge \
+ -o "$(TMPDIR)"/rs-profdata/merged.profdata \
+ "$(TMPDIR)"/rs-profdata/default_*.profraw
+ $(CLANG) ./clib.c \
+ -fprofile-use="$(TMPDIR)"/rs-profdata/merged.profdata \
+ -flto=thin \
+ -c \
+ -o $(TMPDIR)/clib.o \
+ -O3
+ rm "$(TMPDIR)"/libxyz.a
+ (cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o)
+ $(RUSTC) -Clinker-plugin-lto=on \
+ -Zpgo-use="$(TMPDIR)"/rs-profdata/merged.profdata \
+ -L$(TMPDIR) \
+ $(COMMON_FLAGS) \
+ -Clinker=$(CLANG) \
+ -Clink-arg=-fuse-ld=lld \
+ -o $(TMPDIR)/rsmain \
+ ./main.rs
--- /dev/null
+#include <stdint.h>
+
+uint32_t c_always_inlined() {
+ return 1234;
+}
+
+__attribute__((noinline)) uint32_t c_never_inlined() {
+ return 12345;
+}
--- /dev/null
+#include <stdint.h>
+
+// A trivial function defined in Rust, returning a constant value. This should
+// always be inlined.
+uint32_t rust_always_inlined();
+
+
+uint32_t rust_never_inlined();
+
+int main(int argc, char** argv) {
+ return (rust_never_inlined() + rust_always_inlined()) * 0;
+}
--- /dev/null
+#[link(name = "xyz")]
+extern "C" {
+ fn c_always_inlined() -> u32;
+ fn c_never_inlined() -> u32;
+}
+
+fn main() {
+ unsafe {
+ println!("blub: {}", c_always_inlined() + c_never_inlined());
+ }
+}
--- /dev/null
+#![crate_type="staticlib"]
+
+#[no_mangle]
+pub extern "C" fn rust_always_inlined() -> u32 {
+ 42
+}
+
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rust_never_inlined() -> u32 {
+ 421
+}
+++ /dev/null
-// edition:2018
-// aux-build:arc_wake.rs
-
-#![feature(async_await)]
-
-extern crate arc_wake;
-
-use std::pin::Pin;
-use std::future::Future;
-use std::sync::{
- Arc,
- atomic::{self, AtomicUsize},
-};
-use std::task::{Context, Poll};
-use arc_wake::ArcWake;
-
-struct Counter {
- wakes: AtomicUsize,
-}
-
-impl ArcWake for Counter {
- fn wake(self: Arc<Self>) {
- Self::wake_by_ref(&self)
- }
- fn wake_by_ref(arc_self: &Arc<Self>) {
- arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
- }
-}
-
-struct WakeOnceThenComplete(bool);
-
-fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) }
-
-impl Future for WakeOnceThenComplete {
- type Output = ();
- fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
- if self.0 {
- Poll::Ready(())
- } else {
- cx.waker().wake_by_ref();
- self.0 = true;
- Poll::Pending
- }
- }
-}
-
-fn async_block(x: u8) -> impl Future<Output = u8> {
- async move {
- wake_and_yield_once().await;
- x
- }
-}
-
-fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
- async move {
- wake_and_yield_once().await;
- *x
- }
-}
-
-fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
- async move {
- let future = async {
- wake_and_yield_once().await;
- x
- };
- future.await
- }
-}
-
-fn async_closure(x: u8) -> impl Future<Output = u8> {
- (async move |x: u8| -> u8 {
- wake_and_yield_once().await;
- x
- })(x)
-}
-
-async fn async_fn(x: u8) -> u8 {
- wake_and_yield_once().await;
- x
-}
-
-async fn generic_async_fn<T>(x: T) -> T {
- wake_and_yield_once().await;
- x
-}
-
-async fn async_fn_with_borrow(x: &u8) -> u8 {
- wake_and_yield_once().await;
- *x
-}
-
-async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 {
- wake_and_yield_once().await;
- *x
-}
-
-fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
- async move {
- wake_and_yield_once().await;
- *x
- }
-}
-
-/* FIXME(cramertj) support when `existential type T<'a, 'b>:;` works
-async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 {
- await!(wake_and_yield_once());
- *x
-}
-*/
-
-async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 {
- wake_and_yield_once().await;
- *x
-}
-
-fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
- async move {
- async_fn_with_borrow_named_lifetime(&y).await
- }
-}
-
-unsafe async fn unsafe_async_fn(x: u8) -> u8 {
- wake_and_yield_once().await;
- x
-}
-
-struct Foo;
-
-trait Bar {
- fn foo() {}
-}
-
-impl Foo {
- async fn async_method(x: u8) -> u8 {
- unsafe {
- unsafe_async_fn(x).await
- }
- }
-}
-
-fn test_future_yields_once_then_returns<F, Fut>(f: F)
-where
- F: FnOnce(u8) -> Fut,
- Fut: Future<Output = u8>,
-{
- let mut fut = Box::pin(f(9));
- let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) });
- let waker = ArcWake::into_waker(counter.clone());
- let mut cx = Context::from_waker(&waker);
- assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst));
- assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx));
- assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst));
- assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx));
-}
-
-fn main() {
- macro_rules! test {
- ($($fn_name:expr,)*) => { $(
- test_future_yields_once_then_returns($fn_name);
- )* }
- }
-
- macro_rules! test_with_borrow {
- ($($fn_name:expr,)*) => { $(
- test_future_yields_once_then_returns(|x| {
- async move {
- $fn_name(&x).await
- }
- });
- )* }
- }
-
- test! {
- async_block,
- async_nonmove_block,
- async_closure,
- async_fn,
- generic_async_fn,
- async_fn_with_internal_borrow,
- Foo::async_method,
- |x| {
- async move {
- unsafe { unsafe_async_fn(x).await }
- }
- },
- }
- test_with_borrow! {
- async_block_with_borrow_named_lifetime,
- async_fn_with_borrow,
- async_fn_with_borrow_named_lifetime,
- async_fn_with_impl_future_named_lifetime,
- |x| {
- async move {
- async_fn_multiple_args_named_lifetime(x, x).await
- }
- },
- }
-}
+++ /dev/null
-// edition:2018
-// aux-build:arc_wake.rs
-
-#![feature(async_await, await_macro)]
-
-extern crate arc_wake;
-
-use std::pin::Pin;
-use std::future::Future;
-use std::sync::{
- Arc,
- atomic::{self, AtomicUsize},
-};
-use std::task::{Context, Poll};
-use arc_wake::ArcWake;
-
-struct Counter {
- wakes: AtomicUsize,
-}
-
-impl ArcWake for Counter {
- fn wake(self: Arc<Self>) {
- Self::wake_by_ref(&self)
- }
- fn wake_by_ref(arc_self: &Arc<Self>) {
- arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
- }
-}
-
-struct WakeOnceThenComplete(bool);
-
-fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) }
-
-impl Future for WakeOnceThenComplete {
- type Output = ();
- fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
- if self.0 {
- Poll::Ready(())
- } else {
- cx.waker().wake_by_ref();
- self.0 = true;
- Poll::Pending
- }
- }
-}
-
-fn async_block(x: u8) -> impl Future<Output = u8> {
- async move {
- await!(wake_and_yield_once());
- x
- }
-}
-
-fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
- async move {
- await!(wake_and_yield_once());
- *x
- }
-}
-
-fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
- async move {
- let future = async {
- await!(wake_and_yield_once());
- x
- };
- await!(future)
- }
-}
-
-fn async_closure(x: u8) -> impl Future<Output = u8> {
- (async move |x: u8| -> u8 {
- await!(wake_and_yield_once());
- x
- })(x)
-}
-
-async fn async_fn(x: u8) -> u8 {
- await!(wake_and_yield_once());
- x
-}
-
-async fn generic_async_fn<T>(x: T) -> T {
- await!(wake_and_yield_once());
- x
-}
-
-async fn async_fn_with_borrow(x: &u8) -> u8 {
- await!(wake_and_yield_once());
- *x
-}
-
-async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 {
- await!(wake_and_yield_once());
- *x
-}
-
-fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
- async move {
- await!(wake_and_yield_once());
- *x
- }
-}
-
-/* FIXME(cramertj) support when `existential type T<'a, 'b>:;` works
-async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 {
- await!(wake_and_yield_once());
- *x
-}
-*/
-
-async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 {
- await!(wake_and_yield_once());
- *x
-}
-
-fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
- async move {
- await!(async_fn_with_borrow_named_lifetime(&y))
- }
-}
-
-unsafe async fn unsafe_async_fn(x: u8) -> u8 {
- await!(wake_and_yield_once());
- x
-}
-
-struct Foo;
-
-trait Bar {
- fn foo() {}
-}
-
-impl Foo {
- async fn async_method(x: u8) -> u8 {
- unsafe {
- await!(unsafe_async_fn(x))
- }
- }
-}
-
-fn test_future_yields_once_then_returns<F, Fut>(f: F)
-where
- F: FnOnce(u8) -> Fut,
- Fut: Future<Output = u8>,
-{
- let mut fut = Box::pin(f(9));
- let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) });
- let waker = ArcWake::into_waker(counter.clone());
- let mut cx = Context::from_waker(&waker);
- assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst));
- assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx));
- assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst));
- assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx));
-}
-
-fn main() {
- macro_rules! test {
- ($($fn_name:expr,)*) => { $(
- test_future_yields_once_then_returns($fn_name);
- )* }
- }
-
- macro_rules! test_with_borrow {
- ($($fn_name:expr,)*) => { $(
- test_future_yields_once_then_returns(|x| {
- async move {
- await!($fn_name(&x))
- }
- });
- )* }
- }
-
- test! {
- async_block,
- async_nonmove_block,
- async_closure,
- async_fn,
- generic_async_fn,
- async_fn_with_internal_borrow,
- Foo::async_method,
- |x| {
- async move {
- unsafe { await!(unsafe_async_fn(x)) }
- }
- },
- }
- test_with_borrow! {
- async_block_with_borrow_named_lifetime,
- async_fn_with_borrow,
- async_fn_with_borrow_named_lifetime,
- async_fn_with_impl_future_named_lifetime,
- |x| {
- async move {
- await!(async_fn_multiple_args_named_lifetime(x, x))
- }
- },
- }
-}
+++ /dev/null
-// compile-flags: --edition=2018
-
-#![feature(async_await, await_macro)]
-
-pub enum Uninhabited { }
-
-fn uninhabited_async() -> Uninhabited {
- unreachable!()
-}
-
-async fn noop() { }
-
-#[allow(unused)]
-async fn contains_never() {
- let error = uninhabited_async();
- await!(noop());
- let error2 = error;
-}
-
-#[allow(unused_must_use)]
-fn main() {
- contains_never();
-}
+++ /dev/null
-// edition:2018
-// run-pass
-
-#![feature(async_await)]
-
-trait Foo { }
-
-impl Foo for () { }
-
-impl<'a, T> Foo for &'a mut T where T: Foo { }
-
-async fn foo_async<T>(_v: T) -> u8 where T: Foo {
- 0
-}
-
-async fn bad<T>(v: T) -> u8 where T: Foo {
- foo_async(v).await
-}
-
-async fn async_main() {
- let mut v = ();
-
- let _ = bad(&mut v).await;
- let _ = foo_async(&mut v).await;
- let _ = bad(v).await;
-}
-
-fn main() {
- let _ = async_main();
-}
#![feature(fnbox)]
+#![allow(deprecated, deprecated_in_future)]
use std::boxed::FnBox;
+++ /dev/null
-fn inside_closure(x: &mut i32) {
-}
-
-fn outside_closure_1(x: &mut i32) {
-}
-
-fn outside_closure_2(x: &i32) {
-}
-
-fn foo(a: &mut i32) {
- let bar = || {
- inside_closure(a)
- };
- outside_closure_1(a);
- //~^ ERROR cannot borrow `*a` as mutable because previous closure requires unique access
-
- outside_closure_2(a);
- //~^ ERROR cannot borrow `*a` as immutable because previous closure requires unique access
-
- drop(bar);
-}
-
-fn main() {
-}
+++ /dev/null
-error[E0501]: cannot borrow `*a` as mutable because previous closure requires unique access
- --> $DIR/E0501.rs:14:23
- |
-LL | let bar = || {
- | -- closure construction occurs here
-LL | inside_closure(a)
- | - first borrow occurs due to use of `a` in closure
-LL | };
-LL | outside_closure_1(a);
- | ^ second borrow occurs here
-...
-LL | drop(bar);
- | --- first borrow later used here
-
-error[E0501]: cannot borrow `*a` as immutable because previous closure requires unique access
- --> $DIR/E0501.rs:17:23
- |
-LL | let bar = || {
- | -- closure construction occurs here
-LL | inside_closure(a)
- | - first borrow occurs due to use of `a` in closure
-...
-LL | outside_closure_2(a);
- | ^ second borrow occurs here
-...
-LL | drop(bar);
- | --- first borrow later used here
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0501`.
+++ /dev/null
-struct FancyNum {
- num: u8,
-}
-
-fn main() {
- let mut fancy_num = FancyNum { num: 5 };
- let fancy_ref = &fancy_num;
- fancy_num = FancyNum { num: 6 }; //~ ERROR [E0506]
-
- println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num);
-}
+++ /dev/null
-error[E0506]: cannot assign to `fancy_num` because it is borrowed
- --> $DIR/E0506.rs:8:5
- |
-LL | let fancy_ref = &fancy_num;
- | ---------- borrow of `fancy_num` occurs here
-LL | fancy_num = FancyNum { num: 6 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `fancy_num` occurs here
-LL |
-LL | println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num);
- | ------------- borrow later used here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0506`.
+++ /dev/null
-struct NonCopy;
-
-fn main() {
- let array = [NonCopy; 1];
- let _value = array[0]; //~ ERROR [E0508]
-}
+++ /dev/null
-error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array
- --> $DIR/E0508-fail.rs:5:18
- |
-LL | let _value = array[0];
- | ^^^^^^^^
- | |
- | 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`.
+++ /dev/null
-struct NonCopy;
-
-fn main() {
- let array = [NonCopy; 1];
- let _value = array[0]; //~ ERROR [E0508]
-}
+++ /dev/null
-error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array
- --> $DIR/E0508.rs:5:18
- |
-LL | let _value = array[0];
- | ^^^^^^^^
- | |
- | 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`.
+++ /dev/null
-mod module_that_doesnt_exist; //~ ERROR E0583
-
-fn main() {
-}
+++ /dev/null
-error[E0583]: file not found for module `module_that_doesnt_exist`
- --> $DIR/E0583.rs:1:5
- |
-LL | mod module_that_doesnt_exist;
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: name the file either module_that_doesnt_exist.rs or module_that_doesnt_exist/mod.rs inside the directory "$DIR"
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0583`.
+++ /dev/null
-static NUM: i32 = 18;
-
-fn main() {
- NUM = 20; //~ ERROR cannot assign to immutable static item `NUM`
-}
+++ /dev/null
-error[E0594]: cannot assign to immutable static item `NUM`
- --> $DIR/E0594.rs:4:5
- |
-LL | NUM = 20;
- | ^^^^^^^^ cannot assign
-
-error: aborting due to previous error
-
+++ /dev/null
-fn main() {
- let x = 1;
- let y = &mut x; //~ ERROR [E0596]
-}
+++ /dev/null
-error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
- --> $DIR/E0596.rs:3:13
- |
-LL | let x = 1;
- | - help: consider changing this to be mutable: `mut x`
-LL | let y = &mut x;
- | ^^^^^^ cannot borrow as mutable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0596`.
+++ /dev/null
-#[derive(Clone, Copy)]
-struct S;
-
-trait T {
- fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in methods without bodies
-
- fn bar((x, y): (i32, i32)) {} //~ ERROR patterns aren't allowed in methods without bodies
-
- fn method(S { .. }: S) {} //~ ERROR patterns aren't allowed in methods without bodies
-
- fn f(&ident: &S) {} // ok
- fn g(&&ident: &&S) {} // ok
- fn h(mut ident: S) {} // ok
-}
-
-fn main() {}
+++ /dev/null
-error[E0642]: patterns aren't allowed in methods without bodies
- --> $DIR/E0642.rs:5:12
- |
-LL | fn foo((x, y): (i32, i32));
- | ^^^^^^
-help: give this argument a name or use an underscore to ignore it
- |
-LL | fn foo(_: (i32, i32));
- | ^
-
-error[E0642]: patterns aren't allowed in methods without bodies
- --> $DIR/E0642.rs:7:12
- |
-LL | fn bar((x, y): (i32, i32)) {}
- | ^^^^^^
-help: give this argument a name or use an underscore to ignore it
- |
-LL | fn bar(_: (i32, i32)) {}
- | ^
-
-error[E0642]: patterns aren't allowed in methods without bodies
- --> $DIR/E0642.rs:9:15
- |
-LL | fn method(S { .. }: S) {}
- | ^^^^^^^^
-help: give this argument a name or use an underscore to ignore it
- |
-LL | fn method(_: S) {}
- | ^
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0642`.
+++ /dev/null
-#![feature(asm)]
-
-fn main() {
- let a;
- asm!("nop" "nop");
- //~^ ERROR E0660
- asm!("nop" "nop" : "=r"(a));
- //~^ ERROR E0660
-}
+++ /dev/null
-error[E0660]: malformed inline assembly
- --> $DIR/E0660.rs:5:5
- |
-LL | asm!("nop" "nop");
- | ^^^^^^^^^^^^^^^^^^
-
-error[E0660]: malformed inline assembly
- --> $DIR/E0660.rs:7:5
- |
-LL | asm!("nop" "nop" : "=r"(a));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-#![feature(asm)]
-
-fn main() {
- let a;
- asm!("nop" : "r"(a));
- //~^ ERROR E0661
-}
+++ /dev/null
-error[E0661]: output operand constraint lacks '=' or '+'
- --> $DIR/E0661.rs:5:18
- |
-LL | asm!("nop" : "r"(a));
- | ^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-#![feature(asm)]
-
-fn main() {
- asm!("xor %eax, %eax"
- :
- : "=test"("a") //~ ERROR E0662
- );
-}
+++ /dev/null
-error[E0662]: input operand constraint contains '='
- --> $DIR/E0662.rs:6:12
- |
-LL | : "=test"("a")
- | ^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-#![feature(asm)]
-
-fn main() {
- asm!("xor %eax, %eax"
- :
- : "+test"("a") //~ ERROR E0663
- );
-}
+++ /dev/null
-error[E0663]: input operand constraint contains '+'
- --> $DIR/E0663.rs:6:12
- |
-LL | : "+test"("a")
- | ^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-#![feature(asm)]
-
-fn main() {
- asm!("mov $$0x200, %eax"
- :
- :
- : "{eax}" //~ ERROR E0664
- );
-}
+++ /dev/null
-error[E0664]: clobber should not be surrounded by braces
- --> $DIR/E0664.rs:7:12
- |
-LL | : "{eax}"
- | ^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-#[derive(Default)] //~ ERROR E0665
-enum Food {
- Sweet,
- Salty,
-}
-
-fn main() {
-}
+++ /dev/null
-error[E0665]: `Default` cannot be derived for enums, only structs
- --> $DIR/E0665.rs:1:10
- |
-LL | #[derive(Default)]
- | ^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-// compile-pass
-
-// This is a stub feature that doesn't control anything, so to make tidy happy,
-// gate-test-test_2018_feature
-
-#![feature(test_2018_feature)]
-//~^ WARN the feature `test_2018_feature` is included in the Rust 2018 edition
-#![feature(rust_2018_preview)]
-
-fn main() {}
+++ /dev/null
-warning[E0705]: the feature `test_2018_feature` is included in the Rust 2018 edition
- --> $DIR/E0705.rs:6:12
- |
-LL | #![feature(test_2018_feature)]
- | ^^^^^^^^^^^^^^^^^
-
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0284`.
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0284`.
--- /dev/null
+// run-pass
+
+// edition:2018
+// aux-build:arc_wake.rs
+
+#![feature(async_await)]
+
+extern crate arc_wake;
+
+use std::pin::Pin;
+use std::future::Future;
+use std::sync::{
+ Arc,
+ atomic::{self, AtomicUsize},
+};
+use std::task::{Context, Poll};
+use arc_wake::ArcWake;
+
+struct Counter {
+ wakes: AtomicUsize,
+}
+
+impl ArcWake for Counter {
+ fn wake(self: Arc<Self>) {
+ Self::wake_by_ref(&self)
+ }
+ fn wake_by_ref(arc_self: &Arc<Self>) {
+ arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
+ }
+}
+
+struct WakeOnceThenComplete(bool);
+
+fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) }
+
+impl Future for WakeOnceThenComplete {
+ type Output = ();
+ fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
+ if self.0 {
+ Poll::Ready(())
+ } else {
+ cx.waker().wake_by_ref();
+ self.0 = true;
+ Poll::Pending
+ }
+ }
+}
+
+fn async_block(x: u8) -> impl Future<Output = u8> {
+ async move {
+ wake_and_yield_once().await;
+ x
+ }
+}
+
+fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
+ async move {
+ wake_and_yield_once().await;
+ *x
+ }
+}
+
+fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
+ async move {
+ let future = async {
+ wake_and_yield_once().await;
+ x
+ };
+ future.await
+ }
+}
+
+fn async_closure(x: u8) -> impl Future<Output = u8> {
+ (async move |x: u8| -> u8 {
+ wake_and_yield_once().await;
+ x
+ })(x)
+}
+
+async fn async_fn(x: u8) -> u8 {
+ wake_and_yield_once().await;
+ x
+}
+
+async fn generic_async_fn<T>(x: T) -> T {
+ wake_and_yield_once().await;
+ x
+}
+
+async fn async_fn_with_borrow(x: &u8) -> u8 {
+ wake_and_yield_once().await;
+ *x
+}
+
+async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 {
+ wake_and_yield_once().await;
+ *x
+}
+
+fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
+ async move {
+ wake_and_yield_once().await;
+ *x
+ }
+}
+
+/* FIXME(cramertj) support when `existential type T<'a, 'b>:;` works
+async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 {
+ await!(wake_and_yield_once());
+ *x
+}
+*/
+
+async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 {
+ wake_and_yield_once().await;
+ *x
+}
+
+fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
+ async move {
+ async_fn_with_borrow_named_lifetime(&y).await
+ }
+}
+
+unsafe async fn unsafe_async_fn(x: u8) -> u8 {
+ wake_and_yield_once().await;
+ x
+}
+
+struct Foo;
+
+trait Bar {
+ fn foo() {}
+}
+
+impl Foo {
+ async fn async_method(x: u8) -> u8 {
+ unsafe {
+ unsafe_async_fn(x).await
+ }
+ }
+}
+
+fn test_future_yields_once_then_returns<F, Fut>(f: F)
+where
+ F: FnOnce(u8) -> Fut,
+ Fut: Future<Output = u8>,
+{
+ let mut fut = Box::pin(f(9));
+ let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) });
+ let waker = ArcWake::into_waker(counter.clone());
+ let mut cx = Context::from_waker(&waker);
+ assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst));
+ assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx));
+ assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst));
+ assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx));
+}
+
+fn main() {
+ macro_rules! test {
+ ($($fn_name:expr,)*) => { $(
+ test_future_yields_once_then_returns($fn_name);
+ )* }
+ }
+
+ macro_rules! test_with_borrow {
+ ($($fn_name:expr,)*) => { $(
+ test_future_yields_once_then_returns(|x| {
+ async move {
+ $fn_name(&x).await
+ }
+ });
+ )* }
+ }
+
+ test! {
+ async_block,
+ async_nonmove_block,
+ async_closure,
+ async_fn,
+ generic_async_fn,
+ async_fn_with_internal_borrow,
+ Foo::async_method,
+ |x| {
+ async move {
+ unsafe { unsafe_async_fn(x).await }
+ }
+ },
+ }
+ test_with_borrow! {
+ async_block_with_borrow_named_lifetime,
+ async_fn_with_borrow,
+ async_fn_with_borrow_named_lifetime,
+ async_fn_with_impl_future_named_lifetime,
+ |x| {
+ async move {
+ async_fn_multiple_args_named_lifetime(x, x).await
+ }
+ },
+ }
+}
--- /dev/null
+// edition:2018
+
+#![feature(arbitrary_self_types, async_await, await_macro, pin)]
+
+use std::ops::Add;
+
+async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
+//~^ ERROR ambiguous lifetime bound in `async fn`
+
+async fn multiple_hrtb_and_single_named_lifetime_ok<'c>(
+ _: impl for<'a> Add<&'a u8>,
+ _: impl for<'b> Add<&'b u8>,
+ _: &'c u8,
+) {}
+
+async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
+//~^ ambiguous lifetime bound in `async fn`
+
+fn main() {}
--- /dev/null
+error: ambiguous lifetime bound in `async fn`
+ --> $DIR/async-fn-multiple-lifetimes.rs:7:65
+ |
+LL | async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
+ | ^ neither `'a` nor `'b` outlives the other
+ |
+ = note: multiple unrelated lifetimes are not allowed in `async fn`.
+ = note: if you're using argument-position elided lifetimes, consider switching to a single named lifetime.
+
+error: ambiguous lifetime bound in `async fn`
+ --> $DIR/async-fn-multiple-lifetimes.rs:16:52
+ |
+LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
+ | ^ the elided lifetimes here do not outlive one another
+ |
+ = note: multiple unrelated lifetimes are not allowed in `async fn`.
+ = note: if you're using argument-position elided lifetimes, consider switching to a single named lifetime.
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// edition:2018
+
+#![feature(async_await, await_macro)]
+#![allow(dead_code)]
+
+struct HasLifetime<'a>(&'a bool);
+
+async fn error(lt: HasLifetime) { //~ ERROR implicit elided lifetime not allowed here
+ if *lt.0 {}
+}
+
+fn no_error(lt: HasLifetime) {
+ if *lt.0 {}
+}
+
+fn main() {}
--- /dev/null
+error[E0726]: implicit elided lifetime not allowed here
+ --> $DIR/async-fn-path-elision.rs:8:20
+ |
+LL | async fn error(lt: HasLifetime) {
+ | ^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+
+error: aborting due to previous error
+
--- /dev/null
+// compile-pass
+// edition:2018
+
+#![feature(async_await, await_macro)]
+
+macro_rules! match_expr {
+ ($x:expr) => {}
+}
+
+fn main() {
+ match_expr!(async {});
+ match_expr!(async || {});
+}
--- /dev/null
+// compile-pass
+// edition:2018
+
+#![feature(async_await, await_macro)]
+
+trait MyClosure {
+ type Args;
+}
+
+impl<R> MyClosure for dyn FnMut() -> R
+where R: 'static {
+ type Args = ();
+}
+
+struct MyStream<C: ?Sized + MyClosure> {
+ x: C::Args,
+}
+
+async fn get_future<C: ?Sized + MyClosure>(_stream: MyStream<C>) {}
+
+async fn f() {
+ let messages: MyStream<FnMut()> = unimplemented!();
+ await!(get_future(messages));
+}
+
+fn main() {}
+++ /dev/null
-// force-host
-// no-prefer-dynamic
-#![crate_type = "proc-macro"]
-
-extern crate proc_macro;
-use proc_macro::TokenStream;
-
-#[proc_macro_attribute]
-pub fn attr(_args: TokenStream, input: TokenStream) -> TokenStream {
- println!("{}", input);
- TokenStream::new()
-}
--- /dev/null
+#![feature(async_await, await_macro)]
+#![allow(non_camel_case_types)]
+#![deny(keyword_idents)]
+
+mod outer_mod {
+ pub mod await { //~ ERROR `await` is a keyword in the 2018 edition
+ //~^ WARN this was previously accepted by the compiler
+ pub struct await; //~ ERROR `await` is a keyword in the 2018 edition
+ //~^ WARN this was previously accepted by the compiler
+ }
+}
+use outer_mod::await::await; //~ ERROR `await` is a keyword in the 2018 edition
+//~^ ERROR `await` is a keyword in the 2018 edition
+//~^^ WARN this was previously accepted by the compiler
+//~^^^ WARN this was previously accepted by the compiler
+
+struct Foo { await: () }
+//~^ ERROR `await` is a keyword in the 2018 edition
+//~^^ WARN this was previously accepted by the compiler
+
+impl Foo { fn await() {} }
+//~^ ERROR `await` is a keyword in the 2018 edition
+//~^^ WARN this was previously accepted by the compiler
+
+macro_rules! await {
+//~^ ERROR `await` is a keyword in the 2018 edition
+//~^^ WARN this was previously accepted by the compiler
+ () => {}
+}
+
+fn main() {
+ match await { await => {} } //~ ERROR `await` is a keyword in the 2018 edition
+ //~^ ERROR `await` is a keyword in the 2018 edition
+ //~^^ WARN this was previously accepted by the compiler
+ //~^^^ WARN this was previously accepted by the compiler
+}
--- /dev/null
+error: `await` is a keyword in the 2018 edition
+ --> $DIR/2015-edition-error-in-non-macro-position.rs:6:13
+ |
+LL | pub mod await {
+ | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+ |
+note: lint level defined here
+ --> $DIR/2015-edition-error-in-non-macro-position.rs:3:9
+ |
+LL | #![deny(keyword_idents)]
+ | ^^^^^^^^^^^^^^
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+ --> $DIR/2015-edition-error-in-non-macro-position.rs:8:20
+ |
+LL | pub struct await;
+ | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+ --> $DIR/2015-edition-error-in-non-macro-position.rs:12:16
+ |
+LL | use outer_mod::await::await;
+ | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+ --> $DIR/2015-edition-error-in-non-macro-position.rs:12:23
+ |
+LL | use outer_mod::await::await;
+ | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+ --> $DIR/2015-edition-error-in-non-macro-position.rs:17:14
+ |
+LL | struct Foo { await: () }
+ | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+ --> $DIR/2015-edition-error-in-non-macro-position.rs:21:15
+ |
+LL | impl Foo { fn await() {} }
+ | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+ --> $DIR/2015-edition-error-in-non-macro-position.rs:25:14
+ |
+LL | macro_rules! await {
+ | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+ --> $DIR/2015-edition-error-in-non-macro-position.rs:32:11
+ |
+LL | match await { await => {} }
+ | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+ --> $DIR/2015-edition-error-in-non-macro-position.rs:32:19
+ |
+LL | match await { await => {} }
+ | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: aborting due to 9 previous errors
+
--- /dev/null
+// run-rustfix
+
+#![allow(non_camel_case_types)]
+#![deny(keyword_idents)]
+
+mod outer_mod {
+ pub mod r#await {
+//~^ ERROR `await` is a keyword
+//~| WARN was previously accepted
+ pub struct r#await;
+//~^ ERROR `await` is a keyword
+//~| WARN was previously accepted
+ }
+}
+use outer_mod::r#await::r#await;
+//~^ ERROR `await` is a keyword
+//~| ERROR `await` is a keyword
+//~| WARN was previously accepted
+//~| WARN was previously accepted
+
+fn main() {
+ match r#await { r#await => {} }
+//~^ ERROR `await` is a keyword
+//~| ERROR `await` is a keyword
+//~| WARN was previously accepted
+//~| WARN was previously accepted
+}
--- /dev/null
+// run-rustfix
+
+#![allow(non_camel_case_types)]
+#![deny(keyword_idents)]
+
+mod outer_mod {
+ pub mod await {
+//~^ ERROR `await` is a keyword
+//~| WARN was previously accepted
+ pub struct await;
+//~^ ERROR `await` is a keyword
+//~| WARN was previously accepted
+ }
+}
+use outer_mod::await::await;
+//~^ ERROR `await` is a keyword
+//~| ERROR `await` is a keyword
+//~| WARN was previously accepted
+//~| WARN was previously accepted
+
+fn main() {
+ match await { await => {} }
+//~^ ERROR `await` is a keyword
+//~| ERROR `await` is a keyword
+//~| WARN was previously accepted
+//~| WARN was previously accepted
+}
--- /dev/null
+error: `await` is a keyword in the 2018 edition
+ --> $DIR/2015-edition-warning.rs:7:13
+ |
+LL | pub mod await {
+ | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+ |
+note: lint level defined here
+ --> $DIR/2015-edition-warning.rs:4:9
+ |
+LL | #![deny(keyword_idents)]
+ | ^^^^^^^^^^^^^^
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+ --> $DIR/2015-edition-warning.rs:10:20
+ |
+LL | pub struct await;
+ | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+ --> $DIR/2015-edition-warning.rs:15:16
+ |
+LL | use outer_mod::await::await;
+ | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+ --> $DIR/2015-edition-warning.rs:15:23
+ |
+LL | use outer_mod::await::await;
+ | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+ --> $DIR/2015-edition-warning.rs:22:11
+ |
+LL | match await { await => {} }
+ | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: `await` is a keyword in the 2018 edition
+ --> $DIR/2015-edition-warning.rs:22:19
+ |
+LL | match await { await => {} }
+ | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: aborting due to 6 previous errors
+
--- /dev/null
+// edition:2018
+
+#![allow(non_camel_case_types)]
+#![feature(async_await, await_macro)]
+
+mod outer_mod {
+ pub mod await { //~ ERROR expected identifier, found reserved keyword `await`
+ pub struct await; //~ ERROR expected identifier, found reserved keyword `await`
+ }
+}
+use self::outer_mod::await::await; //~ ERROR expected identifier, found reserved keyword `await`
+//~^ ERROR expected identifier, found reserved keyword `await`
+
+struct Foo { await: () }
+//~^ ERROR expected identifier, found reserved keyword `await`
+
+impl Foo { fn await() {} }
+//~^ ERROR expected identifier, found reserved keyword `await`
+
+macro_rules! await {
+//~^ ERROR expected identifier, found reserved keyword `await`
+ () => {}
+}
+
+fn main() {}
--- /dev/null
+error: expected identifier, found reserved keyword `await`
+ --> $DIR/2018-edition-error-in-non-macro-position.rs:7:13
+ |
+LL | pub mod await {
+ | ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+ |
+LL | pub mod r#await {
+ | ^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+ --> $DIR/2018-edition-error-in-non-macro-position.rs:8:20
+ |
+LL | pub struct await;
+ | ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+ |
+LL | pub struct r#await;
+ | ^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+ --> $DIR/2018-edition-error-in-non-macro-position.rs:11:22
+ |
+LL | use self::outer_mod::await::await;
+ | ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+ |
+LL | use self::outer_mod::r#await::await;
+ | ^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+ --> $DIR/2018-edition-error-in-non-macro-position.rs:11:29
+ |
+LL | use self::outer_mod::await::await;
+ | ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+ |
+LL | use self::outer_mod::await::r#await;
+ | ^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+ --> $DIR/2018-edition-error-in-non-macro-position.rs:14:14
+ |
+LL | struct Foo { await: () }
+ | ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+ |
+LL | struct Foo { r#await: () }
+ | ^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+ --> $DIR/2018-edition-error-in-non-macro-position.rs:17:15
+ |
+LL | impl Foo { fn await() {} }
+ | ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+ |
+LL | impl Foo { fn r#await() {} }
+ | ^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+ --> $DIR/2018-edition-error-in-non-macro-position.rs:20:14
+ |
+LL | macro_rules! await {
+ | ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+ |
+LL | macro_rules! r#await {
+ | ^^^^^^^
+
+error: aborting due to 7 previous errors
+
--- /dev/null
+// edition:2018
+#![allow(non_camel_case_types)]
+
+mod outer_mod {
+ pub mod await { //~ ERROR expected identifier
+ pub struct await; //~ ERROR expected identifier
+ }
+}
+use self::outer_mod::await::await; //~ ERROR expected identifier
+ //~^ ERROR expected identifier, found reserved keyword `await`
+
+fn main() {}
--- /dev/null
+error: expected identifier, found reserved keyword `await`
+ --> $DIR/2018-edition-error.rs:5:13
+ |
+LL | pub mod await {
+ | ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+ |
+LL | pub mod r#await {
+ | ^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+ --> $DIR/2018-edition-error.rs:6:20
+ |
+LL | pub struct await;
+ | ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+ |
+LL | pub struct r#await;
+ | ^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+ --> $DIR/2018-edition-error.rs:9:22
+ |
+LL | use self::outer_mod::await::await;
+ | ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+ |
+LL | use self::outer_mod::r#await::await;
+ | ^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+ --> $DIR/2018-edition-error.rs:9:29
+ |
+LL | use self::outer_mod::await::await;
+ | ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+ |
+LL | use self::outer_mod::await::r#await;
+ | ^^^^^^^
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+// edition:2018
+
+#![feature(async_await)]
+
+async fn bar() -> Result<(), ()> {
+ Ok(())
+}
+
+async fn foo1() -> Result<(), ()> {
+ let _ = await bar(); //~ ERROR incorrect use of `await`
+ Ok(())
+}
+async fn foo2() -> Result<(), ()> {
+ let _ = await? bar(); //~ ERROR incorrect use of `await`
+ Ok(())
+}
+async fn foo3() -> Result<(), ()> {
+ let _ = await bar()?; //~ ERROR incorrect use of `await`
+ //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
+ Ok(())
+}
+async fn foo21() -> Result<(), ()> {
+ let _ = await { bar() }; //~ ERROR incorrect use of `await`
+ Ok(())
+}
+async fn foo22() -> Result<(), ()> {
+ let _ = await(bar()); //~ ERROR incorrect use of `await`
+ Ok(())
+}
+async fn foo23() -> Result<(), ()> {
+ let _ = await { bar() }?; //~ ERROR incorrect use of `await`
+ Ok(())
+}
+async fn foo4() -> Result<(), ()> {
+ let _ = (await bar())?; //~ ERROR incorrect use of `await`
+ Ok(())
+}
+async fn foo5() -> Result<(), ()> {
+ let _ = bar().await(); //~ ERROR incorrect use of `await`
+ Ok(())
+}
+async fn foo6() -> Result<(), ()> {
+ let _ = bar().await()?; //~ ERROR incorrect use of `await`
+ Ok(())
+}
+async fn foo7() -> Result<(), ()> {
+ let _ = bar().await; // OK
+ Ok(())
+}
+async fn foo8() -> Result<(), ()> {
+ let _ = bar().await?; // OK
+ Ok(())
+}
+fn foo9() -> Result<(), ()> {
+ let _ = await bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks
+ //~^ ERROR incorrect use of `await`
+ Ok(())
+}
+fn foo10() -> Result<(), ()> {
+ let _ = await? bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks
+ //~^ ERROR incorrect use of `await`
+ Ok(())
+}
+fn foo11() -> Result<(), ()> {
+ let _ = await bar()?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+ //~^ ERROR incorrect use of `await`
+ Ok(())
+}
+fn foo12() -> Result<(), ()> {
+ let _ = (await bar())?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+ //~^ ERROR incorrect use of `await`
+ Ok(())
+}
+fn foo13() -> Result<(), ()> {
+ let _ = bar().await(); //~ ERROR `await` is only allowed inside `async` functions and blocks
+ //~^ ERROR incorrect use of `await`
+ Ok(())
+}
+fn foo14() -> Result<(), ()> {
+ let _ = bar().await()?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+ //~^ ERROR incorrect use of `await`
+ Ok(())
+}
+fn foo15() -> Result<(), ()> {
+ let _ = bar().await; //~ ERROR `await` is only allowed inside `async` functions and blocks
+ Ok(())
+}
+fn foo16() -> Result<(), ()> {
+ let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+ Ok(())
+}
+fn foo24() -> Result<(), ()> {
+ fn foo() -> Result<(), ()> {
+ let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+ Ok(())
+ }
+ foo()
+}
+fn foo25() -> Result<(), ()> {
+ let foo = || {
+ let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+ Ok(())
+ };
+ foo()
+}
+
+fn main() {
+ match await { await => () }
+ //~^ ERROR expected expression, found `=>`
+ //~| ERROR incorrect use of `await`
+} //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `}`
--- /dev/null
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:10:13
+ |
+LL | let _ = await bar();
+ | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:14:13
+ |
+LL | let _ = await? bar();
+ | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?`
+
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:18:13
+ |
+LL | let _ = await bar()?;
+ | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
+
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:23:13
+ |
+LL | let _ = await { bar() };
+ | ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
+
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:27:13
+ |
+LL | let _ = await(bar());
+ | ^^^^^^^^^^^^ help: `await` is a postfix operation: `(bar()).await`
+
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:31:13
+ |
+LL | let _ = await { bar() }?;
+ | ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
+
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:35:14
+ |
+LL | let _ = (await bar())?;
+ | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:39:24
+ |
+LL | let _ = bar().await();
+ | ^^ help: `await` is not a method call, remove the parentheses
+
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:43:24
+ |
+LL | let _ = bar().await()?;
+ | ^^ help: `await` is not a method call, remove the parentheses
+
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:55:13
+ |
+LL | let _ = await bar();
+ | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:60:13
+ |
+LL | let _ = await? bar();
+ | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?`
+
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:65:13
+ |
+LL | let _ = await bar()?;
+ | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
+
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:70:14
+ |
+LL | let _ = (await bar())?;
+ | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:75:24
+ |
+LL | let _ = bar().await();
+ | ^^ help: `await` is not a method call, remove the parentheses
+
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:80:24
+ |
+LL | let _ = bar().await()?;
+ | ^^ help: `await` is not a method call, remove the parentheses
+
+error: expected expression, found `=>`
+ --> $DIR/incorrect-syntax-suggestions.rs:108:25
+ |
+LL | match await { await => () }
+ | ----- ^^ expected expression
+ | |
+ | while parsing this incorrect await expression
+
+error: incorrect use of `await`
+ --> $DIR/incorrect-syntax-suggestions.rs:108:11
+ |
+LL | match await { await => () }
+ | ^^^^^^^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ await => () }.await`
+
+error: expected one of `.`, `?`, `{`, or an operator, found `}`
+ --> $DIR/incorrect-syntax-suggestions.rs:111:1
+ |
+LL | match await { await => () }
+ | ----- - expected one of `.`, `?`, `{`, or an operator here
+ | |
+ | while parsing this match expression
+...
+LL | }
+ | ^ unexpected token
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+ --> $DIR/incorrect-syntax-suggestions.rs:55:13
+ |
+LL | fn foo9() -> Result<(), ()> {
+ | ---- this is not `async`
+LL | let _ = await bar();
+ | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+ --> $DIR/incorrect-syntax-suggestions.rs:60:13
+ |
+LL | fn foo10() -> Result<(), ()> {
+ | ----- this is not `async`
+LL | let _ = await? bar();
+ | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+ --> $DIR/incorrect-syntax-suggestions.rs:65:13
+ |
+LL | fn foo11() -> Result<(), ()> {
+ | ----- this is not `async`
+LL | let _ = await bar()?;
+ | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+ --> $DIR/incorrect-syntax-suggestions.rs:70:14
+ |
+LL | fn foo12() -> Result<(), ()> {
+ | ----- this is not `async`
+LL | let _ = (await bar())?;
+ | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+ --> $DIR/incorrect-syntax-suggestions.rs:75:13
+ |
+LL | fn foo13() -> Result<(), ()> {
+ | ----- this is not `async`
+LL | let _ = bar().await();
+ | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+ --> $DIR/incorrect-syntax-suggestions.rs:80:13
+ |
+LL | fn foo14() -> Result<(), ()> {
+ | ----- this is not `async`
+LL | let _ = bar().await()?;
+ | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+ --> $DIR/incorrect-syntax-suggestions.rs:85:13
+ |
+LL | fn foo15() -> Result<(), ()> {
+ | ----- this is not `async`
+LL | let _ = bar().await;
+ | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+ --> $DIR/incorrect-syntax-suggestions.rs:89:13
+ |
+LL | fn foo16() -> Result<(), ()> {
+ | ----- this is not `async`
+LL | let _ = bar().await?;
+ | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+ --> $DIR/incorrect-syntax-suggestions.rs:94:17
+ |
+LL | fn foo() -> Result<(), ()> {
+ | --- this is not `async`
+LL | let _ = bar().await?;
+ | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+ --> $DIR/incorrect-syntax-suggestions.rs:101:17
+ |
+LL | let foo = || {
+ | -- this is not `async`
+LL | let _ = bar().await?;
+ | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
+ --> $DIR/incorrect-syntax-suggestions.rs:18:19
+ |
+LL | let _ = await bar()?;
+ | ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future`
+ |
+ = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future`
+ = note: required by `std::ops::Try::into_result`
+
+error: aborting due to 29 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// edition:2018
+
+macro_rules! r#await {
+ () => { println!("Hello, world!") }
+}
+
+fn main() {
+ await!()
+ //~^ ERROR expected expression, found `)`
+}
--- /dev/null
+error: expected expression, found `)`
+ --> $DIR/post_expansion_error.rs:8:12
+ |
+LL | await!()
+ | ----- ^ expected expression
+ | |
+ | while parsing this await macro call
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+
+// edition:2018
+// aux-build:arc_wake.rs
+
+#![feature(async_await, await_macro)]
+
+extern crate arc_wake;
+
+use std::pin::Pin;
+use std::future::Future;
+use std::sync::{
+ Arc,
+ atomic::{self, AtomicUsize},
+};
+use std::task::{Context, Poll};
+use arc_wake::ArcWake;
+
+struct Counter {
+ wakes: AtomicUsize,
+}
+
+impl ArcWake for Counter {
+ fn wake(self: Arc<Self>) {
+ Self::wake_by_ref(&self)
+ }
+ fn wake_by_ref(arc_self: &Arc<Self>) {
+ arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
+ }
+}
+
+struct WakeOnceThenComplete(bool);
+
+fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) }
+
+impl Future for WakeOnceThenComplete {
+ type Output = ();
+ fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
+ if self.0 {
+ Poll::Ready(())
+ } else {
+ cx.waker().wake_by_ref();
+ self.0 = true;
+ Poll::Pending
+ }
+ }
+}
+
+fn async_block(x: u8) -> impl Future<Output = u8> {
+ async move {
+ await!(wake_and_yield_once());
+ x
+ }
+}
+
+fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
+ async move {
+ await!(wake_and_yield_once());
+ *x
+ }
+}
+
+fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
+ async move {
+ let future = async {
+ await!(wake_and_yield_once());
+ x
+ };
+ await!(future)
+ }
+}
+
+fn async_closure(x: u8) -> impl Future<Output = u8> {
+ (async move |x: u8| -> u8 {
+ await!(wake_and_yield_once());
+ x
+ })(x)
+}
+
+async fn async_fn(x: u8) -> u8 {
+ await!(wake_and_yield_once());
+ x
+}
+
+async fn generic_async_fn<T>(x: T) -> T {
+ await!(wake_and_yield_once());
+ x
+}
+
+async fn async_fn_with_borrow(x: &u8) -> u8 {
+ await!(wake_and_yield_once());
+ *x
+}
+
+async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 {
+ await!(wake_and_yield_once());
+ *x
+}
+
+fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
+ async move {
+ await!(wake_and_yield_once());
+ *x
+ }
+}
+
+/* FIXME(cramertj) support when `existential type T<'a, 'b>:;` works
+async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 {
+ await!(wake_and_yield_once());
+ *x
+}
+*/
+
+async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 {
+ await!(wake_and_yield_once());
+ *x
+}
+
+fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
+ async move {
+ await!(async_fn_with_borrow_named_lifetime(&y))
+ }
+}
+
+unsafe async fn unsafe_async_fn(x: u8) -> u8 {
+ await!(wake_and_yield_once());
+ x
+}
+
+struct Foo;
+
+trait Bar {
+ fn foo() {}
+}
+
+impl Foo {
+ async fn async_method(x: u8) -> u8 {
+ unsafe {
+ await!(unsafe_async_fn(x))
+ }
+ }
+}
+
+fn test_future_yields_once_then_returns<F, Fut>(f: F)
+where
+ F: FnOnce(u8) -> Fut,
+ Fut: Future<Output = u8>,
+{
+ let mut fut = Box::pin(f(9));
+ let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) });
+ let waker = ArcWake::into_waker(counter.clone());
+ let mut cx = Context::from_waker(&waker);
+ assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst));
+ assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx));
+ assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst));
+ assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx));
+}
+
+fn main() {
+ macro_rules! test {
+ ($($fn_name:expr,)*) => { $(
+ test_future_yields_once_then_returns($fn_name);
+ )* }
+ }
+
+ macro_rules! test_with_borrow {
+ ($($fn_name:expr,)*) => { $(
+ test_future_yields_once_then_returns(|x| {
+ async move {
+ await!($fn_name(&x))
+ }
+ });
+ )* }
+ }
+
+ test! {
+ async_block,
+ async_nonmove_block,
+ async_closure,
+ async_fn,
+ generic_async_fn,
+ async_fn_with_internal_borrow,
+ Foo::async_method,
+ |x| {
+ async move {
+ unsafe { await!(unsafe_async_fn(x)) }
+ }
+ },
+ }
+ test_with_borrow! {
+ async_block_with_borrow_named_lifetime,
+ async_fn_with_borrow,
+ async_fn_with_borrow_named_lifetime,
+ async_fn_with_impl_future_named_lifetime,
+ |x| {
+ async move {
+ await!(async_fn_multiple_args_named_lifetime(x, x))
+ }
+ },
+ }
+}
--- /dev/null
+// Test that we don't show variables with from async fn desugaring
+
+// edition:2018
+#![feature(async_await)]
+
+async fn async_fn(&ref mut s: &[i32]) {}
+//~^ ERROR cannot borrow data in a `&` reference as mutable [E0596]
+
+fn main() {}
--- /dev/null
+error[E0596]: cannot borrow data in a `&` reference as mutable
+ --> $DIR/dont-print-desugared-async.rs:6:20
+ |
+LL | async fn async_fn(&ref mut s: &[i32]) {}
+ | -^^^^^^^^^
+ | ||
+ | |cannot borrow as mutable through `&` reference
+ | help: consider changing this to be a mutable reference: `&mut ref mut s`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
+++ /dev/null
-// aux-build:arc_wake.rs
-// edition:2018
-// run-pass
-
-#![allow(unused_variables)]
-#![feature(async_await, await_macro)]
-
-// Test that the drop order for parameters in a fn and async fn matches up. Also test that
-// parameters (used or unused) are not dropped until the async fn completes execution.
-// See also #54716.
-
-extern crate arc_wake;
-
-use arc_wake::ArcWake;
-use std::cell::RefCell;
-use std::future::Future;
-use std::marker::PhantomData;
-use std::sync::Arc;
-use std::rc::Rc;
-use std::task::Context;
-
-struct EmptyWaker;
-
-impl ArcWake for EmptyWaker {
- fn wake(self: Arc<Self>) {}
-}
-
-#[derive(Debug, Eq, PartialEq)]
-enum DropOrder {
- Function,
- Val(&'static str),
-}
-
-type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
-
-struct D(&'static str, DropOrderListPtr);
-
-impl Drop for D {
- fn drop(&mut self) {
- self.1.borrow_mut().push(DropOrder::Val(self.0));
- }
-}
-
-/// Check that unused bindings are dropped after the function is polled.
-async fn foo_async(ref mut x: D, ref mut _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-fn foo_sync(ref mut x: D, ref mut _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-/// Check that underscore patterns are dropped after the function is polled.
-async fn bar_async(ref mut x: D, _: D) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-fn bar_sync(ref mut x: D, _: D) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-/// Check that underscore patterns within more complex patterns are dropped after the function
-/// is polled.
-async fn baz_async((ref mut x, _): (D, D)) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-fn baz_sync((ref mut x, _): (D, D)) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-/// Check that underscore and unused bindings within and outwith more complex patterns are dropped
-/// after the function is polled.
-async fn foobar_async(ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-fn foobar_sync(ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-struct Foo;
-
-impl Foo {
- /// Check that unused bindings are dropped after the method is polled.
- async fn foo_async(ref mut x: D, ref mut _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn foo_sync(ref mut x: D, ref mut _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- /// Check that underscore patterns are dropped after the method is polled.
- async fn bar_async(ref mut x: D, _: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn bar_sync(ref mut x: D, _: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- /// Check that underscore patterns within more complex patterns are dropped after the method
- /// is polled.
- async fn baz_async((ref mut x, _): (D, D)) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn baz_sync((ref mut x, _): (D, D)) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- /// Check that underscore and unused bindings within and outwith more complex patterns are
- /// dropped after the method is polled.
- async fn foobar_async(
- ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
- ) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn foobar_sync(
- ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
- ) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-}
-
-struct Bar<'a>(PhantomData<&'a ()>);
-
-impl<'a> Bar<'a> {
- /// Check that unused bindings are dropped after the method with self is polled.
- async fn foo_async(&'a self, ref mut x: D, ref mut _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn foo_sync(&'a self, ref mut x: D, ref mut _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- /// Check that underscore patterns are dropped after the method with self is polled.
- async fn bar_async(&'a self, ref mut x: D, _: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn bar_sync(&'a self, ref mut x: D, _: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- /// Check that underscore patterns within more complex patterns are dropped after the method
- /// with self is polled.
- async fn baz_async(&'a self, (ref mut x, _): (D, D)) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn baz_sync(&'a self, (ref mut x, _): (D, D)) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- /// Check that underscore and unused bindings within and outwith more complex patterns are
- /// dropped after the method with self is polled.
- async fn foobar_async(
- &'a self, ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
- ) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn foobar_sync(
- &'a self, ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
- ) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-}
-
-fn assert_drop_order_after_poll<Fut: Future<Output = ()>>(
- f: impl FnOnce(DropOrderListPtr) -> Fut,
- g: impl FnOnce(DropOrderListPtr),
-) {
- let empty = Arc::new(EmptyWaker);
- let waker = ArcWake::into_waker(empty);
- let mut cx = Context::from_waker(&waker);
-
- let actual_order = Rc::new(RefCell::new(Vec::new()));
- let mut fut = Box::pin(f(actual_order.clone()));
- let _ = fut.as_mut().poll(&mut cx);
-
- let expected_order = Rc::new(RefCell::new(Vec::new()));
- g(expected_order.clone());
-
- assert_eq!(*actual_order.borrow(), *expected_order.borrow());
-}
-
-fn main() {
- // Free functions (see doc comment on function for what it tests).
- assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())),
- |l| foo_sync(D("x", l.clone()), D("_y", l.clone())));
- assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())),
- |l| bar_sync(D("x", l.clone()), D("_", l.clone())));
- assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))),
- |l| baz_sync((D("x", l.clone()), D("_", l.clone()))));
- assert_drop_order_after_poll(
- |l| {
- foobar_async(
- D("x", l.clone()),
- (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
- D("_", l.clone()),
- D("_y", l.clone()),
- )
- },
- |l| {
- foobar_sync(
- D("x", l.clone()),
- (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
- D("_", l.clone()),
- D("_y", l.clone()),
- )
- },
- );
-
- // Methods w/out self (see doc comment on function for what it tests).
- assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())),
- |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone())));
- assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())),
- |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone())));
- assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))),
- |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone()))));
- assert_drop_order_after_poll(
- |l| {
- Foo::foobar_async(
- D("x", l.clone()),
- (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
- D("_", l.clone()),
- D("_y", l.clone()),
- )
- },
- |l| {
- Foo::foobar_sync(
- D("x", l.clone()),
- (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
- D("_", l.clone()),
- D("_y", l.clone()),
- )
- },
- );
-
- // Methods (see doc comment on function for what it tests).
- let b = Bar(Default::default());
- assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())),
- |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone())));
- assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())),
- |l| b.bar_sync(D("x", l.clone()), D("_", l.clone())));
- assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))),
- |l| b.baz_sync((D("x", l.clone()), D("_", l.clone()))));
- assert_drop_order_after_poll(
- |l| {
- b.foobar_async(
- D("x", l.clone()),
- (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
- D("_", l.clone()),
- D("_y", l.clone()),
- )
- },
- |l| {
- b.foobar_sync(
- D("x", l.clone()),
- (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
- D("_", l.clone()),
- D("_y", l.clone()),
- )
- },
- );
-}
+++ /dev/null
-// aux-build:arc_wake.rs
-// edition:2018
-// run-pass
-
-#![allow(unused_variables)]
-#![feature(async_await, await_macro)]
-
-// Test that the drop order for parameters in a fn and async fn matches up. Also test that
-// parameters (used or unused) are not dropped until the async fn completes execution.
-// See also #54716.
-
-extern crate arc_wake;
-
-use arc_wake::ArcWake;
-use std::cell::RefCell;
-use std::future::Future;
-use std::marker::PhantomData;
-use std::sync::Arc;
-use std::rc::Rc;
-use std::task::Context;
-
-struct EmptyWaker;
-
-impl ArcWake for EmptyWaker {
- fn wake(self: Arc<Self>) {}
-}
-
-#[derive(Debug, Eq, PartialEq)]
-enum DropOrder {
- Function,
- Val(&'static str),
-}
-
-type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
-
-struct D(&'static str, DropOrderListPtr);
-
-impl Drop for D {
- fn drop(&mut self) {
- self.1.borrow_mut().push(DropOrder::Val(self.0));
- }
-}
-
-/// Check that unused bindings are dropped after the function is polled.
-async fn foo_async(x: D, _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-fn foo_sync(x: D, _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-/// Check that underscore patterns are dropped after the function is polled.
-async fn bar_async(x: D, _: D) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-fn bar_sync(x: D, _: D) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-/// Check that underscore patterns within more complex patterns are dropped after the function
-/// is polled.
-async fn baz_async((x, _): (D, D)) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-fn baz_sync((x, _): (D, D)) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-/// Check that underscore and unused bindings within and outwith more complex patterns are dropped
-/// after the function is polled.
-async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
-}
-
-struct Foo;
-
-impl Foo {
- /// Check that unused bindings are dropped after the method is polled.
- async fn foo_async(x: D, _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn foo_sync(x: D, _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- /// Check that underscore patterns are dropped after the method is polled.
- async fn bar_async(x: D, _: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn bar_sync(x: D, _: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- /// Check that underscore patterns within more complex patterns are dropped after the method
- /// is polled.
- async fn baz_async((x, _): (D, D)) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn baz_sync((x, _): (D, D)) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- /// Check that underscore and unused bindings within and outwith more complex patterns are
- /// dropped after the method is polled.
- async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-}
-
-struct Bar<'a>(PhantomData<&'a ()>);
-
-impl<'a> Bar<'a> {
- /// Check that unused bindings are dropped after the method with self is polled.
- async fn foo_async(&'a self, x: D, _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn foo_sync(&'a self, x: D, _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- /// Check that underscore patterns are dropped after the method with self is polled.
- async fn bar_async(&'a self, x: D, _: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn bar_sync(&'a self, x: D, _: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- /// Check that underscore patterns within more complex patterns are dropped after the method
- /// with self is polled.
- async fn baz_async(&'a self, (x, _): (D, D)) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn baz_sync(&'a self, (x, _): (D, D)) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- /// Check that underscore and unused bindings within and outwith more complex patterns are
- /// dropped after the method with self is polled.
- async fn foobar_async(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-
- fn foobar_sync(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
- x.1.borrow_mut().push(DropOrder::Function);
- }
-}
-
-fn assert_drop_order_after_poll<Fut: Future<Output = ()>>(
- f: impl FnOnce(DropOrderListPtr) -> Fut,
- g: impl FnOnce(DropOrderListPtr),
-) {
- let empty = Arc::new(EmptyWaker);
- let waker = ArcWake::into_waker(empty);
- let mut cx = Context::from_waker(&waker);
-
- let actual_order = Rc::new(RefCell::new(Vec::new()));
- let mut fut = Box::pin(f(actual_order.clone()));
- let _ = fut.as_mut().poll(&mut cx);
-
- let expected_order = Rc::new(RefCell::new(Vec::new()));
- g(expected_order.clone());
-
- assert_eq!(*actual_order.borrow(), *expected_order.borrow());
-}
-
-fn main() {
- // Free functions (see doc comment on function for what it tests).
- assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())),
- |l| foo_sync(D("x", l.clone()), D("_y", l.clone())));
- assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())),
- |l| bar_sync(D("x", l.clone()), D("_", l.clone())));
- assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))),
- |l| baz_sync((D("x", l.clone()), D("_", l.clone()))));
- assert_drop_order_after_poll(
- |l| {
- foobar_async(
- D("x", l.clone()),
- (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
- D("_", l.clone()),
- D("_y", l.clone()),
- )
- },
- |l| {
- foobar_sync(
- D("x", l.clone()),
- (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
- D("_", l.clone()),
- D("_y", l.clone()),
- )
- },
- );
-
- // Methods w/out self (see doc comment on function for what it tests).
- assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())),
- |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone())));
- assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())),
- |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone())));
- assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))),
- |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone()))));
- assert_drop_order_after_poll(
- |l| {
- Foo::foobar_async(
- D("x", l.clone()),
- (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
- D("_", l.clone()),
- D("_y", l.clone()),
- )
- },
- |l| {
- Foo::foobar_sync(
- D("x", l.clone()),
- (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
- D("_", l.clone()),
- D("_y", l.clone()),
- )
- },
- );
-
- // Methods (see doc comment on function for what it tests).
- let b = Bar(Default::default());
- assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())),
- |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone())));
- assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())),
- |l| b.bar_sync(D("x", l.clone()), D("_", l.clone())));
- assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))),
- |l| b.baz_sync((D("x", l.clone()), D("_", l.clone()))));
- assert_drop_order_after_poll(
- |l| {
- b.foobar_async(
- D("x", l.clone()),
- (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
- D("_", l.clone()),
- D("_y", l.clone()),
- )
- },
- |l| {
- b.foobar_sync(
- D("x", l.clone()),
- (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
- D("_", l.clone()),
- D("_y", l.clone()),
- )
- },
- );
-}
+++ /dev/null
-// edition:2018
-
-#![allow(unused_variables)]
-#![feature(async_await)]
-
-async fn foobar_async(x: u32, (a, _, _c): (u32, u32, u32), _: u32, _y: u32) {
- assert_eq!(__arg1, (1, 2, 3)); //~ ERROR cannot find value `__arg1` in this scope [E0425]
- assert_eq!(__arg2, 4); //~ ERROR cannot find value `__arg2` in this scope [E0425]
-}
-
-async fn baz_async(ref mut x: u32, ref y: u32) {
- assert_eq!(__arg0, 1); //~ ERROR cannot find value `__arg0` in this scope [E0425]
- assert_eq!(__arg1, 2); //~ ERROR cannot find value `__arg1` in this scope [E0425]
-}
-
-fn main() {}
+++ /dev/null
-error[E0425]: cannot find value `__arg1` in this scope
- --> $DIR/drop-order-locals-are-hidden.rs:7:16
- |
-LL | assert_eq!(__arg1, (1, 2, 3));
- | ^^^^^^ not found in this scope
-
-error[E0425]: cannot find value `__arg2` in this scope
- --> $DIR/drop-order-locals-are-hidden.rs:8:16
- |
-LL | assert_eq!(__arg2, 4);
- | ^^^^^^ not found in this scope
-
-error[E0425]: cannot find value `__arg0` in this scope
- --> $DIR/drop-order-locals-are-hidden.rs:12:16
- |
-LL | assert_eq!(__arg0, 1);
- | ^^^^^^ not found in this scope
-
-error[E0425]: cannot find value `__arg1` in this scope
- --> $DIR/drop-order-locals-are-hidden.rs:13:16
- |
-LL | assert_eq!(__arg1, 2);
- | ^^^^^^ not found in this scope
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0425`.
--- /dev/null
+// edition:2018
+
+use std::sync::Arc;
+use std::task::{
+ Waker, RawWaker, RawWakerVTable,
+};
+
+macro_rules! waker_vtable {
+ ($ty:ident) => {
+ &RawWakerVTable::new(
+ clone_arc_raw::<$ty>,
+ wake_arc_raw::<$ty>,
+ wake_by_ref_arc_raw::<$ty>,
+ drop_arc_raw::<$ty>,
+ )
+ };
+}
+
+pub trait ArcWake {
+ fn wake(self: Arc<Self>);
+
+ fn wake_by_ref(arc_self: &Arc<Self>) {
+ arc_self.clone().wake()
+ }
+
+ fn into_waker(wake: Arc<Self>) -> Waker where Self: Sized
+ {
+ let ptr = Arc::into_raw(wake) as *const ();
+
+ unsafe {
+ Waker::from_raw(RawWaker::new(ptr, waker_vtable!(Self)))
+ }
+ }
+}
+
+unsafe fn increase_refcount<T: ArcWake>(data: *const ()) {
+ // Retain Arc by creating a copy
+ let arc: Arc<T> = Arc::from_raw(data as *const T);
+ let arc_clone = arc.clone();
+ // Forget the Arcs again, so that the refcount isn't decrased
+ let _ = Arc::into_raw(arc);
+ let _ = Arc::into_raw(arc_clone);
+}
+
+unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker {
+ increase_refcount::<T>(data);
+ RawWaker::new(data, waker_vtable!(T))
+}
+
+unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) {
+ // Drop Arc
+ let _: Arc<T> = Arc::from_raw(data as *const T);
+}
+
+unsafe fn wake_arc_raw<T: ArcWake>(data: *const ()) {
+ let arc: Arc<T> = Arc::from_raw(data as *const T);
+ ArcWake::wake(arc);
+}
+
+unsafe fn wake_by_ref_arc_raw<T: ArcWake>(data: *const ()) {
+ let arc: Arc<T> = Arc::from_raw(data as *const T);
+ ArcWake::wake_by_ref(&arc);
+ let _ = Arc::into_raw(arc);
+}
--- /dev/null
+// aux-build:arc_wake.rs
+// edition:2018
+// run-pass
+
+#![allow(unused_variables)]
+#![feature(async_await, await_macro)]
+
+// Test that the drop order for parameters in a fn and async fn matches up. Also test that
+// parameters (used or unused) are not dropped until the async fn completes execution.
+// See also #54716.
+
+extern crate arc_wake;
+
+use arc_wake::ArcWake;
+use std::cell::RefCell;
+use std::future::Future;
+use std::marker::PhantomData;
+use std::sync::Arc;
+use std::rc::Rc;
+use std::task::Context;
+
+struct EmptyWaker;
+
+impl ArcWake for EmptyWaker {
+ fn wake(self: Arc<Self>) {}
+}
+
+#[derive(Debug, Eq, PartialEq)]
+enum DropOrder {
+ Function,
+ Val(&'static str),
+}
+
+type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
+
+struct D(&'static str, DropOrderListPtr);
+
+impl Drop for D {
+ fn drop(&mut self) {
+ self.1.borrow_mut().push(DropOrder::Val(self.0));
+ }
+}
+
+/// Check that unused bindings are dropped after the function is polled.
+async fn foo_async(ref mut x: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn foo_sync(ref mut x: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore patterns are dropped after the function is polled.
+async fn bar_async(ref mut x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn bar_sync(ref mut x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore patterns within more complex patterns are dropped after the function
+/// is polled.
+async fn baz_async((ref mut x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn baz_sync((ref mut x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore and unused bindings within and outwith more complex patterns are dropped
+/// after the function is polled.
+async fn foobar_async(ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn foobar_sync(ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+struct Foo;
+
+impl Foo {
+ /// Check that unused bindings are dropped after the method is polled.
+ async fn foo_async(ref mut x: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foo_sync(ref mut x: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns are dropped after the method is polled.
+ async fn bar_async(ref mut x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn bar_sync(ref mut x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns within more complex patterns are dropped after the method
+ /// is polled.
+ async fn baz_async((ref mut x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn baz_sync((ref mut x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore and unused bindings within and outwith more complex patterns are
+ /// dropped after the method is polled.
+ async fn foobar_async(
+ ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
+ ) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foobar_sync(
+ ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
+ ) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+}
+
+struct Bar<'a>(PhantomData<&'a ()>);
+
+impl<'a> Bar<'a> {
+ /// Check that unused bindings are dropped after the method with self is polled.
+ async fn foo_async(&'a self, ref mut x: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foo_sync(&'a self, ref mut x: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns are dropped after the method with self is polled.
+ async fn bar_async(&'a self, ref mut x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn bar_sync(&'a self, ref mut x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns within more complex patterns are dropped after the method
+ /// with self is polled.
+ async fn baz_async(&'a self, (ref mut x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn baz_sync(&'a self, (ref mut x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore and unused bindings within and outwith more complex patterns are
+ /// dropped after the method with self is polled.
+ async fn foobar_async(
+ &'a self, ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
+ ) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foobar_sync(
+ &'a self, ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
+ ) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+}
+
+fn assert_drop_order_after_poll<Fut: Future<Output = ()>>(
+ f: impl FnOnce(DropOrderListPtr) -> Fut,
+ g: impl FnOnce(DropOrderListPtr),
+) {
+ let empty = Arc::new(EmptyWaker);
+ let waker = ArcWake::into_waker(empty);
+ let mut cx = Context::from_waker(&waker);
+
+ let actual_order = Rc::new(RefCell::new(Vec::new()));
+ let mut fut = Box::pin(f(actual_order.clone()));
+ let _ = fut.as_mut().poll(&mut cx);
+
+ let expected_order = Rc::new(RefCell::new(Vec::new()));
+ g(expected_order.clone());
+
+ assert_eq!(*actual_order.borrow(), *expected_order.borrow());
+}
+
+fn main() {
+ // Free functions (see doc comment on function for what it tests).
+ assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| foo_sync(D("x", l.clone()), D("_y", l.clone())));
+ assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())),
+ |l| bar_sync(D("x", l.clone()), D("_", l.clone())));
+ assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))),
+ |l| baz_sync((D("x", l.clone()), D("_", l.clone()))));
+ assert_drop_order_after_poll(
+ |l| {
+ foobar_async(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ |l| {
+ foobar_sync(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ );
+
+ // Methods w/out self (see doc comment on function for what it tests).
+ assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone())));
+ assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())),
+ |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone())));
+ assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))),
+ |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone()))));
+ assert_drop_order_after_poll(
+ |l| {
+ Foo::foobar_async(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ |l| {
+ Foo::foobar_sync(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ );
+
+ // Methods (see doc comment on function for what it tests).
+ let b = Bar(Default::default());
+ assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone())));
+ assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())),
+ |l| b.bar_sync(D("x", l.clone()), D("_", l.clone())));
+ assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))),
+ |l| b.baz_sync((D("x", l.clone()), D("_", l.clone()))));
+ assert_drop_order_after_poll(
+ |l| {
+ b.foobar_async(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ |l| {
+ b.foobar_sync(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ );
+}
--- /dev/null
+// aux-build:arc_wake.rs
+// edition:2018
+// run-pass
+
+#![allow(unused_variables)]
+#![feature(async_await, await_macro)]
+
+// Test that the drop order for parameters in a fn and async fn matches up. Also test that
+// parameters (used or unused) are not dropped until the async fn completes execution.
+// See also #54716.
+
+extern crate arc_wake;
+
+use arc_wake::ArcWake;
+use std::cell::RefCell;
+use std::future::Future;
+use std::marker::PhantomData;
+use std::sync::Arc;
+use std::rc::Rc;
+use std::task::Context;
+
+struct EmptyWaker;
+
+impl ArcWake for EmptyWaker {
+ fn wake(self: Arc<Self>) {}
+}
+
+#[derive(Debug, Eq, PartialEq)]
+enum DropOrder {
+ Function,
+ Val(&'static str),
+}
+
+type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
+
+struct D(&'static str, DropOrderListPtr);
+
+impl Drop for D {
+ fn drop(&mut self) {
+ self.1.borrow_mut().push(DropOrder::Val(self.0));
+ }
+}
+
+/// Check that unused bindings are dropped after the function is polled.
+async fn foo_async(x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn foo_sync(x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore patterns are dropped after the function is polled.
+async fn bar_async(x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn bar_sync(x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore patterns within more complex patterns are dropped after the function
+/// is polled.
+async fn baz_async((x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn baz_sync((x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore and unused bindings within and outwith more complex patterns are dropped
+/// after the function is polled.
+async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+struct Foo;
+
+impl Foo {
+ /// Check that unused bindings are dropped after the method is polled.
+ async fn foo_async(x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foo_sync(x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns are dropped after the method is polled.
+ async fn bar_async(x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn bar_sync(x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns within more complex patterns are dropped after the method
+ /// is polled.
+ async fn baz_async((x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn baz_sync((x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore and unused bindings within and outwith more complex patterns are
+ /// dropped after the method is polled.
+ async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+}
+
+struct Bar<'a>(PhantomData<&'a ()>);
+
+impl<'a> Bar<'a> {
+ /// Check that unused bindings are dropped after the method with self is polled.
+ async fn foo_async(&'a self, x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foo_sync(&'a self, x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns are dropped after the method with self is polled.
+ async fn bar_async(&'a self, x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn bar_sync(&'a self, x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns within more complex patterns are dropped after the method
+ /// with self is polled.
+ async fn baz_async(&'a self, (x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn baz_sync(&'a self, (x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore and unused bindings within and outwith more complex patterns are
+ /// dropped after the method with self is polled.
+ async fn foobar_async(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foobar_sync(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+}
+
+fn assert_drop_order_after_poll<Fut: Future<Output = ()>>(
+ f: impl FnOnce(DropOrderListPtr) -> Fut,
+ g: impl FnOnce(DropOrderListPtr),
+) {
+ let empty = Arc::new(EmptyWaker);
+ let waker = ArcWake::into_waker(empty);
+ let mut cx = Context::from_waker(&waker);
+
+ let actual_order = Rc::new(RefCell::new(Vec::new()));
+ let mut fut = Box::pin(f(actual_order.clone()));
+ let _ = fut.as_mut().poll(&mut cx);
+
+ let expected_order = Rc::new(RefCell::new(Vec::new()));
+ g(expected_order.clone());
+
+ assert_eq!(*actual_order.borrow(), *expected_order.borrow());
+}
+
+fn main() {
+ // Free functions (see doc comment on function for what it tests).
+ assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| foo_sync(D("x", l.clone()), D("_y", l.clone())));
+ assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())),
+ |l| bar_sync(D("x", l.clone()), D("_", l.clone())));
+ assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))),
+ |l| baz_sync((D("x", l.clone()), D("_", l.clone()))));
+ assert_drop_order_after_poll(
+ |l| {
+ foobar_async(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ |l| {
+ foobar_sync(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ );
+
+ // Methods w/out self (see doc comment on function for what it tests).
+ assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone())));
+ assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())),
+ |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone())));
+ assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))),
+ |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone()))));
+ assert_drop_order_after_poll(
+ |l| {
+ Foo::foobar_async(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ |l| {
+ Foo::foobar_sync(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ );
+
+ // Methods (see doc comment on function for what it tests).
+ let b = Bar(Default::default());
+ assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone())));
+ assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())),
+ |l| b.bar_sync(D("x", l.clone()), D("_", l.clone())));
+ assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))),
+ |l| b.baz_sync((D("x", l.clone()), D("_", l.clone()))));
+ assert_drop_order_after_poll(
+ |l| {
+ b.foobar_async(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ |l| {
+ b.foobar_sync(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ );
+}
--- /dev/null
+// edition:2018
+
+#![allow(unused_variables)]
+#![feature(async_await)]
+
+async fn foobar_async(x: u32, (a, _, _c): (u32, u32, u32), _: u32, _y: u32) {
+ assert_eq!(__arg1, (1, 2, 3)); //~ ERROR cannot find value `__arg1` in this scope [E0425]
+ assert_eq!(__arg2, 4); //~ ERROR cannot find value `__arg2` in this scope [E0425]
+}
+
+async fn baz_async(ref mut x: u32, ref y: u32) {
+ assert_eq!(__arg0, 1); //~ ERROR cannot find value `__arg0` in this scope [E0425]
+ assert_eq!(__arg1, 2); //~ ERROR cannot find value `__arg1` in this scope [E0425]
+}
+
+fn main() {}
--- /dev/null
+error[E0425]: cannot find value `__arg1` in this scope
+ --> $DIR/drop-order-locals-are-hidden.rs:7:16
+ |
+LL | assert_eq!(__arg1, (1, 2, 3));
+ | ^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `__arg2` in this scope
+ --> $DIR/drop-order-locals-are-hidden.rs:8:16
+ |
+LL | assert_eq!(__arg2, 4);
+ | ^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `__arg0` in this scope
+ --> $DIR/drop-order-locals-are-hidden.rs:12:16
+ |
+LL | assert_eq!(__arg0, 1);
+ | ^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `__arg1` in this scope
+ --> $DIR/drop-order-locals-are-hidden.rs:13:16
+ |
+LL | assert_eq!(__arg1, 2);
+ | ^^^^^^ not found in this scope
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
--- /dev/null
+// edition:2015
+
+#![feature(async_await)]
+
+async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition
+
+fn baz() { async fn foo() {} } //~ ERROR `async fn` is not permitted in the 2015 edition
+
+async fn async_baz() { //~ ERROR `async fn` is not permitted in the 2015 edition
+ async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition
+}
+
+struct Foo {}
+
+impl Foo {
+ async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition
+}
+
+trait Bar {
+ async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition
+ //~^ ERROR trait fns cannot be declared `async`
+}
+
+fn main() {
+ macro_rules! accept_item { ($x:item) => {} }
+
+ accept_item! {
+ async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition
+ }
+
+ let inside_closure = || {
+ async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition
+ };
+}
--- /dev/null
+error[E0670]: `async fn` is not permitted in the 2015 edition
+ --> $DIR/edition-deny-async-fns-2015.rs:5:1
+ |
+LL | async fn foo() {}
+ | ^^^^^
+
+error[E0670]: `async fn` is not permitted in the 2015 edition
+ --> $DIR/edition-deny-async-fns-2015.rs:7:12
+ |
+LL | fn baz() { async fn foo() {} }
+ | ^^^^^
+
+error[E0670]: `async fn` is not permitted in the 2015 edition
+ --> $DIR/edition-deny-async-fns-2015.rs:10:5
+ |
+LL | async fn bar() {}
+ | ^^^^^
+
+error[E0670]: `async fn` is not permitted in the 2015 edition
+ --> $DIR/edition-deny-async-fns-2015.rs:9:1
+ |
+LL | async fn async_baz() {
+ | ^^^^^
+
+error[E0670]: `async fn` is not permitted in the 2015 edition
+ --> $DIR/edition-deny-async-fns-2015.rs:32:9
+ |
+LL | async fn bar() {}
+ | ^^^^^
+
+error[E0670]: `async fn` is not permitted in the 2015 edition
+ --> $DIR/edition-deny-async-fns-2015.rs:28:9
+ |
+LL | async fn foo() {}
+ | ^^^^^
+
+error[E0670]: `async fn` is not permitted in the 2015 edition
+ --> $DIR/edition-deny-async-fns-2015.rs:16:5
+ |
+LL | async fn foo() {}
+ | ^^^^^
+
+error[E0706]: trait fns cannot be declared `async`
+ --> $DIR/edition-deny-async-fns-2015.rs:20:5
+ |
+LL | async fn foo() {}
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0670]: `async fn` is not permitted in the 2015 edition
+ --> $DIR/edition-deny-async-fns-2015.rs:20:5
+ |
+LL | async fn foo() {}
+ | ^^^^^
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0670`.
+++ /dev/null
-// compile-pass
-// edition:2018
-
-#![feature(async_await)]
-
-// This is a regression test to ensure that simple bindings (where replacement arguments aren't
-// created during async fn lowering) that have their DefId used during HIR lowering (such as impl
-// trait) are visited during def collection and thus have a DefId.
-
-async fn foo(ws: impl Iterator<Item = ()>) {}
-
-fn main() {}
+++ /dev/null
-// aux-build:issue-60674.rs
-// compile-pass
-// edition:2018
-#![feature(async_await)]
-
-// This is a regression test that ensures that `mut` patterns are not lost when provided as input
-// to a proc macro.
-
-extern crate issue_60674;
-
-#[issue_60674::attr]
-async fn f(mut x: u8) {}
-
-#[issue_60674::attr]
-async fn g((mut x, y, mut z): (u8, u8, u8)) {}
-
-#[issue_60674::attr]
-async fn g(mut x: u8, (a, mut b, c): (u8, u8, u8), y: u8) {}
-
-fn main() {}
+++ /dev/null
-async fn f(mut x: u8) { }
-async fn g((mut x, y, mut z): (u8, u8, u8)) { }
-async fn g(mut x: u8, (a, mut b, c): (u8, u8, u8), y: u8) { }
--- /dev/null
+// force-host
+// no-prefer-dynamic
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn attr(_args: TokenStream, input: TokenStream) -> TokenStream {
+ println!("{}", input);
+ TokenStream::new()
+}
--- /dev/null
+// edition:2018
+//
+// Tests that the .await syntax can't be used to make a generator
+
+#![feature(async_await)]
+
+async fn foo() {}
+
+fn make_generator() {
+ let _gen = || foo.await; //~ ERROR `await` is only allowed inside `async` functions and blocks
+}
+
+fn main() {}
--- /dev/null
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+ --> $DIR/issue-51719.rs:10:19
+ |
+LL | let _gen = || foo.await;
+ | -- ^^^^^^^^^ only allowed inside `async` functions and blocks
+ | |
+ | this is not `async`
+
+error: aborting due to previous error
+
--- /dev/null
+// edition:2018
+
+#![feature(async_await)]
+
+async fn inc(limit: i64) -> i64 {
+ limit + 1
+}
+
+fn main() {
+ let result = inc(10000);
+ let finished = result.await;
+ //~^ ERROR `await` is only allowed inside `async` functions and blocks
+}
--- /dev/null
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+ --> $DIR/issue-51751.rs:11:20
+ |
+LL | fn main() {
+ | ---- this is not `async`
+LL | let result = inc(10000);
+LL | let finished = result.await;
+ | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error: aborting due to previous error
+
--- /dev/null
+// compile-pass
+// edition:2018
+
+#![feature(arbitrary_self_types, async_await, await_macro)]
+
+use std::task::{self, Poll};
+use std::future::Future;
+use std::marker::Unpin;
+use std::pin::Pin;
+
+// This is a regression test for a ICE/unbounded recursion issue relating to async-await.
+
+#[derive(Debug)]
+#[must_use = "futures do nothing unless polled"]
+pub struct Lazy<F> {
+ f: Option<F>
+}
+
+impl<F> Unpin for Lazy<F> {}
+
+pub fn lazy<F, R>(f: F) -> Lazy<F>
+ where F: FnOnce(&mut task::Context) -> R,
+{
+ Lazy { f: Some(f) }
+}
+
+impl<R, F> Future for Lazy<F>
+ where F: FnOnce(&mut task::Context) -> R,
+{
+ type Output = R;
+
+ fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context) -> Poll<R> {
+ Poll::Ready((self.f.take().unwrap())(cx))
+ }
+}
+
+async fn __receive<WantFn, Fut>(want: WantFn) -> ()
+ where Fut: Future<Output = ()>, WantFn: Fn(&Box<Send + 'static>) -> Fut,
+{
+ await!(lazy(|_| ()));
+}
+
+pub fn basic_spawn_receive() {
+ async { await!(__receive(|_| async { () })) };
+}
+
+fn main() {}
--- /dev/null
+// run-pass
+
+// edition:2018
+// pp-exact
+
+#![feature(async_await)]
+#![allow(unused_parens)]
+
+fn main() { let _a = (async { }); }
--- /dev/null
+// compile-pass
+// edition:2018
+
+#![feature(async_await, await_macro)]
+
+use std::sync::Arc;
+
+trait SomeTrait: Send + Sync + 'static {
+ fn do_something(&self);
+}
+
+async fn my_task(obj: Arc<SomeTrait>) {
+ unimplemented!()
+}
+
+fn main() {}
--- /dev/null
+// compile-pass
+// edition:2018
+
+#![feature(async_await, await_macro)]
+
+use std::future::Future;
+
+#[allow(unused)]
+async fn foo<F: Future<Output = i32>>(x: &i32, future: F) -> i32 {
+ let y = await!(future);
+ *x + y
+}
+
+fn main() {}
--- /dev/null
+// edition:2018
+// run-pass
+
+#![feature(async_await)]
+
+trait Foo { }
+
+impl Foo for () { }
+
+impl<'a, T> Foo for &'a mut T where T: Foo { }
+
+async fn foo_async<T>(_v: T) -> u8 where T: Foo {
+ 0
+}
+
+async fn bad<T>(v: T) -> u8 where T: Foo {
+ foo_async(v).await
+}
+
+async fn async_main() {
+ let mut v = ();
+
+ let _ = bad(&mut v).await;
+ let _ = foo_async(&mut v).await;
+ let _ = bad(v).await;
+}
+
+fn main() {
+ let _ = async_main();
+}
--- /dev/null
+// compile-pass
+// edition:2018
+
+#![feature(async_await, await_macro)]
+
+struct Xyz {
+ a: u64,
+}
+
+trait Foo {}
+
+impl Xyz {
+ async fn do_sth<'a>(
+ &'a self, foo: &'a dyn Foo
+ ) -> bool
+ {
+ true
+ }
+}
+
+fn main() {}
--- /dev/null
+// compile-pass
+// edition:2018
+
+#![feature(async_await, await_macro)]
+
+use std::future::Future;
+
+#[allow(unused)]
+async fn enter<'a, F, R>(mut callback: F)
+where
+ F: FnMut(&'a mut i32) -> R,
+ R: Future<Output = ()> + 'a,
+{
+ unimplemented!()
+}
+
+fn main() {}
--- /dev/null
+// run-pass
+
+// compile-flags: --edition=2018
+
+#![feature(async_await, await_macro)]
+
+pub enum Uninhabited { }
+
+fn uninhabited_async() -> Uninhabited {
+ unreachable!()
+}
+
+async fn noop() { }
+
+#[allow(unused)]
+async fn contains_never() {
+ let error = uninhabited_async();
+ await!(noop());
+ let error2 = error;
+}
+
+#[allow(unused_must_use)]
+fn main() {
+ contains_never();
+}
--- /dev/null
+// compile-pass
+// edition:2018
+
+#![feature(async_await)]
+
+// This is a regression test to ensure that simple bindings (where replacement arguments aren't
+// created during async fn lowering) that have their DefId used during HIR lowering (such as impl
+// trait) are visited during def collection and thus have a DefId.
+
+async fn foo(ws: impl Iterator<Item = ()>) {}
+
+fn main() {}
--- /dev/null
+// Test that existential types are allowed to contain late-bound regions.
+
+// compile-pass
+// edition:2018
+
+#![feature(async_await, existential_type)]
+
+use std::future::Future;
+
+pub existential type Func: Sized;
+
+// Late bound region should be allowed to escape the function, since it's bound
+// in the type.
+fn null_function_ptr() -> Func {
+ None::<for<'a> fn(&'a ())>
+}
+
+async fn async_nop(_: &u8) {}
+
+pub existential type ServeFut: Future<Output=()>;
+
+// Late bound regions occur in the generator witness type here.
+fn serve() -> ServeFut {
+ async move {
+ let x = 5;
+ async_nop(&x).await
+ }
+}
+
+fn main() {}
--- /dev/null
+// aux-build:issue-60674.rs
+// compile-pass
+// edition:2018
+#![feature(async_await)]
+
+// This is a regression test that ensures that `mut` patterns are not lost when provided as input
+// to a proc macro.
+
+extern crate issue_60674;
+
+#[issue_60674::attr]
+async fn f(mut x: u8) {}
+
+#[issue_60674::attr]
+async fn g((mut x, y, mut z): (u8, u8, u8)) {}
+
+#[issue_60674::attr]
+async fn g(mut x: u8, (a, mut b, c): (u8, u8, u8), y: u8) {}
+
+fn main() {}
--- /dev/null
+async fn f(mut x: u8) { }
+async fn g((mut x, y, mut z): (u8, u8, u8)) { }
+async fn g(mut x: u8, (a, mut b, c): (u8, u8, u8), y: u8) { }
--- /dev/null
+// edition:2018
+
+#![feature(async_await, await_macro)]
+
+fn main() {
+ let _ = async |x: u8| {};
+ //~^ ERROR `async` non-`move` closures with arguments are not currently supported
+}
--- /dev/null
+error[E0708]: `async` non-`move` closures with arguments are not currently supported
+ --> $DIR/no-args-non-move-async-closure.rs:6:13
+ |
+LL | let _ = async |x: u8| {};
+ | ^^^^^^^^^^^^^
+ |
+ = help: consider using `let` statements to manually capture variables by reference before entering an `async move` closure
+
+error: aborting due to previous error
+
--- /dev/null
+// edition:2018
+// Test that impl trait does not allow creating recursive types that are
+// otherwise forbidden when using `async` and `await`.
+
+#![feature(await_macro, async_await, generators)]
+
+async fn recursive_async_function() -> () { //~ ERROR
+ await!(recursive_async_function());
+}
+
+fn main() {}
--- /dev/null
+error[E0720]: opaque type expands to a recursive type
+ --> $DIR/recursive-async-impl-trait-type.rs:7:40
+ |
+LL | async fn recursive_async_function() -> () {
+ | ^^ expands to self-referential type
+ |
+ = note: expanded type is `std::future::GenFuture<[static generator@$DIR/recursive-async-impl-trait-type.rs:7:43: 9:2 {impl std::future::Future, ()}]>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0720`.
--- /dev/null
+// Provoke an unresolved type error (T).
+// Error message should pinpoint the type parameter T as needing to be bound
+// (rather than give a general error message)
+// edition:2018
+#![feature(async_await)]
+async fn bar<T>() -> () {}
+
+async fn foo() {
+ bar().await;
+ //~^ ERROR type inside generator must be known in this context
+ //~| NOTE cannot infer type for `T`
+ //~| NOTE the type is part of the generator because of this `yield`
+ //~| NOTE in this expansion of desugaring of `await`
+}
+fn main() {}
--- /dev/null
+error[E0698]: type inside generator must be known in this context
+ --> $DIR/unresolved_type_param.rs:9:5
+ |
+LL | bar().await;
+ | ^^^ cannot infer type for `T`
+ |
+note: the type is part of the generator because of this `yield`
+ --> $DIR/unresolved_type_param.rs:9:5
+ |
+LL | bar().await;
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0698`.
+++ /dev/null
-// edition:2018
-
-#![feature(arbitrary_self_types, async_await, await_macro, pin)]
-
-use std::ops::Add;
-
-async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
-//~^ ERROR ambiguous lifetime bound in `async fn`
-
-async fn multiple_hrtb_and_single_named_lifetime_ok<'c>(
- _: impl for<'a> Add<&'a u8>,
- _: impl for<'b> Add<&'b u8>,
- _: &'c u8,
-) {}
-
-async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
-//~^ ambiguous lifetime bound in `async fn`
-
-fn main() {}
+++ /dev/null
-error: ambiguous lifetime bound in `async fn`
- --> $DIR/async-fn-multiple-lifetimes.rs:7:65
- |
-LL | async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
- | ^ neither `'a` nor `'b` outlives the other
- |
- = note: multiple unrelated lifetimes are not allowed in `async fn`.
- = note: if you're using argument-position elided lifetimes, consider switching to a single named lifetime.
-
-error: ambiguous lifetime bound in `async fn`
- --> $DIR/async-fn-multiple-lifetimes.rs:16:52
- |
-LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
- | ^ the elided lifetimes here do not outlive one another
- |
- = note: multiple unrelated lifetimes are not allowed in `async fn`.
- = note: if you're using argument-position elided lifetimes, consider switching to a single named lifetime.
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-// edition:2018
-
-#![feature(async_await, await_macro)]
-#![allow(dead_code)]
-
-struct HasLifetime<'a>(&'a bool);
-
-async fn error(lt: HasLifetime) { //~ ERROR implicit elided lifetime not allowed here
- if *lt.0 {}
-}
-
-fn no_error(lt: HasLifetime) {
- if *lt.0 {}
-}
-
-fn main() {}
+++ /dev/null
-error[E0726]: implicit elided lifetime not allowed here
- --> $DIR/async-fn-path-elision.rs:8:20
- |
-LL | async fn error(lt: HasLifetime) {
- | ^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
-
-error: aborting due to previous error
-
+++ /dev/null
-// compile-pass
-// edition:2018
-
-#![feature(async_await, await_macro)]
-
-macro_rules! match_expr {
- ($x:expr) => {}
-}
-
-fn main() {
- match_expr!(async {});
- match_expr!(async || {});
-}
+++ /dev/null
-// compile-pass
-// edition:2018
-
-#![feature(async_await, await_macro)]
-
-trait MyClosure {
- type Args;
-}
-
-impl<R> MyClosure for dyn FnMut() -> R
-where R: 'static {
- type Args = ();
-}
-
-struct MyStream<C: ?Sized + MyClosure> {
- x: C::Args,
-}
-
-async fn get_future<C: ?Sized + MyClosure>(_stream: MyStream<C>) {}
-
-async fn f() {
- let messages: MyStream<FnMut()> = unimplemented!();
- await!(get_future(messages));
-}
-
-fn main() {}
+++ /dev/null
-pub mod foo {
- #[macro_export]
- macro_rules! makro {
- ($foo:ident) => {
- fn $foo() { }
- }
- }
-
- pub fn baz() {}
-
- pub fn foobar() {}
-
- pub mod barbaz {
- pub fn barfoo() {}
- }
-}
-
-pub fn foobaz() {}
+++ /dev/null
-#![feature(async_await, await_macro)]
-#![allow(non_camel_case_types)]
-#![deny(keyword_idents)]
-
-mod outer_mod {
- pub mod await { //~ ERROR `await` is a keyword in the 2018 edition
- //~^ WARN this was previously accepted by the compiler
- pub struct await; //~ ERROR `await` is a keyword in the 2018 edition
- //~^ WARN this was previously accepted by the compiler
- }
-}
-use outer_mod::await::await; //~ ERROR `await` is a keyword in the 2018 edition
-//~^ ERROR `await` is a keyword in the 2018 edition
-//~^^ WARN this was previously accepted by the compiler
-//~^^^ WARN this was previously accepted by the compiler
-
-struct Foo { await: () }
-//~^ ERROR `await` is a keyword in the 2018 edition
-//~^^ WARN this was previously accepted by the compiler
-
-impl Foo { fn await() {} }
-//~^ ERROR `await` is a keyword in the 2018 edition
-//~^^ WARN this was previously accepted by the compiler
-
-macro_rules! await {
-//~^ ERROR `await` is a keyword in the 2018 edition
-//~^^ WARN this was previously accepted by the compiler
- () => {}
-}
-
-fn main() {
- match await { await => {} } //~ ERROR `await` is a keyword in the 2018 edition
- //~^ ERROR `await` is a keyword in the 2018 edition
- //~^^ WARN this was previously accepted by the compiler
- //~^^^ WARN this was previously accepted by the compiler
-}
+++ /dev/null
-error: `await` is a keyword in the 2018 edition
- --> $DIR/2015-edition-error-in-non-macro-position.rs:6:13
- |
-LL | pub mod await {
- | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
- |
-note: lint level defined here
- --> $DIR/2015-edition-error-in-non-macro-position.rs:3:9
- |
-LL | #![deny(keyword_idents)]
- | ^^^^^^^^^^^^^^
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: `await` is a keyword in the 2018 edition
- --> $DIR/2015-edition-error-in-non-macro-position.rs:8:20
- |
-LL | pub struct await;
- | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: `await` is a keyword in the 2018 edition
- --> $DIR/2015-edition-error-in-non-macro-position.rs:12:16
- |
-LL | use outer_mod::await::await;
- | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: `await` is a keyword in the 2018 edition
- --> $DIR/2015-edition-error-in-non-macro-position.rs:12:23
- |
-LL | use outer_mod::await::await;
- | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: `await` is a keyword in the 2018 edition
- --> $DIR/2015-edition-error-in-non-macro-position.rs:17:14
- |
-LL | struct Foo { await: () }
- | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: `await` is a keyword in the 2018 edition
- --> $DIR/2015-edition-error-in-non-macro-position.rs:21:15
- |
-LL | impl Foo { fn await() {} }
- | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: `await` is a keyword in the 2018 edition
- --> $DIR/2015-edition-error-in-non-macro-position.rs:25:14
- |
-LL | macro_rules! await {
- | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: `await` is a keyword in the 2018 edition
- --> $DIR/2015-edition-error-in-non-macro-position.rs:32:11
- |
-LL | match await { await => {} }
- | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: `await` is a keyword in the 2018 edition
- --> $DIR/2015-edition-error-in-non-macro-position.rs:32:19
- |
-LL | match await { await => {} }
- | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: aborting due to 9 previous errors
-
+++ /dev/null
-// run-rustfix
-
-#![allow(non_camel_case_types)]
-#![deny(keyword_idents)]
-
-mod outer_mod {
- pub mod r#await {
-//~^ ERROR `await` is a keyword
-//~| WARN was previously accepted
- pub struct r#await;
-//~^ ERROR `await` is a keyword
-//~| WARN was previously accepted
- }
-}
-use outer_mod::r#await::r#await;
-//~^ ERROR `await` is a keyword
-//~| ERROR `await` is a keyword
-//~| WARN was previously accepted
-//~| WARN was previously accepted
-
-fn main() {
- match r#await { r#await => {} }
-//~^ ERROR `await` is a keyword
-//~| ERROR `await` is a keyword
-//~| WARN was previously accepted
-//~| WARN was previously accepted
-}
+++ /dev/null
-// run-rustfix
-
-#![allow(non_camel_case_types)]
-#![deny(keyword_idents)]
-
-mod outer_mod {
- pub mod await {
-//~^ ERROR `await` is a keyword
-//~| WARN was previously accepted
- pub struct await;
-//~^ ERROR `await` is a keyword
-//~| WARN was previously accepted
- }
-}
-use outer_mod::await::await;
-//~^ ERROR `await` is a keyword
-//~| ERROR `await` is a keyword
-//~| WARN was previously accepted
-//~| WARN was previously accepted
-
-fn main() {
- match await { await => {} }
-//~^ ERROR `await` is a keyword
-//~| ERROR `await` is a keyword
-//~| WARN was previously accepted
-//~| WARN was previously accepted
-}
+++ /dev/null
-error: `await` is a keyword in the 2018 edition
- --> $DIR/2015-edition-warning.rs:7:13
- |
-LL | pub mod await {
- | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
- |
-note: lint level defined here
- --> $DIR/2015-edition-warning.rs:4:9
- |
-LL | #![deny(keyword_idents)]
- | ^^^^^^^^^^^^^^
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: `await` is a keyword in the 2018 edition
- --> $DIR/2015-edition-warning.rs:10:20
- |
-LL | pub struct await;
- | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: `await` is a keyword in the 2018 edition
- --> $DIR/2015-edition-warning.rs:15:16
- |
-LL | use outer_mod::await::await;
- | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: `await` is a keyword in the 2018 edition
- --> $DIR/2015-edition-warning.rs:15:23
- |
-LL | use outer_mod::await::await;
- | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: `await` is a keyword in the 2018 edition
- --> $DIR/2015-edition-warning.rs:22:11
- |
-LL | match await { await => {} }
- | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: `await` is a keyword in the 2018 edition
- --> $DIR/2015-edition-warning.rs:22:19
- |
-LL | match await { await => {} }
- | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: aborting due to 6 previous errors
-
+++ /dev/null
-// edition:2018
-
-#![allow(non_camel_case_types)]
-#![feature(async_await, await_macro)]
-
-mod outer_mod {
- pub mod await { //~ ERROR expected identifier, found reserved keyword `await`
- pub struct await; //~ ERROR expected identifier, found reserved keyword `await`
- }
-}
-use self::outer_mod::await::await; //~ ERROR expected identifier, found reserved keyword `await`
-//~^ ERROR expected identifier, found reserved keyword `await`
-
-struct Foo { await: () }
-//~^ ERROR expected identifier, found reserved keyword `await`
-
-impl Foo { fn await() {} }
-//~^ ERROR expected identifier, found reserved keyword `await`
-
-macro_rules! await {
-//~^ ERROR expected identifier, found reserved keyword `await`
- () => {}
-}
-
-fn main() {}
+++ /dev/null
-error: expected identifier, found reserved keyword `await`
- --> $DIR/2018-edition-error-in-non-macro-position.rs:7:13
- |
-LL | pub mod await {
- | ^^^^^ expected identifier, found reserved keyword
-help: you can escape reserved keywords to use them as identifiers
- |
-LL | pub mod r#await {
- | ^^^^^^^
-
-error: expected identifier, found reserved keyword `await`
- --> $DIR/2018-edition-error-in-non-macro-position.rs:8:20
- |
-LL | pub struct await;
- | ^^^^^ expected identifier, found reserved keyword
-help: you can escape reserved keywords to use them as identifiers
- |
-LL | pub struct r#await;
- | ^^^^^^^
-
-error: expected identifier, found reserved keyword `await`
- --> $DIR/2018-edition-error-in-non-macro-position.rs:11:22
- |
-LL | use self::outer_mod::await::await;
- | ^^^^^ expected identifier, found reserved keyword
-help: you can escape reserved keywords to use them as identifiers
- |
-LL | use self::outer_mod::r#await::await;
- | ^^^^^^^
-
-error: expected identifier, found reserved keyword `await`
- --> $DIR/2018-edition-error-in-non-macro-position.rs:11:29
- |
-LL | use self::outer_mod::await::await;
- | ^^^^^ expected identifier, found reserved keyword
-help: you can escape reserved keywords to use them as identifiers
- |
-LL | use self::outer_mod::await::r#await;
- | ^^^^^^^
-
-error: expected identifier, found reserved keyword `await`
- --> $DIR/2018-edition-error-in-non-macro-position.rs:14:14
- |
-LL | struct Foo { await: () }
- | ^^^^^ expected identifier, found reserved keyword
-help: you can escape reserved keywords to use them as identifiers
- |
-LL | struct Foo { r#await: () }
- | ^^^^^^^
-
-error: expected identifier, found reserved keyword `await`
- --> $DIR/2018-edition-error-in-non-macro-position.rs:17:15
- |
-LL | impl Foo { fn await() {} }
- | ^^^^^ expected identifier, found reserved keyword
-help: you can escape reserved keywords to use them as identifiers
- |
-LL | impl Foo { fn r#await() {} }
- | ^^^^^^^
-
-error: expected identifier, found reserved keyword `await`
- --> $DIR/2018-edition-error-in-non-macro-position.rs:20:14
- |
-LL | macro_rules! await {
- | ^^^^^ expected identifier, found reserved keyword
-help: you can escape reserved keywords to use them as identifiers
- |
-LL | macro_rules! r#await {
- | ^^^^^^^
-
-error: aborting due to 7 previous errors
-
+++ /dev/null
-// edition:2018
-#![allow(non_camel_case_types)]
-
-mod outer_mod {
- pub mod await { //~ ERROR expected identifier
- pub struct await; //~ ERROR expected identifier
- }
-}
-use self::outer_mod::await::await; //~ ERROR expected identifier
- //~^ ERROR expected identifier, found reserved keyword `await`
-
-fn main() {}
+++ /dev/null
-error: expected identifier, found reserved keyword `await`
- --> $DIR/2018-edition-error.rs:5:13
- |
-LL | pub mod await {
- | ^^^^^ expected identifier, found reserved keyword
-help: you can escape reserved keywords to use them as identifiers
- |
-LL | pub mod r#await {
- | ^^^^^^^
-
-error: expected identifier, found reserved keyword `await`
- --> $DIR/2018-edition-error.rs:6:20
- |
-LL | pub struct await;
- | ^^^^^ expected identifier, found reserved keyword
-help: you can escape reserved keywords to use them as identifiers
- |
-LL | pub struct r#await;
- | ^^^^^^^
-
-error: expected identifier, found reserved keyword `await`
- --> $DIR/2018-edition-error.rs:9:22
- |
-LL | use self::outer_mod::await::await;
- | ^^^^^ expected identifier, found reserved keyword
-help: you can escape reserved keywords to use them as identifiers
- |
-LL | use self::outer_mod::r#await::await;
- | ^^^^^^^
-
-error: expected identifier, found reserved keyword `await`
- --> $DIR/2018-edition-error.rs:9:29
- |
-LL | use self::outer_mod::await::await;
- | ^^^^^ expected identifier, found reserved keyword
-help: you can escape reserved keywords to use them as identifiers
- |
-LL | use self::outer_mod::await::r#await;
- | ^^^^^^^
-
-error: aborting due to 4 previous errors
-
+++ /dev/null
-// edition:2018
-
-#![feature(async_await)]
-
-async fn bar() -> Result<(), ()> {
- Ok(())
-}
-
-async fn foo1() -> Result<(), ()> {
- let _ = await bar(); //~ ERROR incorrect use of `await`
- Ok(())
-}
-async fn foo2() -> Result<(), ()> {
- let _ = await? bar(); //~ ERROR incorrect use of `await`
- Ok(())
-}
-async fn foo3() -> Result<(), ()> {
- let _ = await bar()?; //~ ERROR incorrect use of `await`
- //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
- Ok(())
-}
-async fn foo21() -> Result<(), ()> {
- let _ = await { bar() }; //~ ERROR incorrect use of `await`
- Ok(())
-}
-async fn foo22() -> Result<(), ()> {
- let _ = await(bar()); //~ ERROR incorrect use of `await`
- Ok(())
-}
-async fn foo23() -> Result<(), ()> {
- let _ = await { bar() }?; //~ ERROR incorrect use of `await`
- Ok(())
-}
-async fn foo4() -> Result<(), ()> {
- let _ = (await bar())?; //~ ERROR incorrect use of `await`
- Ok(())
-}
-async fn foo5() -> Result<(), ()> {
- let _ = bar().await(); //~ ERROR incorrect use of `await`
- Ok(())
-}
-async fn foo6() -> Result<(), ()> {
- let _ = bar().await()?; //~ ERROR incorrect use of `await`
- Ok(())
-}
-async fn foo7() -> Result<(), ()> {
- let _ = bar().await; // OK
- Ok(())
-}
-async fn foo8() -> Result<(), ()> {
- let _ = bar().await?; // OK
- Ok(())
-}
-fn foo9() -> Result<(), ()> {
- let _ = await bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks
- //~^ ERROR incorrect use of `await`
- Ok(())
-}
-fn foo10() -> Result<(), ()> {
- let _ = await? bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks
- //~^ ERROR incorrect use of `await`
- Ok(())
-}
-fn foo11() -> Result<(), ()> {
- let _ = await bar()?; //~ ERROR `await` is only allowed inside `async` functions and blocks
- //~^ ERROR incorrect use of `await`
- Ok(())
-}
-fn foo12() -> Result<(), ()> {
- let _ = (await bar())?; //~ ERROR `await` is only allowed inside `async` functions and blocks
- //~^ ERROR incorrect use of `await`
- Ok(())
-}
-fn foo13() -> Result<(), ()> {
- let _ = bar().await(); //~ ERROR `await` is only allowed inside `async` functions and blocks
- //~^ ERROR incorrect use of `await`
- Ok(())
-}
-fn foo14() -> Result<(), ()> {
- let _ = bar().await()?; //~ ERROR `await` is only allowed inside `async` functions and blocks
- //~^ ERROR incorrect use of `await`
- Ok(())
-}
-fn foo15() -> Result<(), ()> {
- let _ = bar().await; //~ ERROR `await` is only allowed inside `async` functions and blocks
- Ok(())
-}
-fn foo16() -> Result<(), ()> {
- let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks
- Ok(())
-}
-fn foo24() -> Result<(), ()> {
- fn foo() -> Result<(), ()> {
- let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks
- Ok(())
- }
- foo()
-}
-fn foo25() -> Result<(), ()> {
- let foo = || {
- let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks
- Ok(())
- };
- foo()
-}
-
-fn main() {
- match await { await => () }
- //~^ ERROR expected expression, found `=>`
- //~| ERROR incorrect use of `await`
-} //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `}`
+++ /dev/null
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:10:13
- |
-LL | let _ = await bar();
- | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
-
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:14:13
- |
-LL | let _ = await? bar();
- | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?`
-
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:18:13
- |
-LL | let _ = await bar()?;
- | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
-
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:23:13
- |
-LL | let _ = await { bar() };
- | ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
-
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:27:13
- |
-LL | let _ = await(bar());
- | ^^^^^^^^^^^^ help: `await` is a postfix operation: `(bar()).await`
-
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:31:13
- |
-LL | let _ = await { bar() }?;
- | ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
-
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:35:14
- |
-LL | let _ = (await bar())?;
- | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
-
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:39:24
- |
-LL | let _ = bar().await();
- | ^^ help: `await` is not a method call, remove the parentheses
-
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:43:24
- |
-LL | let _ = bar().await()?;
- | ^^ help: `await` is not a method call, remove the parentheses
-
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:55:13
- |
-LL | let _ = await bar();
- | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
-
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:60:13
- |
-LL | let _ = await? bar();
- | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?`
-
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:65:13
- |
-LL | let _ = await bar()?;
- | ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
-
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:70:14
- |
-LL | let _ = (await bar())?;
- | ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
-
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:75:24
- |
-LL | let _ = bar().await();
- | ^^ help: `await` is not a method call, remove the parentheses
-
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:80:24
- |
-LL | let _ = bar().await()?;
- | ^^ help: `await` is not a method call, remove the parentheses
-
-error: expected expression, found `=>`
- --> $DIR/incorrect-syntax-suggestions.rs:108:25
- |
-LL | match await { await => () }
- | ----- ^^ expected expression
- | |
- | while parsing this incorrect await expression
-
-error: incorrect use of `await`
- --> $DIR/incorrect-syntax-suggestions.rs:108:11
- |
-LL | match await { await => () }
- | ^^^^^^^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ await => () }.await`
-
-error: expected one of `.`, `?`, `{`, or an operator, found `}`
- --> $DIR/incorrect-syntax-suggestions.rs:111:1
- |
-LL | match await { await => () }
- | ----- - expected one of `.`, `?`, `{`, or an operator here
- | |
- | while parsing this match expression
-...
-LL | }
- | ^ unexpected token
-
-error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:55:13
- |
-LL | fn foo9() -> Result<(), ()> {
- | ---- this is not `async`
-LL | let _ = await bar();
- | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
-
-error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:60:13
- |
-LL | fn foo10() -> Result<(), ()> {
- | ----- this is not `async`
-LL | let _ = await? bar();
- | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
-
-error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:65:13
- |
-LL | fn foo11() -> Result<(), ()> {
- | ----- this is not `async`
-LL | let _ = await bar()?;
- | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
-
-error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:70:14
- |
-LL | fn foo12() -> Result<(), ()> {
- | ----- this is not `async`
-LL | let _ = (await bar())?;
- | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
-
-error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:75:13
- |
-LL | fn foo13() -> Result<(), ()> {
- | ----- this is not `async`
-LL | let _ = bar().await();
- | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
-
-error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:80:13
- |
-LL | fn foo14() -> Result<(), ()> {
- | ----- this is not `async`
-LL | let _ = bar().await()?;
- | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
-
-error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:85:13
- |
-LL | fn foo15() -> Result<(), ()> {
- | ----- this is not `async`
-LL | let _ = bar().await;
- | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
-
-error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:89:13
- |
-LL | fn foo16() -> Result<(), ()> {
- | ----- this is not `async`
-LL | let _ = bar().await?;
- | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
-
-error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:94:17
- |
-LL | fn foo() -> Result<(), ()> {
- | --- this is not `async`
-LL | let _ = bar().await?;
- | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
-
-error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:101:17
- |
-LL | let foo = || {
- | -- this is not `async`
-LL | let _ = bar().await?;
- | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
-
-error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
- --> $DIR/incorrect-syntax-suggestions.rs:18:19
- |
-LL | let _ = await bar()?;
- | ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future`
- |
- = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future`
- = note: required by `std::ops::Try::into_result`
-
-error: aborting due to 29 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-// edition:2018
-
-macro_rules! r#await {
- () => { println!("Hello, world!") }
-}
-
-fn main() {
- await!()
- //~^ ERROR expected expression, found `)`
-}
+++ /dev/null
-error: expected expression, found `)`
- --> $DIR/post_expansion_error.rs:8:12
- |
-LL | await!()
- | ----- ^ expected expression
- | |
- | while parsing this await macro call
-
-error: aborting due to previous error
-
-#![feature(core, fnbox)]
-
-use std::boxed::FnBox;
-
struct FuncContainer {
f1: fn(data: u8),
f2: extern "C" fn(data: u8),
}
struct BoxedObj {
- boxed_closure: Box<FnBox() -> u32>,
+ boxed_closure: Box<FnOnce() -> u32>,
}
struct Wrapper<F> where F: FnMut() -> u32 {
0
}
-fn check_expression() -> Obj<Box<FnBox() -> u32>> {
- Obj { closure: Box::new(|| 42_u32) as Box<FnBox() -> u32>, not_closure: 42 }
+fn check_expression() -> Obj<Box<FnOnce() -> u32>> {
+ Obj { closure: Box::new(|| 42_u32) as Box<FnOnce() -> u32>, not_closure: 42 }
}
fn main() {
let boxed_fn = BoxedObj { boxed_closure: Box::new(func) };
boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found
- let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box<FnBox() -> u32> };
+ let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box<FnOnce() -> u32> };
boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found
// test expression writing in the notes
-error[E0599]: no method named `closure` found for type `Obj<[closure@$DIR/issue-2392.rs:39:36: 39:41]>` in the current scope
- --> $DIR/issue-2392.rs:40:15
+error[E0599]: no method named `closure` found for type `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
+ --> $DIR/issue-2392.rs:36:15
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
| -------------------------------------- method `closure` not found for this
LL | (o_closure.closure)();
| ^ ^
-error[E0599]: no method named `not_closure` found for type `Obj<[closure@$DIR/issue-2392.rs:39:36: 39:41]>` in the current scope
- --> $DIR/issue-2392.rs:42:15
+error[E0599]: no method named `not_closure` found for type `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
+ --> $DIR/issue-2392.rs:38:15
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
| -------------------------------------- method `not_closure` not found for this
| field, not a method
error[E0599]: no method named `closure` found for type `Obj<fn() -> u32 {func}>` in the current scope
- --> $DIR/issue-2392.rs:46:12
+ --> $DIR/issue-2392.rs:42:12
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
| -------------------------------------- method `closure` not found for this
| ^ ^
error[E0599]: no method named `boxed_closure` found for type `BoxedObj` in the current scope
- --> $DIR/issue-2392.rs:49:14
+ --> $DIR/issue-2392.rs:45:14
|
LL | struct BoxedObj {
| --------------- method `boxed_closure` not found for this
| ^ ^
error[E0599]: no method named `boxed_closure` found for type `BoxedObj` in the current scope
- --> $DIR/issue-2392.rs:52:19
+ --> $DIR/issue-2392.rs:48:19
|
LL | struct BoxedObj {
| --------------- method `boxed_closure` not found for this
| ^ ^
error[E0599]: no method named `closure` found for type `Obj<fn() -> u32 {func}>` in the current scope
- --> $DIR/issue-2392.rs:57:12
+ --> $DIR/issue-2392.rs:53:12
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
| -------------------------------------- method `closure` not found for this
| ^ ^
error[E0599]: no method named `not_closure` found for type `Obj<fn() -> u32 {func}>` in the current scope
- --> $DIR/issue-2392.rs:59:12
+ --> $DIR/issue-2392.rs:55:12
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
| -------------------------------------- method `not_closure` not found for this
| |
| field, not a method
-error[E0599]: no method named `closure` found for type `Obj<std::boxed::Box<(dyn std::boxed::FnBox<(), Output = u32> + 'static)>>` in the current scope
- --> $DIR/issue-2392.rs:62:24
+error[E0599]: no method named `closure` found for type `Obj<std::boxed::Box<(dyn std::ops::FnOnce() -> u32 + 'static)>>` in the current scope
+ --> $DIR/issue-2392.rs:58:24
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
| -------------------------------------- method `closure` not found for this
| ^ ^
error[E0599]: no method named `f1` found for type `FuncContainer` in the current scope
- --> $DIR/issue-2392.rs:68:31
+ --> $DIR/issue-2392.rs:64:31
|
LL | struct FuncContainer {
| -------------------- method `f1` not found for this
| ^ ^
error[E0599]: no method named `f2` found for type `FuncContainer` in the current scope
- --> $DIR/issue-2392.rs:69:31
+ --> $DIR/issue-2392.rs:65:31
|
LL | struct FuncContainer {
| -------------------- method `f2` not found for this
| ^ ^
error[E0599]: no method named `f3` found for type `FuncContainer` in the current scope
- --> $DIR/issue-2392.rs:70:31
+ --> $DIR/issue-2392.rs:66:31
|
LL | struct FuncContainer {
| -------------------- method `f3` not found for this
--> $DIR/cannot-infer-const-args.rs:9:5
|
LL | foo();
- | ^^^ cannot infer type for `fn() -> usize {foo::<_>}`
+ | ^^^ cannot infer type for `fn() -> usize {foo::<_: usize>}`
error: aborting due to previous error
LL | const fn slice([a, b]: &[i32]) -> i32 {
| ^^^^^^ pattern `&[]` not covered
-error[E0723]: can only call other `const fn` within a `const fn`, but `const std::ops::Add::add` is not stable as `const fn`
+error[E0723]: can only call other `const fn` within a `const fn`, but `const <&i32 as std::ops::Add>::add` is not stable as `const fn`
--> $DIR/const_let_refutable.rs:4:5
|
LL | a + b
LL | const fn slice([a, b]: &[i32]) -> i32 {
| ^^^^^^ pattern `&[]` not covered
-error[E0723]: can only call other `const fn` within a `const fn`, but `const std::ops::Add::add` is not stable as `const fn`
+error[E0723]: can only call other `const fn` within a `const fn`, but `const <&i32 as std::ops::Add>::add` is not stable as `const fn`
--> $DIR/const_let_refutable.rs:4:5
|
LL | a + b
--> $DIR/deprecated_no_stack_check.rs:2:12
|
LL | #![feature(no_stack_check)]
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ feature has been removed
error: aborting due to previous error
-#[deprecated = b"test"] //~ ERROR attribute must be of the form
+#[deprecated = b"test"] //~ ERROR malformed `deprecated` attribute
fn foo() {}
fn main() {}
-error: attribute must be of the form `#[deprecated]` or `#[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason)]` or `#[deprecated = "reason"]`
+error: malformed `deprecated` attribute input
--> $DIR/invalid-literal.rs:1:1
|
LL | #[deprecated = b"test"]
| ^^^^^^^^^^^^^^^^^^^^^^^
+help: the following are the possible correct uses
+ |
+LL | #[deprecated]
+ | ^^^^^^^^^^^^^
+LL | #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[deprecated = "reason"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
+++ /dev/null
-use std::marker::PhantomData;
-
-pub trait External {}
-
-pub struct M<'a, 'b, 'c, T, U, V> {
- a: PhantomData<&'a ()>,
- b: PhantomData<&'b ()>,
- c: PhantomData<&'c ()>,
- d: PhantomData<T>,
- e: PhantomData<U>,
- f: PhantomData<V>,
-}
-
-impl<'a, 'b, 'c, T, U, V, W> External for (T, M<'a, 'b, 'c, Box<U>, V, W>)
-where
- 'b: 'a,
- T: 'a,
- U: (FnOnce(T) -> V) + 'static,
- V: Iterator<Item=T> + Clone,
- W: std::ops::Add,
- W::Output: Copy,
-{}
+++ /dev/null
-// Ref: https://github.com/rust-lang/rust/issues/23563#issuecomment-260751672
-
-pub trait LolTo<T> {
- fn convert_to(&self) -> T;
-}
-
-pub trait LolInto<T>: Sized {
- fn convert_into(self) -> T;
-}
-
-pub trait LolFrom<T> {
- fn from(T) -> Self;
-}
-
-impl<'a, T: ?Sized, U> LolInto<U> for &'a T where T: LolTo<U> {
- fn convert_into(self) -> U {
- self.convert_to()
- }
-}
-
-impl<T, U> LolFrom<T> for U where T: LolInto<U> {
- fn from(t: T) -> U {
- t.convert_into()
- }
-}
+++ /dev/null
-// aux-build:complex_impl_support.rs
-
-extern crate complex_impl_support;
-
-use complex_impl_support::{External, M};
-
-struct Q;
-
-impl<R> External for (Q, R) {} //~ ERROR must be used
-//~^ ERROR conflicting implementations of trait
-
-fn main() {}
+++ /dev/null
-error[E0119]: conflicting implementations of trait `complex_impl_support::External` for type `(Q, complex_impl_support::M<'_, '_, '_, std::boxed::Box<_>, _, _>)`:
- --> $DIR/complex-impl.rs:9:1
- |
-LL | impl<R> External for (Q, R) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `complex_impl_support`:
- - impl<'a, 'b, 'c, T, U, V, W> complex_impl_support::External for (T, complex_impl_support::M<'a, 'b, 'c, std::boxed::Box<U>, V, W>)
- where <U as std::ops::FnOnce<(T,)>>::Output == V, <V as std::iter::Iterator>::Item == T, 'b : 'a, T : 'a, U: std::ops::FnOnce<(T,)>, U : 'static, V: std::iter::Iterator, V: std::clone::Clone, W: std::ops::Add, <W as std::ops::Add>::Output: std::marker::Copy;
-
-error[E0210]: type parameter `R` must be used as the type parameter for some local type (e.g., `MyStruct<R>`)
- --> $DIR/complex-impl.rs:9:1
- |
-LL | impl<R> External for (Q, R) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `R` must be used as the type parameter for some local type
- |
- = note: only traits defined in the current crate can be implemented for a type parameter
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0119, E0210.
-For more information about an error, try `rustc --explain E0119`.
+++ /dev/null
-use std::marker::PhantomData;
-use std::convert::{TryFrom, AsRef};
-
-struct Q;
-impl AsRef<Q> for Box<Q> { //~ ERROR conflicting implementations
- fn as_ref(&self) -> &Q {
- &**self
- }
-}
-
-struct S;
-impl From<S> for S { //~ ERROR conflicting implementations
- fn from(s: S) -> S {
- s
- }
-}
-
-struct X;
-impl TryFrom<X> for X { //~ ERROR conflicting implementations
- type Error = ();
- fn try_from(u: X) -> Result<X, ()> {
- Ok(u)
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0119]: conflicting implementations of trait `std::convert::AsRef<Q>` for type `std::boxed::Box<Q>`:
- --> $DIR/conflict-with-std.rs:5:1
- |
-LL | impl AsRef<Q> for Box<Q> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `alloc`:
- - impl<T> std::convert::AsRef<T> for std::boxed::Box<T>
- where T: ?Sized;
-
-error[E0119]: conflicting implementations of trait `std::convert::From<S>` for type `S`:
- --> $DIR/conflict-with-std.rs:12:1
- |
-LL | impl From<S> for S {
- | ^^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `core`:
- - impl<T> std::convert::From<T> for T;
-
-error[E0119]: conflicting implementations of trait `std::convert::TryFrom<X>` for type `X`:
- --> $DIR/conflict-with-std.rs:19:1
- |
-LL | impl TryFrom<X> for X {
- | ^^^^^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `core`:
- - impl<T, U> std::convert::TryFrom<U> for T
- where U: std::convert::Into<T>;
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0119`.
+++ /dev/null
-// aux-build:issue-23563-a.rs
-
-// Ref: https://github.com/rust-lang/rust/issues/23563#issuecomment-260751672
-
-extern crate issue_23563_a as a;
-
-use a::LolFrom;
-use a::LolInto;
-use a::LolTo;
-
-struct LocalType<T>(Option<T>);
-
-impl<'a, T> LolFrom<&'a [T]> for LocalType<T> { //~ ERROR conflicting implementations of trait
- fn from(_: &'a [T]) -> LocalType<T> { LocalType(None) }
-}
-
-impl<T> LolInto<LocalType<T>> for LocalType<T> {
- fn convert_into(self) -> LocalType<T> {
- self
- }
-}
-
-impl LolTo<LocalType<u8>> for [u8] {
- fn convert_to(&self) -> LocalType<u8> {
- LocalType(None)
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0119]: conflicting implementations of trait `a::LolFrom<&[_]>` for type `LocalType<_>`:
- --> $DIR/issue-23563.rs:13:1
- |
-LL | impl<'a, T> LolFrom<&'a [T]> for LocalType<T> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `issue_23563_a`:
- - impl<T, U> a::LolFrom<T> for U
- where T: a::LolInto<U>;
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0119`.
+++ /dev/null
-pub struct GenX<S> {
- inner: S,
-}
-
-impl<S> Into<S> for GenX<S> { //~ ERROR conflicting implementations
- fn into(self) -> S {
- self.inner
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0119]: conflicting implementations of trait `std::convert::Into<_>` for type `GenX<_>`:
- --> $DIR/issue-27403.rs:5:1
- |
-LL | impl<S> Into<S> for GenX<S> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `core`:
- - impl<T, U> std::convert::Into<U> for T
- where U: std::convert::From<T>;
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0119`.
+++ /dev/null
-use std::ops::Deref;
-
-struct Foo;
-
-impl<Foo> Deref for Foo { } //~ ERROR must be used
-//~^ ERROR conflicting implementations
-
-fn main() {}
+++ /dev/null
-error[E0119]: conflicting implementations of trait `std::ops::Deref` for type `&_`:
- --> $DIR/issue-28981.rs:5:1
- |
-LL | impl<Foo> Deref for Foo { }
- | ^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `core`:
- - impl<T> std::ops::Deref for &T
- where T: ?Sized;
-
-error[E0210]: type parameter `Foo` must be used as the type parameter for some local type (e.g., `MyStruct<Foo>`)
- --> $DIR/issue-28981.rs:5:1
- |
-LL | impl<Foo> Deref for Foo { }
- | ^^^^^^^^^^^^^^^^^^^^^^^ type parameter `Foo` must be used as the type parameter for some local type
- |
- = note: only traits defined in the current crate can be implemented for a type parameter
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0119, E0210.
-For more information about an error, try `rustc --explain E0119`.
+++ /dev/null
-// Ref: https://stackoverflow.com/q/37347311
-
-trait Storage {
- type Error;
-}
-
-enum MyError<S: Storage> {
- StorageProblem(S::Error),
-}
-
-impl<S: Storage> From<S::Error> for MyError<S> { //~ ERROR conflicting implementations
- fn from(error: S::Error) -> MyError<S> {
- MyError::StorageProblem(error)
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0119]: conflicting implementations of trait `std::convert::From<MyError<_>>` for type `MyError<_>`:
- --> $DIR/so-37347311.rs:11:1
- |
-LL | impl<S: Storage> From<S::Error> for MyError<S> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `core`:
- - impl<T> std::convert::From<T> for T;
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0119`.
+++ /dev/null
-// edition:2015
-
-#![feature(async_await)]
-
-async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition
-
-fn baz() { async fn foo() {} } //~ ERROR `async fn` is not permitted in the 2015 edition
-
-async fn async_baz() { //~ ERROR `async fn` is not permitted in the 2015 edition
- async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition
-}
-
-struct Foo {}
-
-impl Foo {
- async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition
-}
-
-trait Bar {
- async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition
- //~^ ERROR trait fns cannot be declared `async`
-}
-
-fn main() {
- macro_rules! accept_item { ($x:item) => {} }
-
- accept_item! {
- async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition
- }
-
- let inside_closure = || {
- async fn bar() {} //~ ERROR `async fn` is not permitted in the 2015 edition
- };
-}
+++ /dev/null
-error[E0670]: `async fn` is not permitted in the 2015 edition
- --> $DIR/edition-deny-async-fns-2015.rs:5:1
- |
-LL | async fn foo() {}
- | ^^^^^
-
-error[E0670]: `async fn` is not permitted in the 2015 edition
- --> $DIR/edition-deny-async-fns-2015.rs:7:12
- |
-LL | fn baz() { async fn foo() {} }
- | ^^^^^
-
-error[E0670]: `async fn` is not permitted in the 2015 edition
- --> $DIR/edition-deny-async-fns-2015.rs:10:5
- |
-LL | async fn bar() {}
- | ^^^^^
-
-error[E0670]: `async fn` is not permitted in the 2015 edition
- --> $DIR/edition-deny-async-fns-2015.rs:9:1
- |
-LL | async fn async_baz() {
- | ^^^^^
-
-error[E0670]: `async fn` is not permitted in the 2015 edition
- --> $DIR/edition-deny-async-fns-2015.rs:32:9
- |
-LL | async fn bar() {}
- | ^^^^^
-
-error[E0670]: `async fn` is not permitted in the 2015 edition
- --> $DIR/edition-deny-async-fns-2015.rs:28:9
- |
-LL | async fn foo() {}
- | ^^^^^
-
-error[E0670]: `async fn` is not permitted in the 2015 edition
- --> $DIR/edition-deny-async-fns-2015.rs:16:5
- |
-LL | async fn foo() {}
- | ^^^^^
-
-error[E0706]: trait fns cannot be declared `async`
- --> $DIR/edition-deny-async-fns-2015.rs:20:5
- |
-LL | async fn foo() {}
- | ^^^^^^^^^^^^^^^^^
-
-error[E0670]: `async fn` is not permitted in the 2015 edition
- --> $DIR/edition-deny-async-fns-2015.rs:20:5
- |
-LL | async fn foo() {}
- | ^^^^^
-
-error: aborting due to 9 previous errors
-
-For more information about this error, try `rustc --explain E0670`.
-error[E0452]: malformed lint attribute
+error[E0452]: malformed lint attribute input
--> $DIR/E0452.rs:1:10
|
LL | #![allow(foo = "")]
- | ^^^^^^^^
+ | ^^^^^^^^ bad attribute argument
error: aborting due to previous error
--- /dev/null
+fn inside_closure(x: &mut i32) {
+}
+
+fn outside_closure_1(x: &mut i32) {
+}
+
+fn outside_closure_2(x: &i32) {
+}
+
+fn foo(a: &mut i32) {
+ let bar = || {
+ inside_closure(a)
+ };
+ outside_closure_1(a);
+ //~^ ERROR cannot borrow `*a` as mutable because previous closure requires unique access
+
+ outside_closure_2(a);
+ //~^ ERROR cannot borrow `*a` as immutable because previous closure requires unique access
+
+ drop(bar);
+}
+
+fn main() {
+}
--- /dev/null
+error[E0501]: cannot borrow `*a` as mutable because previous closure requires unique access
+ --> $DIR/E0501.rs:14:23
+ |
+LL | let bar = || {
+ | -- closure construction occurs here
+LL | inside_closure(a)
+ | - first borrow occurs due to use of `a` in closure
+LL | };
+LL | outside_closure_1(a);
+ | ^ second borrow occurs here
+...
+LL | drop(bar);
+ | --- first borrow later used here
+
+error[E0501]: cannot borrow `*a` as immutable because previous closure requires unique access
+ --> $DIR/E0501.rs:17:23
+ |
+LL | let bar = || {
+ | -- closure construction occurs here
+LL | inside_closure(a)
+ | - first borrow occurs due to use of `a` in closure
+...
+LL | outside_closure_2(a);
+ | ^ second borrow occurs here
+...
+LL | drop(bar);
+ | --- first borrow later used here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0501`.
--- /dev/null
+struct FancyNum {
+ num: u8,
+}
+
+fn main() {
+ let mut fancy_num = FancyNum { num: 5 };
+ let fancy_ref = &fancy_num;
+ fancy_num = FancyNum { num: 6 }; //~ ERROR [E0506]
+
+ println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num);
+}
--- /dev/null
+error[E0506]: cannot assign to `fancy_num` because it is borrowed
+ --> $DIR/E0506.rs:8:5
+ |
+LL | let fancy_ref = &fancy_num;
+ | ---------- borrow of `fancy_num` occurs here
+LL | fancy_num = FancyNum { num: 6 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `fancy_num` occurs here
+LL |
+LL | println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num);
+ | ------------- borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
--- /dev/null
+struct NonCopy;
+
+fn main() {
+ let array = [NonCopy; 1];
+ let _value = array[0]; //~ ERROR [E0508]
+}
--- /dev/null
+error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array
+ --> $DIR/E0508-fail.rs:5:18
+ |
+LL | let _value = array[0];
+ | ^^^^^^^^
+ | |
+ | 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`.
--- /dev/null
+struct NonCopy;
+
+fn main() {
+ let array = [NonCopy; 1];
+ let _value = array[0]; //~ ERROR [E0508]
+}
--- /dev/null
+error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array
+ --> $DIR/E0508.rs:5:18
+ |
+LL | let _value = array[0];
+ | ^^^^^^^^
+ | |
+ | 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`.
--- /dev/null
+mod module_that_doesnt_exist; //~ ERROR E0583
+
+fn main() {
+}
--- /dev/null
+error[E0583]: file not found for module `module_that_doesnt_exist`
+ --> $DIR/E0583.rs:1:5
+ |
+LL | mod module_that_doesnt_exist;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: name the file either module_that_doesnt_exist.rs or module_that_doesnt_exist/mod.rs inside the directory "$DIR"
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0583`.
--- /dev/null
+static NUM: i32 = 18;
+
+fn main() {
+ NUM = 20; //~ ERROR cannot assign to immutable static item `NUM`
+}
--- /dev/null
+error[E0594]: cannot assign to immutable static item `NUM`
+ --> $DIR/E0594.rs:4:5
+ |
+LL | NUM = 20;
+ | ^^^^^^^^ cannot assign
+
+error: aborting due to previous error
+
--- /dev/null
+fn main() {
+ let x = 1;
+ let y = &mut x; //~ ERROR [E0596]
+}
--- /dev/null
+error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
+ --> $DIR/E0596.rs:3:13
+ |
+LL | let x = 1;
+ | - help: consider changing this to be mutable: `mut x`
+LL | let y = &mut x;
+ | ^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
--- /dev/null
+#[derive(Clone, Copy)]
+struct S;
+
+trait T {
+ fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in methods without bodies
+
+ fn bar((x, y): (i32, i32)) {} //~ ERROR patterns aren't allowed in methods without bodies
+
+ fn method(S { .. }: S) {} //~ ERROR patterns aren't allowed in methods without bodies
+
+ fn f(&ident: &S) {} // ok
+ fn g(&&ident: &&S) {} // ok
+ fn h(mut ident: S) {} // ok
+}
+
+fn main() {}
--- /dev/null
+error[E0642]: patterns aren't allowed in methods without bodies
+ --> $DIR/E0642.rs:5:12
+ |
+LL | fn foo((x, y): (i32, i32));
+ | ^^^^^^
+help: give this argument a name or use an underscore to ignore it
+ |
+LL | fn foo(_: (i32, i32));
+ | ^
+
+error[E0642]: patterns aren't allowed in methods without bodies
+ --> $DIR/E0642.rs:7:12
+ |
+LL | fn bar((x, y): (i32, i32)) {}
+ | ^^^^^^
+help: give this argument a name or use an underscore to ignore it
+ |
+LL | fn bar(_: (i32, i32)) {}
+ | ^
+
+error[E0642]: patterns aren't allowed in methods without bodies
+ --> $DIR/E0642.rs:9:15
+ |
+LL | fn method(S { .. }: S) {}
+ | ^^^^^^^^
+help: give this argument a name or use an underscore to ignore it
+ |
+LL | fn method(_: S) {}
+ | ^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0642`.
--- /dev/null
+#![feature(asm)]
+
+fn main() {
+ let a;
+ asm!("nop" "nop");
+ //~^ ERROR E0660
+ asm!("nop" "nop" : "=r"(a));
+ //~^ ERROR E0660
+}
--- /dev/null
+error[E0660]: malformed inline assembly
+ --> $DIR/E0660.rs:5:5
+ |
+LL | asm!("nop" "nop");
+ | ^^^^^^^^^^^^^^^^^^
+
+error[E0660]: malformed inline assembly
+ --> $DIR/E0660.rs:7:5
+ |
+LL | asm!("nop" "nop" : "=r"(a));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+#![feature(asm)]
+
+fn main() {
+ let a;
+ asm!("nop" : "r"(a));
+ //~^ ERROR E0661
+}
--- /dev/null
+error[E0661]: output operand constraint lacks '=' or '+'
+ --> $DIR/E0661.rs:5:18
+ |
+LL | asm!("nop" : "r"(a));
+ | ^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(asm)]
+
+fn main() {
+ asm!("xor %eax, %eax"
+ :
+ : "=test"("a") //~ ERROR E0662
+ );
+}
--- /dev/null
+error[E0662]: input operand constraint contains '='
+ --> $DIR/E0662.rs:6:12
+ |
+LL | : "=test"("a")
+ | ^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(asm)]
+
+fn main() {
+ asm!("xor %eax, %eax"
+ :
+ : "+test"("a") //~ ERROR E0663
+ );
+}
--- /dev/null
+error[E0663]: input operand constraint contains '+'
+ --> $DIR/E0663.rs:6:12
+ |
+LL | : "+test"("a")
+ | ^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(asm)]
+
+fn main() {
+ asm!("mov $$0x200, %eax"
+ :
+ :
+ : "{eax}" //~ ERROR E0664
+ );
+}
--- /dev/null
+error[E0664]: clobber should not be surrounded by braces
+ --> $DIR/E0664.rs:7:12
+ |
+LL | : "{eax}"
+ | ^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#[derive(Default)] //~ ERROR E0665
+enum Food {
+ Sweet,
+ Salty,
+}
+
+fn main() {
+}
--- /dev/null
+error[E0665]: `Default` cannot be derived for enums, only structs
+ --> $DIR/E0665.rs:1:10
+ |
+LL | #[derive(Default)]
+ | ^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// compile-pass
+
+// This is a stub feature that doesn't control anything, so to make tidy happy,
+// gate-test-test_2018_feature
+
+#![feature(test_2018_feature)]
+//~^ WARN the feature `test_2018_feature` is included in the Rust 2018 edition
+#![feature(rust_2018_preview)]
+
+fn main() {}
--- /dev/null
+warning[E0705]: the feature `test_2018_feature` is included in the Rust 2018 edition
+ --> $DIR/E0705.rs:6:12
+ |
+LL | #![feature(test_2018_feature)]
+ | ^^^^^^^^^^^^^^^^^
+
--- /dev/null
+use std::marker::PhantomData;
+
+pub trait External {}
+
+pub struct M<'a, 'b, 'c, T, U, V> {
+ a: PhantomData<&'a ()>,
+ b: PhantomData<&'b ()>,
+ c: PhantomData<&'c ()>,
+ d: PhantomData<T>,
+ e: PhantomData<U>,
+ f: PhantomData<V>,
+}
+
+impl<'a, 'b, 'c, T, U, V, W> External for (T, M<'a, 'b, 'c, Box<U>, V, W>)
+where
+ 'b: 'a,
+ T: 'a,
+ U: (FnOnce(T) -> V) + 'static,
+ V: Iterator<Item=T> + Clone,
+ W: std::ops::Add,
+ W::Output: Copy,
+{}
--- /dev/null
+// Ref: https://github.com/rust-lang/rust/issues/23563#issuecomment-260751672
+
+pub trait LolTo<T> {
+ fn convert_to(&self) -> T;
+}
+
+pub trait LolInto<T>: Sized {
+ fn convert_into(self) -> T;
+}
+
+pub trait LolFrom<T> {
+ fn from(T) -> Self;
+}
+
+impl<'a, T: ?Sized, U> LolInto<U> for &'a T where T: LolTo<U> {
+ fn convert_into(self) -> U {
+ self.convert_to()
+ }
+}
+
+impl<T, U> LolFrom<T> for U where T: LolInto<U> {
+ fn from(t: T) -> U {
+ t.convert_into()
+ }
+}
--- /dev/null
+// aux-build:complex_impl_support.rs
+
+extern crate complex_impl_support;
+
+use complex_impl_support::{External, M};
+
+struct Q;
+
+impl<R> External for (Q, R) {} //~ ERROR must be used
+//~^ ERROR conflicting implementations of trait
+
+fn main() {}
--- /dev/null
+error[E0119]: conflicting implementations of trait `complex_impl_support::External` for type `(Q, complex_impl_support::M<'_, '_, '_, std::boxed::Box<_>, _, _>)`:
+ --> $DIR/complex-impl.rs:9:1
+ |
+LL | impl<R> External for (Q, R) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: conflicting implementation in crate `complex_impl_support`:
+ - impl<'a, 'b, 'c, T, U, V, W> complex_impl_support::External for (T, complex_impl_support::M<'a, 'b, 'c, std::boxed::Box<U>, V, W>)
+ where <U as std::ops::FnOnce<(T,)>>::Output == V, <V as std::iter::Iterator>::Item == T, 'b : 'a, T : 'a, U: std::ops::FnOnce<(T,)>, U : 'static, V: std::iter::Iterator, V: std::clone::Clone, W: std::ops::Add, <W as std::ops::Add>::Output: std::marker::Copy;
+
+error[E0210]: type parameter `R` must be used as the type parameter for some local type (e.g., `MyStruct<R>`)
+ --> $DIR/complex-impl.rs:9:1
+ |
+LL | impl<R> External for (Q, R) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `R` must be used as the type parameter for some local type
+ |
+ = note: only traits defined in the current crate can be implemented for a type parameter
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0119, E0210.
+For more information about an error, try `rustc --explain E0119`.
--- /dev/null
+use std::marker::PhantomData;
+use std::convert::{TryFrom, AsRef};
+
+struct Q;
+impl AsRef<Q> for Box<Q> { //~ ERROR conflicting implementations
+ fn as_ref(&self) -> &Q {
+ &**self
+ }
+}
+
+struct S;
+impl From<S> for S { //~ ERROR conflicting implementations
+ fn from(s: S) -> S {
+ s
+ }
+}
+
+struct X;
+impl TryFrom<X> for X { //~ ERROR conflicting implementations
+ type Error = ();
+ fn try_from(u: X) -> Result<X, ()> {
+ Ok(u)
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0119]: conflicting implementations of trait `std::convert::AsRef<Q>` for type `std::boxed::Box<Q>`:
+ --> $DIR/conflict-with-std.rs:5:1
+ |
+LL | impl AsRef<Q> for Box<Q> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: conflicting implementation in crate `alloc`:
+ - impl<T> std::convert::AsRef<T> for std::boxed::Box<T>
+ where T: ?Sized;
+
+error[E0119]: conflicting implementations of trait `std::convert::From<S>` for type `S`:
+ --> $DIR/conflict-with-std.rs:12:1
+ |
+LL | impl From<S> for S {
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: conflicting implementation in crate `core`:
+ - impl<T> std::convert::From<T> for T;
+
+error[E0119]: conflicting implementations of trait `std::convert::TryFrom<X>` for type `X`:
+ --> $DIR/conflict-with-std.rs:19:1
+ |
+LL | impl TryFrom<X> for X {
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: conflicting implementation in crate `core`:
+ - impl<T, U> std::convert::TryFrom<U> for T
+ where U: std::convert::Into<T>;
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0119`.
--- /dev/null
+// aux-build:issue-23563-a.rs
+
+// Ref: https://github.com/rust-lang/rust/issues/23563#issuecomment-260751672
+
+extern crate issue_23563_a as a;
+
+use a::LolFrom;
+use a::LolInto;
+use a::LolTo;
+
+struct LocalType<T>(Option<T>);
+
+impl<'a, T> LolFrom<&'a [T]> for LocalType<T> { //~ ERROR conflicting implementations of trait
+ fn from(_: &'a [T]) -> LocalType<T> { LocalType(None) }
+}
+
+impl<T> LolInto<LocalType<T>> for LocalType<T> {
+ fn convert_into(self) -> LocalType<T> {
+ self
+ }
+}
+
+impl LolTo<LocalType<u8>> for [u8] {
+ fn convert_to(&self) -> LocalType<u8> {
+ LocalType(None)
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0119]: conflicting implementations of trait `a::LolFrom<&[_]>` for type `LocalType<_>`:
+ --> $DIR/issue-23563.rs:13:1
+ |
+LL | impl<'a, T> LolFrom<&'a [T]> for LocalType<T> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: conflicting implementation in crate `issue_23563_a`:
+ - impl<T, U> a::LolFrom<T> for U
+ where T: a::LolInto<U>;
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
--- /dev/null
+pub struct GenX<S> {
+ inner: S,
+}
+
+impl<S> Into<S> for GenX<S> { //~ ERROR conflicting implementations
+ fn into(self) -> S {
+ self.inner
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0119]: conflicting implementations of trait `std::convert::Into<_>` for type `GenX<_>`:
+ --> $DIR/issue-27403.rs:5:1
+ |
+LL | impl<S> Into<S> for GenX<S> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: conflicting implementation in crate `core`:
+ - impl<T, U> std::convert::Into<U> for T
+ where U: std::convert::From<T>;
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
--- /dev/null
+use std::ops::Deref;
+
+struct Foo;
+
+impl<Foo> Deref for Foo { } //~ ERROR must be used
+//~^ ERROR conflicting implementations
+
+fn main() {}
--- /dev/null
+error[E0119]: conflicting implementations of trait `std::ops::Deref` for type `&_`:
+ --> $DIR/issue-28981.rs:5:1
+ |
+LL | impl<Foo> Deref for Foo { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: conflicting implementation in crate `core`:
+ - impl<T> std::ops::Deref for &T
+ where T: ?Sized;
+
+error[E0210]: type parameter `Foo` must be used as the type parameter for some local type (e.g., `MyStruct<Foo>`)
+ --> $DIR/issue-28981.rs:5:1
+ |
+LL | impl<Foo> Deref for Foo { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^ type parameter `Foo` must be used as the type parameter for some local type
+ |
+ = note: only traits defined in the current crate can be implemented for a type parameter
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0119, E0210.
+For more information about an error, try `rustc --explain E0119`.
--- /dev/null
+// Ref: https://stackoverflow.com/q/37347311
+
+trait Storage {
+ type Error;
+}
+
+enum MyError<S: Storage> {
+ StorageProblem(S::Error),
+}
+
+impl<S: Storage> From<S::Error> for MyError<S> { //~ ERROR conflicting implementations
+ fn from(error: S::Error) -> MyError<S> {
+ MyError::StorageProblem(error)
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0119]: conflicting implementations of trait `std::convert::From<MyError<_>>` for type `MyError<_>`:
+ --> $DIR/so-37347311.rs:11:1
+ |
+LL | impl<S: Storage> From<S::Error> for MyError<S> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: conflicting implementation in crate `core`:
+ - impl<T> std::convert::From<T> for T;
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
+++ /dev/null
-// Test that existential types are allowed to contain late-bound regions.
-
-// compile-pass
-// edition:2018
-
-#![feature(async_await, existential_type)]
-
-use std::future::Future;
-
-pub existential type Func: Sized;
-
-// Late bound region should be allowed to escape the function, since it's bound
-// in the type.
-fn null_function_ptr() -> Func {
- None::<for<'a> fn(&'a ())>
-}
-
-async fn async_nop(_: &u8) {}
-
-pub existential type ServeFut: Future<Output=()>;
-
-// Late bound regions occur in the generator witness type here.
-fn serve() -> ServeFut {
- async move {
- let x = 5;
- async_nop(&x).await
- }
-}
-
-fn main() {}
//~^ ERROR arguments to macro_use are not allowed here
#[macro_use = "2700"] struct S;
- //~^ ERROR attribute must be of the form
+ //~^ ERROR malformed `macro_use` attribute
#[macro_use] fn f() { }
LL | mod inner { #![macro_use(my_macro)] }
| ^^^^^^^^^^^^^^^^^^^^^^^
-error: attribute must be of the form `#[macro_use]` or `#[macro_use(name1, name2, ...)]`
+error: malformed `macro_use` attribute input
--> $DIR/issue-43106-gating-of-macro_use.rs:15:5
|
LL | #[macro_use = "2700"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^
+help: the following are the possible correct uses
+ |
+LL | #[macro_use] struct S;
+ | ^^^^^^^^^^^^
+LL | #[macro_use(name1, name2, ...)] struct S;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors
-#![feature(
- foo_bar_baz,
- foo(bar),
- foo = "baz"
-)]
-//~^^^ ERROR: malformed feature
-//~^^^ ERROR: malformed feature
+#![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
+//~^ ERROR malformed `feature`
+//~| ERROR malformed `feature`
-#![feature] //~ ERROR: attribute must be of the form
-#![feature = "foo"] //~ ERROR: attribute must be of the form
+#![feature] //~ ERROR malformed `feature` attribute
+#![feature = "foo"] //~ ERROR malformed `feature` attribute
#![feature(test_removed_feature)] //~ ERROR: feature has been removed
-error[E0556]: malformed feature, expected just one word
- --> $DIR/gated-bad-feature.rs:3:5
+error[E0556]: malformed `feature` attribute input
+ --> $DIR/gated-bad-feature.rs:1:25
|
-LL | foo(bar),
- | ^^^^^^^^
+LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
+ | ^^^^^^^^ help: expected just one word: `foo`
-error[E0556]: malformed feature, expected just one word
- --> $DIR/gated-bad-feature.rs:4:5
+error[E0556]: malformed `feature` attribute input
+ --> $DIR/gated-bad-feature.rs:1:35
|
-LL | foo = "baz"
- | ^^^^^^^^^^^
+LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
+ | ^^^^^^^^^^^ help: expected just one word: `foo`
error[E0557]: feature has been removed
- --> $DIR/gated-bad-feature.rs:12:12
+ --> $DIR/gated-bad-feature.rs:8:12
|
LL | #![feature(test_removed_feature)]
- | ^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^ feature has been removed
-error: attribute must be of the form `#[feature(name1, name1, ...)]`
- --> $DIR/gated-bad-feature.rs:9:1
+error: malformed `feature` attribute input
+ --> $DIR/gated-bad-feature.rs:5:1
|
LL | #![feature]
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^ help: must be of the form: `#[feature(name1, name1, ...)]`
-error: attribute must be of the form `#[feature(name1, name1, ...)]`
- --> $DIR/gated-bad-feature.rs:10:1
+error: malformed `feature` attribute input
+ --> $DIR/gated-bad-feature.rs:6:1
|
LL | #![feature = "foo"]
- | ^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[feature(name1, name1, ...)]`
error: aborting due to 5 previous errors
+++ /dev/null
-// Provoke an unresolved type error (T).
-// Error message should pinpoint the type parameter T as needing to be bound
-// (rather than give a general error message)
-// edition:2018
-#![feature(async_await)]
-async fn bar<T>() -> () {}
-
-async fn foo() {
- bar().await;
- //~^ ERROR type inside generator must be known in this context
- //~| NOTE cannot infer type for `T`
- //~| NOTE the type is part of the generator because of this `yield`
- //~| NOTE in this expansion of desugaring of `await`
-}
-fn main() {}
+++ /dev/null
-error[E0698]: type inside generator must be known in this context
- --> $DIR/unresolved_type_param.rs:9:5
- |
-LL | bar().await;
- | ^^^ cannot infer type for `T`
- |
-note: the type is part of the generator because of this `yield`
- --> $DIR/unresolved_type_param.rs:9:5
- |
-LL | bar().await;
- | ^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0698`.
+++ /dev/null
-// edition:2018
-// Test that impl trait does not allow creating recursive types that are
-// otherwise forbidden when using `async` and `await`.
-
-#![feature(await_macro, async_await, generators)]
-
-async fn recursive_async_function() -> () { //~ ERROR
- await!(recursive_async_function());
-}
-
-fn main() {}
+++ /dev/null
-error[E0720]: opaque type expands to a recursive type
- --> $DIR/recursive-async-impl-trait-type.rs:7:40
- |
-LL | async fn recursive_async_function() -> () {
- | ^^ expands to self-referential type
- |
- = note: expanded type is `std::future::GenFuture<[static generator@$DIR/recursive-async-impl-trait-type.rs:7:43: 9:2 {impl std::future::Future, ()}]>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0720`.
fn a(&self) { }
-//~^ ERROR unexpected `self` argument in function
-//~| NOTE `self` is only valid as the first argument of an associated function
+//~^ ERROR unexpected `self` parameter in function
+//~| NOTE not valid as function parameter
+//~| NOTE `self` is only valid as the first parameter of an associated function
fn main() { }
-error: unexpected `self` argument in function
- --> $DIR/bare-fn-start.rs:1:7
+error: unexpected `self` parameter in function
+ --> $DIR/bare-fn-start.rs:1:6
|
LL | fn a(&self) { }
- | ^^^^ `self` is only valid as the first argument of an associated function
+ | ^^^^^ not valid as function parameter
+ |
+ = note: `self` is only valid as the first parameter of an associated function
error: aborting due to previous error
fn b(foo: u32, &mut self) { }
-//~^ ERROR unexpected `self` argument in function
-//~| NOTE `self` is only valid as the first argument of an associated function
+//~^ ERROR unexpected `self` parameter in function
+//~| NOTE not valid as function parameter
+//~| NOTE `self` is only valid as the first parameter of an associated function
fn main() { }
-error: unexpected `self` argument in function
- --> $DIR/bare-fn.rs:1:21
+error: unexpected `self` parameter in function
+ --> $DIR/bare-fn.rs:1:16
|
LL | fn b(foo: u32, &mut self) { }
- | ^^^^ `self` is only valid as the first argument of an associated function
+ | ^^^^^^^^^ not valid as function parameter
+ |
+ = note: `self` is only valid as the first parameter of an associated function
error: aborting due to previous error
impl Foo {
fn c(foo: u32, self) {}
- //~^ ERROR unexpected `self` argument in function
- //~| NOTE `self` is only valid as the first argument of an associated function
+ //~^ ERROR unexpected `self` parameter in function
+ //~| NOTE must be the first associated function parameter
fn good(&mut self, foo: u32) {}
}
-error: unexpected `self` argument in function
+error: unexpected `self` parameter in function
--> $DIR/trait-fn.rs:4:20
|
LL | fn c(foo: u32, self) {}
- | ^^^^ `self` is only valid as the first argument of an associated function
+ | ^^^^ must be the first associated function parameter
error: aborting due to previous error
// regression test for issue 16974
-#![crate_type(lib)] //~ ERROR attribute must be of the form
+#![crate_type(lib)] //~ ERROR malformed `crate_type` attribute input
fn my_lib_fn() {}
-error: attribute must be of the form `#[crate_type = "bin|lib|..."]`
+error: malformed `crate_type` attribute input
--> $DIR/invalid_crate_type_syntax.rs:2:1
|
LL | #![crate_type(lib)]
- | ^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[crate_type = "bin|lib|..."]`
error: aborting due to previous error
+++ /dev/null
-// compile-pass
-// edition:2018
-
-#![feature(arbitrary_self_types, async_await, await_macro)]
-
-use std::task::{self, Poll};
-use std::future::Future;
-use std::marker::Unpin;
-use std::pin::Pin;
-
-// This is a regression test for a ICE/unbounded recursion issue relating to async-await.
-
-#[derive(Debug)]
-#[must_use = "futures do nothing unless polled"]
-pub struct Lazy<F> {
- f: Option<F>
-}
-
-impl<F> Unpin for Lazy<F> {}
-
-pub fn lazy<F, R>(f: F) -> Lazy<F>
- where F: FnOnce(&mut task::Context) -> R,
-{
- Lazy { f: Some(f) }
-}
-
-impl<R, F> Future for Lazy<F>
- where F: FnOnce(&mut task::Context) -> R,
-{
- type Output = R;
-
- fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context) -> Poll<R> {
- Poll::Ready((self.f.take().unwrap())(cx))
- }
-}
-
-async fn __receive<WantFn, Fut>(want: WantFn) -> ()
- where Fut: Future<Output = ()>, WantFn: Fn(&Box<Send + 'static>) -> Fut,
-{
- await!(lazy(|_| ()));
-}
-
-pub fn basic_spawn_receive() {
- async { await!(__receive(|_| async { () })) };
-}
-
-fn main() {}
+++ /dev/null
-#![allow(dead_code)]
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
-
-// This test checks that generic parameter re-ordering diagnostic suggestions mention that
-// consts come after types and lifetimes when the `const_generics` feature is enabled.
-// We cannot run rustfix on this test because of the above const generics warning.
-
-struct A;
-
-impl A {
- pub fn do_things<T, 'a, 'b: 'a>() {
- //~^ ERROR lifetime parameters must be declared prior to type parameters
- println!("panic");
- }
-}
-
-fn main() {}
+++ /dev/null
-warning: the feature `const_generics` is incomplete and may cause the compiler to crash
- --> $DIR/issue-59508-1.rs:2:12
- |
-LL | #![feature(const_generics)]
- | ^^^^^^^^^^^^^^
-
-error: lifetime parameters must be declared prior to type parameters
- --> $DIR/issue-59508-1.rs:12:25
- |
-LL | pub fn do_things<T, 'a, 'b: 'a>() {
- | ----^^--^^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b: 'a, T>`
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-rustfix
-
-#![allow(dead_code)]
-
-// This test checks that generic parameter re-ordering diagnostic suggestions contain bounds.
-
-struct A;
-
-impl A {
- pub fn do_things<'a, 'b: 'a, T>() {
- //~^ ERROR lifetime parameters must be declared prior to type parameters
- println!("panic");
- }
-}
-
-fn main() {}
+++ /dev/null
-// run-rustfix
-
-#![allow(dead_code)]
-
-// This test checks that generic parameter re-ordering diagnostic suggestions contain bounds.
-
-struct A;
-
-impl A {
- pub fn do_things<T, 'a, 'b: 'a>() {
- //~^ ERROR lifetime parameters must be declared prior to type parameters
- println!("panic");
- }
-}
-
-fn main() {}
+++ /dev/null
-error: lifetime parameters must be declared prior to type parameters
- --> $DIR/issue-59508.rs:10:25
- |
-LL | pub fn do_things<T, 'a, 'b: 'a>() {
- | ----^^--^^----- help: reorder the parameters: lifetimes, then types: `<'a, 'b: 'a, T>`
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-rustfix
-
-#![allow(warnings)]
-
-struct A;
-struct B;
-
-fn foo() -> Result<A, B> {
- Ok(A)
-}
-
-fn bar() -> Result<A, B> {
- foo()
- //~^ ERROR try expression alternatives have incompatible types [E0308]
-}
-
-fn main() {}
+++ /dev/null
-// run-rustfix
-
-#![allow(warnings)]
-
-struct A;
-struct B;
-
-fn foo() -> Result<A, B> {
- Ok(A)
-}
-
-fn bar() -> Result<A, B> {
- foo()?
- //~^ ERROR try expression alternatives have incompatible types [E0308]
-}
-
-fn main() {}
+++ /dev/null
-error[E0308]: try expression alternatives have incompatible types
- --> $DIR/issue-59756.rs:13:5
- |
-LL | foo()?
- | ^^^^^-
- | | |
- | | help: try removing this `?`
- | expected enum `std::result::Result`, found struct `A`
- |
- = note: expected type `std::result::Result<A, B>`
- found type `A`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// aux-build:issue-59764.rs
-// compile-flags:--extern issue_59764
-// edition:2018
-
-#![allow(warnings)]
-
-// This tests the suggestion to import macros from the root of a crate. This aims to capture
-// the case where a user attempts to import a macro from the definition location instead of the
-// root of the crate and the macro is annotated with `#![macro_export]`.
-
-// Edge cases..
-
-mod multiple_imports_same_line_at_end {
- use issue_59764::foo::{baz, makro};
- //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
-}
-
-mod multiple_imports_multiline_at_end_trailing_comma {
- use issue_59764::foo::{
- baz,
- makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
- };
-}
-
-mod multiple_imports_multiline_at_end {
- use issue_59764::foo::{
- baz,
- makro //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
- };
-}
-
-mod multiple_imports_same_line_in_middle {
- use issue_59764::foo::{baz, makro, foobar};
- //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
-}
-
-mod multiple_imports_multiline_in_middle_trailing_comma {
- use issue_59764::foo::{
- baz,
- makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
- foobar,
- };
-}
-
-mod multiple_imports_multiline_in_middle {
- use issue_59764::foo::{
- baz,
- makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
- foobar
- };
-}
-
-mod nested_imports {
- use issue_59764::{foobaz, foo::makro};
- //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
-}
-
-mod nested_multiple_imports {
- use issue_59764::{foobaz, foo::{baz, makro}};
- //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
-}
-
-mod nested_multiline_multiple_imports_trailing_comma {
- use issue_59764::{
- foobaz,
- foo::{
- baz,
- makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
- },
- };
-}
-
-mod nested_multiline_multiple_imports {
- use issue_59764::{
- foobaz,
- foo::{
- baz,
- makro //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
- }
- };
-}
-
-mod doubly_nested_multiple_imports {
- use issue_59764::{foobaz, foo::{baz, makro, barbaz::{barfoo}}};
- //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
-}
-
-mod doubly_multiline_nested_multiple_imports {
- use issue_59764::{
- foobaz,
- foo::{
- baz,
- makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
- barbaz::{
- barfoo,
- }
- }
- };
-}
-
-mod renamed_import {
- use issue_59764::foo::makro as baz;
- //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
-}
-
-mod renamed_multiple_imports {
- use issue_59764::foo::{baz, makro as foobar};
- //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
-}
-
-mod lots_of_whitespace {
- use
- issue_59764::{
-
- foobaz,
-
-
- foo::{baz,
-
- makro as foobar} //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
-
- };
-}
-
-// Simple case..
-
-use issue_59764::foo::makro;
-//~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
-
-makro!(bar);
-//~^ ERROR cannot determine resolution for the macro `makro`
-
-fn main() {
- bar();
- //~^ ERROR cannot find function `bar` in this scope [E0425]
-}
+++ /dev/null
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:14:33
- |
-LL | use issue_59764::foo::{baz, makro};
- | ^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | use issue_59764::{makro, foo::{baz}};
- | ^^^^^^^^^ --^^
-
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:21:9
- |
-LL | makro,
- | ^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | use issue_59764::{makro, foo::{
-LL | baz,
-LL |
-LL | }};
- |
-
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:28:9
- |
-LL | makro
- | ^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | use issue_59764::{makro, foo::{
-LL | baz,
-LL |
-LL | }};
- |
-
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:33:33
- |
-LL | use issue_59764::foo::{baz, makro, foobar};
- | ^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | use issue_59764::{makro, foo::{baz, foobar}};
- | ^^^^^^^^^ -- ^^
-
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:40:9
- |
-LL | makro,
- | ^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | use issue_59764::{makro, foo::{
-LL | baz,
-LL |
-LL | foobar,
-LL | }};
- |
-
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:48:9
- |
-LL | makro,
- | ^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | use issue_59764::{makro, foo::{
-LL | baz,
-LL |
-LL | foobar
-LL | }};
- |
-
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:54:31
- |
-LL | use issue_59764::{foobaz, foo::makro};
- | ^^^^^^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | use issue_59764::{makro, foobaz};
- | ^^^^^^^ --
-
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:59:42
- |
-LL | use issue_59764::{foobaz, foo::{baz, makro}};
- | ^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | use issue_59764::{makro, foobaz, foo::{baz}};
- | ^^^^^^^ --
-
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:68:13
- |
-LL | makro,
- | ^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | use issue_59764::{makro,
-LL | foobaz,
-LL | foo::{
-LL | baz,
-LL |
- |
-
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:78:13
- |
-LL | makro
- | ^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | use issue_59764::{makro,
-LL | foobaz,
-LL | foo::{
-LL | baz,
-LL |
- |
-
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:84:42
- |
-LL | use issue_59764::{foobaz, foo::{baz, makro, barbaz::{barfoo}}};
- | ^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | use issue_59764::{makro, foobaz, foo::{baz, barbaz::{barfoo}}};
- | ^^^^^^^ --
-
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:93:13
- |
-LL | makro,
- | ^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | use issue_59764::{makro,
-LL | foobaz,
-LL | foo::{
-LL | baz,
-LL |
- |
-
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:102:9
- |
-LL | use issue_59764::foo::makro as baz;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | use issue_59764::makro as baz;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:107:33
- |
-LL | use issue_59764::foo::{baz, makro as foobar};
- | ^^^^^^^^^^^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | use issue_59764::{makro as foobar, foo::{baz}};
- | ^^^^^^^^^^^^^^^^^^^ --^^
-
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:120:17
- |
-LL | makro as foobar}
- | ^^^^^^^^^^^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | issue_59764::{makro as foobar,
-LL |
-LL | foobaz,
-LL |
-LL |
-LL | foo::{baz}
- |
-
-error[E0432]: unresolved import `issue_59764::foo::makro`
- --> $DIR/issue-59764.rs:127:5
- |
-LL | use issue_59764::foo::makro;
- | ^^^^^^^^^^^^^^^^^^^^^^^ no `makro` in `foo`
- |
- = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
-help: a macro with this name exists at the root of the crate
- |
-LL | use issue_59764::makro;
- | ^^^^^^^^^^^^^^^^^^
-
-error: cannot determine resolution for the macro `makro`
- --> $DIR/issue-59764.rs:130:1
- |
-LL | makro!(bar);
- | ^^^^^
- |
- = note: import resolution is stuck, try simplifying macro imports
-
-error[E0425]: cannot find function `bar` in this scope
- --> $DIR/issue-59764.rs:134:5
- |
-LL | bar();
- | ^^^ not found in this scope
-
-error: aborting due to 18 previous errors
-
-Some errors have detailed explanations: E0425, E0432.
-For more information about an error, try `rustc --explain E0425`.
+++ /dev/null
-fn main() {}
-
-trait T {
- fn qux() -> Option<usize> {
- let _ = if true {
- });
-//~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
-//~^^ ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `}`
-//~^^^ ERROR 6:11: 6:12: expected identifier, found `;`
-//~^^^^ ERROR missing `fn`, `type`, or `const` for trait-item declaration
- Some(4)
- }
+++ /dev/null
-error: expected one of `.`, `;`, `?`, `else`, or an operator, found `}`
- --> $DIR/issue-60075.rs:6:10
- |
-LL | });
- | ^ expected one of `.`, `;`, `?`, `else`, or an operator here
-
-error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
- --> $DIR/issue-60075.rs:6:11
- |
-LL | fn qux() -> Option<usize> {
- | - unclosed delimiter
-LL | let _ = if true {
-LL | });
- | ^ help: `}` may belong here
-
-error: expected identifier, found `;`
- --> $DIR/issue-60075.rs:6:11
- |
-LL | });
- | ^ expected identifier
-
-error: missing `fn`, `type`, or `const` for trait-item declaration
- --> $DIR/issue-60075.rs:6:12
- |
-LL | });
- | ____________^
-LL | |
-LL | |
-LL | |
-LL | |
-LL | | Some(4)
- | |________^ missing `fn`, `type`, or `const`
-
-error: aborting due to 4 previous errors
-
+++ /dev/null
-// ignore-tidy-linelength
-
-#![deny(warnings)]
-
-struct Borked {}
-
-impl Borked {
- fn a(&self) {}
-}
-
-fn run_wild<T>(b: &Borked) {
- b.a::<'_, T>();
- //~^ ERROR cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
- //~^^ ERROR wrong number of type arguments: expected 0, found 1
- //~^^^ WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-}
-
-fn main() {}
+++ /dev/null
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
- --> $DIR/issue-60622.rs:12:11
- |
-LL | fn a(&self) {}
- | - the late bound lifetime parameter is introduced here
-...
-LL | b.a::<'_, T>();
- | ^^
- |
-note: lint level defined here
- --> $DIR/issue-60622.rs:3:9
- |
-LL | #![deny(warnings)]
- | ^^^^^^^^
- = note: #[deny(late_bound_lifetime_arguments)] implied by #[deny(warnings)]
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
-
-error[E0107]: wrong number of type arguments: expected 0, found 1
- --> $DIR/issue-60622.rs:12:15
- |
-LL | b.a::<'_, T>();
- | ^ unexpected type argument
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0107`.
--- /dev/null
+pub mod foo {
+ #[macro_export]
+ macro_rules! makro {
+ ($foo:ident) => {
+ fn $foo() { }
+ }
+ }
+
+ pub fn baz() {}
+
+ pub fn foobar() {}
+
+ pub mod barbaz {
+ pub fn barfoo() {}
+ }
+}
+
+pub fn foobaz() {}
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0284`.
#[repr]
let _y = "123";
//~^^ ERROR attribute should not be applied to a statement
- //~| ERROR attribute must be of the form
+ //~| ERROR malformed `repr` attribute
fn foo() {}
let _z = #[repr] 1;
//~^ ERROR attribute should not be applied to an expression
- //~| ERROR attribute must be of the form
+ //~| ERROR malformed `repr` attribute
}
-error: attribute must be of the form `#[repr(C, packed, ...)]`
+error: malformed `repr` attribute input
--> $DIR/issue-43988.rs:24:5
|
LL | #[repr]
- | ^^^^^^^
+ | ^^^^^^^ help: must be of the form: `#[repr(C, packed, ...)]`
-error: attribute must be of the form `#[repr(C, packed, ...)]`
+error: malformed `repr` attribute input
--> $DIR/issue-43988.rs:35:14
|
LL | let _z = #[repr] 1;
- | ^^^^^^^
+ | ^^^^^^^ help: must be of the form: `#[repr(C, packed, ...)]`
error[E0518]: attribute should be applied to function or closure
--> $DIR/issue-43988.rs:5:5
+++ /dev/null
-// edition:2018
-//
-// Tests that the .await syntax can't be used to make a generator
-
-#![feature(async_await)]
-
-async fn foo() {}
-
-fn make_generator() {
- let _gen = || foo.await; //~ ERROR `await` is only allowed inside `async` functions and blocks
-}
-
-fn main() {}
+++ /dev/null
-error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/issue-51719.rs:10:19
- |
-LL | let _gen = || foo.await;
- | -- ^^^^^^^^^ only allowed inside `async` functions and blocks
- | |
- | this is not `async`
-
-error: aborting due to previous error
-
+++ /dev/null
-// edition:2018
-
-#![feature(async_await)]
-
-async fn inc(limit: i64) -> i64 {
- limit + 1
-}
-
-fn main() {
- let result = inc(10000);
- let finished = result.await;
- //~^ ERROR `await` is only allowed inside `async` functions and blocks
-}
+++ /dev/null
-error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/issue-51751.rs:11:20
- |
-LL | fn main() {
- | ---- this is not `async`
-LL | let result = inc(10000);
-LL | let finished = result.await;
- | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
-
-error: aborting due to previous error
-
+++ /dev/null
-// compile-pass
-// edition:2018
-
-#![feature(async_await, await_macro)]
-
-use std::sync::Arc;
-
-trait SomeTrait: Send + Sync + 'static {
- fn do_something(&self);
-}
-
-async fn my_task(obj: Arc<SomeTrait>) {
- unimplemented!()
-}
-
-fn main() {}
+++ /dev/null
-// compile-pass
-// edition:2018
-
-#![feature(async_await, await_macro)]
-
-use std::future::Future;
-
-#[allow(unused)]
-async fn foo<F: Future<Output = i32>>(x: &i32, future: F) -> i32 {
- let y = await!(future);
- *x + y
-}
-
-fn main() {}
+++ /dev/null
-// compile-pass
-// edition:2018
-
-#![feature(async_await, await_macro)]
-
-struct Xyz {
- a: u64,
-}
-
-trait Foo {}
-
-impl Xyz {
- async fn do_sth<'a>(
- &'a self, foo: &'a dyn Foo
- ) -> bool
- {
- true
- }
-}
-
-fn main() {}
+++ /dev/null
-// compile-pass
-// edition:2018
-
-#![feature(async_await, await_macro)]
-
-use std::future::Future;
-
-#[allow(unused)]
-async fn enter<'a, F, R>(mut callback: F)
-where
- F: FnMut(&'a mut i32) -> R,
- R: Future<Output = ()> + 'a,
-{
- unimplemented!()
-}
-
-fn main() {}
--- /dev/null
+#![allow(dead_code)]
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+// This test checks that generic parameter re-ordering diagnostic suggestions mention that
+// consts come after types and lifetimes when the `const_generics` feature is enabled.
+// We cannot run rustfix on this test because of the above const generics warning.
+
+struct A;
+
+impl A {
+ pub fn do_things<T, 'a, 'b: 'a>() {
+ //~^ ERROR lifetime parameters must be declared prior to type parameters
+ println!("panic");
+ }
+}
+
+fn main() {}
--- /dev/null
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+ --> $DIR/issue-59508-1.rs:2:12
+ |
+LL | #![feature(const_generics)]
+ | ^^^^^^^^^^^^^^
+
+error: lifetime parameters must be declared prior to type parameters
+ --> $DIR/issue-59508-1.rs:12:25
+ |
+LL | pub fn do_things<T, 'a, 'b: 'a>() {
+ | ----^^--^^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b: 'a, T>`
+
+error: aborting due to previous error
+
--- /dev/null
+// run-rustfix
+
+#![allow(dead_code)]
+
+// This test checks that generic parameter re-ordering diagnostic suggestions contain bounds.
+
+struct A;
+
+impl A {
+ pub fn do_things<'a, 'b: 'a, T>() {
+ //~^ ERROR lifetime parameters must be declared prior to type parameters
+ println!("panic");
+ }
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+
+#![allow(dead_code)]
+
+// This test checks that generic parameter re-ordering diagnostic suggestions contain bounds.
+
+struct A;
+
+impl A {
+ pub fn do_things<T, 'a, 'b: 'a>() {
+ //~^ ERROR lifetime parameters must be declared prior to type parameters
+ println!("panic");
+ }
+}
+
+fn main() {}
--- /dev/null
+error: lifetime parameters must be declared prior to type parameters
+ --> $DIR/issue-59508.rs:10:25
+ |
+LL | pub fn do_things<T, 'a, 'b: 'a>() {
+ | ----^^--^^----- help: reorder the parameters: lifetimes, then types: `<'a, 'b: 'a, T>`
+
+error: aborting due to previous error
+
--- /dev/null
+// run-rustfix
+
+#![allow(warnings)]
+
+struct A;
+struct B;
+
+fn foo() -> Result<A, B> {
+ Ok(A)
+}
+
+fn bar() -> Result<A, B> {
+ foo()
+ //~^ ERROR try expression alternatives have incompatible types [E0308]
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+
+#![allow(warnings)]
+
+struct A;
+struct B;
+
+fn foo() -> Result<A, B> {
+ Ok(A)
+}
+
+fn bar() -> Result<A, B> {
+ foo()?
+ //~^ ERROR try expression alternatives have incompatible types [E0308]
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: try expression alternatives have incompatible types
+ --> $DIR/issue-59756.rs:13:5
+ |
+LL | foo()?
+ | ^^^^^-
+ | | |
+ | | help: try removing this `?`
+ | expected enum `std::result::Result`, found struct `A`
+ |
+ = note: expected type `std::result::Result<A, B>`
+ found type `A`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// aux-build:issue-59764.rs
+// compile-flags:--extern issue_59764
+// edition:2018
+
+#![allow(warnings)]
+
+// This tests the suggestion to import macros from the root of a crate. This aims to capture
+// the case where a user attempts to import a macro from the definition location instead of the
+// root of the crate and the macro is annotated with `#![macro_export]`.
+
+// Edge cases..
+
+mod multiple_imports_same_line_at_end {
+ use issue_59764::foo::{baz, makro};
+ //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+}
+
+mod multiple_imports_multiline_at_end_trailing_comma {
+ use issue_59764::foo::{
+ baz,
+ makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+ };
+}
+
+mod multiple_imports_multiline_at_end {
+ use issue_59764::foo::{
+ baz,
+ makro //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+ };
+}
+
+mod multiple_imports_same_line_in_middle {
+ use issue_59764::foo::{baz, makro, foobar};
+ //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+}
+
+mod multiple_imports_multiline_in_middle_trailing_comma {
+ use issue_59764::foo::{
+ baz,
+ makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+ foobar,
+ };
+}
+
+mod multiple_imports_multiline_in_middle {
+ use issue_59764::foo::{
+ baz,
+ makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+ foobar
+ };
+}
+
+mod nested_imports {
+ use issue_59764::{foobaz, foo::makro};
+ //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+}
+
+mod nested_multiple_imports {
+ use issue_59764::{foobaz, foo::{baz, makro}};
+ //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+}
+
+mod nested_multiline_multiple_imports_trailing_comma {
+ use issue_59764::{
+ foobaz,
+ foo::{
+ baz,
+ makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+ },
+ };
+}
+
+mod nested_multiline_multiple_imports {
+ use issue_59764::{
+ foobaz,
+ foo::{
+ baz,
+ makro //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+ }
+ };
+}
+
+mod doubly_nested_multiple_imports {
+ use issue_59764::{foobaz, foo::{baz, makro, barbaz::{barfoo}}};
+ //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+}
+
+mod doubly_multiline_nested_multiple_imports {
+ use issue_59764::{
+ foobaz,
+ foo::{
+ baz,
+ makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+ barbaz::{
+ barfoo,
+ }
+ }
+ };
+}
+
+mod renamed_import {
+ use issue_59764::foo::makro as baz;
+ //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+}
+
+mod renamed_multiple_imports {
+ use issue_59764::foo::{baz, makro as foobar};
+ //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+}
+
+mod lots_of_whitespace {
+ use
+ issue_59764::{
+
+ foobaz,
+
+
+ foo::{baz,
+
+ makro as foobar} //~ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+
+ };
+}
+
+// Simple case..
+
+use issue_59764::foo::makro;
+//~^ ERROR unresolved import `issue_59764::foo::makro` [E0432]
+
+makro!(bar);
+//~^ ERROR cannot determine resolution for the macro `makro`
+
+fn main() {
+ bar();
+ //~^ ERROR cannot find function `bar` in this scope [E0425]
+}
--- /dev/null
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:14:33
+ |
+LL | use issue_59764::foo::{baz, makro};
+ | ^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | use issue_59764::{makro, foo::{baz}};
+ | ^^^^^^^^^ --^^
+
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:21:9
+ |
+LL | makro,
+ | ^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | use issue_59764::{makro, foo::{
+LL | baz,
+LL |
+LL | }};
+ |
+
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:28:9
+ |
+LL | makro
+ | ^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | use issue_59764::{makro, foo::{
+LL | baz,
+LL |
+LL | }};
+ |
+
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:33:33
+ |
+LL | use issue_59764::foo::{baz, makro, foobar};
+ | ^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | use issue_59764::{makro, foo::{baz, foobar}};
+ | ^^^^^^^^^ -- ^^
+
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:40:9
+ |
+LL | makro,
+ | ^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | use issue_59764::{makro, foo::{
+LL | baz,
+LL |
+LL | foobar,
+LL | }};
+ |
+
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:48:9
+ |
+LL | makro,
+ | ^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | use issue_59764::{makro, foo::{
+LL | baz,
+LL |
+LL | foobar
+LL | }};
+ |
+
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:54:31
+ |
+LL | use issue_59764::{foobaz, foo::makro};
+ | ^^^^^^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | use issue_59764::{makro, foobaz};
+ | ^^^^^^^ --
+
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:59:42
+ |
+LL | use issue_59764::{foobaz, foo::{baz, makro}};
+ | ^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | use issue_59764::{makro, foobaz, foo::{baz}};
+ | ^^^^^^^ --
+
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:68:13
+ |
+LL | makro,
+ | ^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | use issue_59764::{makro,
+LL | foobaz,
+LL | foo::{
+LL | baz,
+LL |
+ |
+
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:78:13
+ |
+LL | makro
+ | ^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | use issue_59764::{makro,
+LL | foobaz,
+LL | foo::{
+LL | baz,
+LL |
+ |
+
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:84:42
+ |
+LL | use issue_59764::{foobaz, foo::{baz, makro, barbaz::{barfoo}}};
+ | ^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | use issue_59764::{makro, foobaz, foo::{baz, barbaz::{barfoo}}};
+ | ^^^^^^^ --
+
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:93:13
+ |
+LL | makro,
+ | ^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | use issue_59764::{makro,
+LL | foobaz,
+LL | foo::{
+LL | baz,
+LL |
+ |
+
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:102:9
+ |
+LL | use issue_59764::foo::makro as baz;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | use issue_59764::makro as baz;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:107:33
+ |
+LL | use issue_59764::foo::{baz, makro as foobar};
+ | ^^^^^^^^^^^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | use issue_59764::{makro as foobar, foo::{baz}};
+ | ^^^^^^^^^^^^^^^^^^^ --^^
+
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:120:17
+ |
+LL | makro as foobar}
+ | ^^^^^^^^^^^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | issue_59764::{makro as foobar,
+LL |
+LL | foobaz,
+LL |
+LL |
+LL | foo::{baz}
+ |
+
+error[E0432]: unresolved import `issue_59764::foo::makro`
+ --> $DIR/issue-59764.rs:127:5
+ |
+LL | use issue_59764::foo::makro;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ no `makro` in `foo`
+ |
+ = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+ |
+LL | use issue_59764::makro;
+ | ^^^^^^^^^^^^^^^^^^
+
+error: cannot determine resolution for the macro `makro`
+ --> $DIR/issue-59764.rs:130:1
+ |
+LL | makro!(bar);
+ | ^^^^^
+ |
+ = note: import resolution is stuck, try simplifying macro imports
+
+error[E0425]: cannot find function `bar` in this scope
+ --> $DIR/issue-59764.rs:134:5
+ |
+LL | bar();
+ | ^^^ not found in this scope
+
+error: aborting due to 18 previous errors
+
+Some errors have detailed explanations: E0425, E0432.
+For more information about an error, try `rustc --explain E0425`.
--- /dev/null
+fn main() {}
+
+trait T {
+ fn qux() -> Option<usize> {
+ let _ = if true {
+ });
+//~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
+//~^^ ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `}`
+//~^^^ ERROR 6:11: 6:12: expected identifier, found `;`
+//~^^^^ ERROR missing `fn`, `type`, or `const` for trait-item declaration
+ Some(4)
+ }
--- /dev/null
+error: expected one of `.`, `;`, `?`, `else`, or an operator, found `}`
+ --> $DIR/issue-60075.rs:6:10
+ |
+LL | });
+ | ^ expected one of `.`, `;`, `?`, `else`, or an operator here
+
+error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
+ --> $DIR/issue-60075.rs:6:11
+ |
+LL | fn qux() -> Option<usize> {
+ | - unclosed delimiter
+LL | let _ = if true {
+LL | });
+ | ^ help: `}` may belong here
+
+error: expected identifier, found `;`
+ --> $DIR/issue-60075.rs:6:11
+ |
+LL | });
+ | ^ expected identifier
+
+error: missing `fn`, `type`, or `const` for trait-item declaration
+ --> $DIR/issue-60075.rs:6:12
+ |
+LL | });
+ | ____________^
+LL | |
+LL | |
+LL | |
+LL | |
+LL | | Some(4)
+ | |________^ missing `fn`, `type`, or `const`
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+// ignore-tidy-linelength
+
+#![deny(warnings)]
+
+struct Borked {}
+
+impl Borked {
+ fn a(&self) {}
+}
+
+fn run_wild<T>(b: &Borked) {
+ b.a::<'_, T>();
+ //~^ ERROR cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+ //~^^ ERROR wrong number of type arguments: expected 0, found 1
+ //~^^^ WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+}
+
+fn main() {}
--- /dev/null
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+ --> $DIR/issue-60622.rs:12:11
+ |
+LL | fn a(&self) {}
+ | - the late bound lifetime parameter is introduced here
+...
+LL | b.a::<'_, T>();
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/issue-60622.rs:3:9
+ |
+LL | #![deny(warnings)]
+ | ^^^^^^^^
+ = note: #[deny(late_bound_lifetime_arguments)] implied by #[deny(warnings)]
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
+
+error[E0107]: wrong number of type arguments: expected 0, found 1
+ --> $DIR/issue-60622.rs:12:15
+ |
+LL | b.a::<'_, T>();
+ | ^ unexpected type argument
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0107`.
--- /dev/null
+struct A {}
+struct B {}
+
+impl From<A> for B {
+ fn from(a: A) -> B {
+ B{}
+ }
+}
+
+fn main() {
+ let c1 = ();
+ c1::<()>;
+ //~^ ERROR type arguments are not allowed for this type
+
+ let c1 = A {};
+ c1::<Into<B>>;
+ //~^ ERROR type arguments are not allowed for this type
+}
--- /dev/null
+error[E0109]: type arguments are not allowed for this type
+ --> $DIR/issue-60989.rs:12:10
+ |
+LL | c1::<()>;
+ | ^^ type argument not allowed
+
+error[E0109]: type arguments are not allowed for this type
+ --> $DIR/issue-60989.rs:16:10
+ |
+LL | c1::<Into<B>>;
+ | ^^^^^^^ type argument not allowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0109`.
--- /dev/null
+fn main() {
+ let mut bad_letters = vec!['e', 't', 'o', 'i'];
+ for l in bad_letters {
+ // something here
+ }
+ bad_letters.push('s'); //~ ERROR borrow of moved value: `bad_letters`
+}
--- /dev/null
+error[E0382]: borrow of moved value: `bad_letters`
+ --> $DIR/issue-61108.rs:6:5
+ |
+LL | let mut bad_letters = vec!['e', 't', 'o', 'i'];
+ | --------------- move occurs because `bad_letters` has type `std::vec::Vec<char>`, which does not implement the `Copy` trait
+LL | for l in bad_letters {
+ | -----------
+ | |
+ | value moved here
+ | help: consider borrowing to avoid moving into the for loop: `&bad_letters`
+...
+LL | bad_letters.push('s');
+ | ^^^^^^^^^^^ value borrowed here after move
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
-#![deny = "foo"] //~ ERROR attribute must be of the form
+#![deny = "foo"] //~ ERROR malformed `deny` attribute input
#![allow(bar = "baz")] //~ ERROR malformed lint attribute
fn main() { }
-error[E0452]: malformed lint attribute
+error[E0452]: malformed lint attribute input
--> $DIR/lint-malformed.rs:2:10
|
LL | #![allow(bar = "baz")]
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^ bad attribute argument
-error: attribute must be of the form `#[deny(lint1, lint2, ..., /*opt*/ reason = "...")]`
+error: malformed `deny` attribute input
--> $DIR/lint-malformed.rs:1:1
|
LL | #![deny = "foo"]
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[deny(lint1, lint2, ..., /*opt*/ reason = "...")]`
error: aborting due to 2 previous errors
#![warn(absolute_paths_not_starting_with_crate, reason = 0)]
//~^ ERROR malformed lint attribute
-//~| HELP reason must be a string literal
+//~| NOTE reason must be a string literal
#![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
//~^ ERROR malformed lint attribute
-//~| HELP reason must be a string literal
+//~| NOTE reason must be a string literal
#![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
//~^ ERROR malformed lint attribute
+//~| NOTE bad attribute argument
#![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
//~^ ERROR malformed lint attribute
+//~| NOTE bad attribute argument
#![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
//~^ ERROR malformed lint attribute
+//~| NOTE bad attribute argument
#![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
//~^ ERROR malformed lint attribute
-//~| HELP reason in lint attribute must come last
+//~| NOTE reason in lint attribute must come last
#![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
//~^ ERROR malformed lint attribute
-//~| HELP reason in lint attribute must come last
+//~| NOTE reason in lint attribute must come last
#![warn(missing_copy_implementations, reason)]
//~^ WARN unknown lint
+//~| NOTE #[warn(unknown_lints)] on by default
fn main() {}
-error[E0452]: malformed lint attribute
+error[E0452]: malformed lint attribute input
--> $DIR/reasons-erroneous.rs:3:58
|
LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
- | ^
- |
- = help: reason must be a string literal
+ | ^ reason must be a string literal
-error[E0452]: malformed lint attribute
+error[E0452]: malformed lint attribute input
--> $DIR/reasons-erroneous.rs:6:40
|
LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: reason must be a string literal
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal
-error[E0452]: malformed lint attribute
+error[E0452]: malformed lint attribute input
--> $DIR/reasons-erroneous.rs:9:29
|
LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
-error[E0452]: malformed lint attribute
- --> $DIR/reasons-erroneous.rs:11:23
+error[E0452]: malformed lint attribute input
+ --> $DIR/reasons-erroneous.rs:12:23
|
LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
-error[E0452]: malformed lint attribute
- --> $DIR/reasons-erroneous.rs:13:36
+error[E0452]: malformed lint attribute input
+ --> $DIR/reasons-erroneous.rs:15:36
|
LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
-error[E0452]: malformed lint attribute
- --> $DIR/reasons-erroneous.rs:15:44
+error[E0452]: malformed lint attribute input
+ --> $DIR/reasons-erroneous.rs:18:44
|
LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
- | ^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: reason in lint attribute must come last
+ | ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
-error[E0452]: malformed lint attribute
- --> $DIR/reasons-erroneous.rs:18:25
+error[E0452]: malformed lint attribute input
+ --> $DIR/reasons-erroneous.rs:21:25
|
LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: reason in lint attribute must come last
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
warning: unknown lint: `reason`
- --> $DIR/reasons-erroneous.rs:21:39
+ --> $DIR/reasons-erroneous.rs:24:39
|
LL | #![warn(missing_copy_implementations, reason)]
| ^^^^^^
LL | format!(struct);
| ^^^^^^ expected expression
-error: expected expression, found `<eof>`
- --> $DIR/format-parse-errors.rs:4:23
+error: expected expression, found end of macro arguments
+ --> $DIR/format-parse-errors.rs:4:24
|
LL | format!("s", name =);
- | ^ expected expression
+ | ^ expected expression
-error: expected `=`, found `<eof>`
- --> $DIR/format-parse-errors.rs:5:29
+error: expected `=`, found end of macro arguments
+ --> $DIR/format-parse-errors.rs:5:32
|
LL | format!("s", foo = foo, bar);
- | ^^^ expected `=`
+ | ^ expected `=`
error: expected expression, found keyword `struct`
--> $DIR/format-parse-errors.rs:6:24
-#[derive(Copy(Bad))]
-//~^ ERROR expected one of `)`, `,`, or `::`, found `(`
+#[derive(Copy(Bad))] //~ ERROR expected one of `)`, `,`, or `::`, found `(`
struct Test1;
-#[derive(Copy="bad")]
-//~^ ERROR expected one of `)`, `,`, or `::`, found `=`
+#[derive(Copy="bad")] //~ ERROR expected one of `)`, `,`, or `::`, found `=`
struct Test2;
-#[derive()]
-//~^ WARNING empty trait list
+#[derive()] //~ WARNING empty trait list
struct Test3;
-#[derive]
-//~^ ERROR attribute must be of the form
+#[derive] //~ ERROR malformed `derive` attribute input
struct Test4;
fn main() {}
| ^ expected one of `)`, `,`, or `::` here
error: expected one of `)`, `,`, or `::`, found `=`
- --> $DIR/malformed-derive-entry.rs:5:14
+ --> $DIR/malformed-derive-entry.rs:4:14
|
LL | #[derive(Copy="bad")]
| ^ expected one of `)`, `,`, or `::` here
warning: empty trait list in `derive`
- --> $DIR/malformed-derive-entry.rs:9:1
+ --> $DIR/malformed-derive-entry.rs:7:1
|
LL | #[derive()]
| ^^^^^^^^^^^
-error: attribute must be of the form `#[derive(Trait1, Trait2, ...)]`
- --> $DIR/malformed-derive-entry.rs:13:1
+error: malformed `derive` attribute input
+ --> $DIR/malformed-derive-entry.rs:10:1
|
LL | #[derive]
- | ^^^^^^^^^
+ | ^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]`
error: aborting due to 3 previous errors
#![feature(plugin)]
-#![plugin] //~ ERROR attribute must be of the form
+#![plugin] //~ ERROR malformed `plugin` attribute
fn main() {}
-error: attribute must be of the form `#[plugin(name|name(args))]`
+error: malformed `plugin` attribute input
--> $DIR/malformed-plugin-1.rs:2:1
|
LL | #![plugin]
- | ^^^^^^^^^^
+ | ^^^^^^^^^^ help: must be of the form: `#[plugin(name|name(args))]`
error: aborting due to previous error
#![feature(plugin)]
-#![plugin="bleh"] //~ ERROR attribute must be of the form
+#![plugin="bleh"] //~ ERROR malformed `plugin` attribute
fn main() {}
-error: attribute must be of the form `#[plugin(name|name(args))]`
+error: malformed `plugin` attribute input
--> $DIR/malformed-plugin-2.rs:2:1
|
LL | #![plugin="bleh"]
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[plugin(name|name(args))]`
error: aborting due to previous error
#![feature(plugin)]
-#![plugin(foo="bleh")] //~ ERROR malformed plugin attribute
+#![plugin(foo="bleh")] //~ ERROR malformed `plugin` attribute
fn main() {}
-error[E0498]: malformed plugin attribute
+error[E0498]: malformed `plugin` attribute
--> $DIR/malformed-plugin-3.rs:2:1
|
LL | #![plugin(foo="bleh")]
- | ^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^ malformed attribute
error: aborting due to previous error
-#[cfg_attr] //~ ERROR expected `(`, found `<eof>`
+#[cfg_attr] //~ ERROR malformed `cfg_attr` attribute
struct S1;
#[cfg_attr = ""] //~ ERROR expected `(`, found `=`
struct S2;
-#[derive] //~ ERROR attribute must be of the form
+#[derive] //~ ERROR malformed `derive` attribute
struct S3;
-#[derive = ""] //~ ERROR attribute must be of the form
+#[derive = ""] //~ ERROR malformed `derive` attribute
struct S4;
fn main() {}
-error: expected `(`, found `<eof>`
+error: malformed `cfg_attr` attribute input
+ --> $DIR/malformed-special-attrs.rs:1:1
+ |
+LL | #[cfg_attr]
+ | ^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ |
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
error: expected `(`, found `=`
--> $DIR/malformed-special-attrs.rs:4:12
|
-LL | #[cfg_attr]
- | - expected `(`
-...
LL | #[cfg_attr = ""]
- | ^ unexpected token
+ | ^ expected `(`
-error: attribute must be of the form `#[derive(Trait1, Trait2, ...)]`
+error: malformed `derive` attribute input
--> $DIR/malformed-special-attrs.rs:7:1
|
LL | #[derive]
- | ^^^^^^^^^
+ | ^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]`
-error: attribute must be of the form `#[derive(Trait1, Trait2, ...)]`
+error: malformed `derive` attribute input
--> $DIR/malformed-special-attrs.rs:10:1
|
LL | #[derive = ""]
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]`
error: aborting due to 4 previous errors
#![feature(unwind_attributes)]
-#[unwind]
-//~^ ERROR attribute must be of the form
+#[unwind] //~ ERROR malformed `unwind` attribute
extern "C" fn f1() {}
-#[unwind = ""]
-//~^ ERROR attribute must be of the form
+#[unwind = ""] //~ ERROR malformed `unwind` attribute
extern "C" fn f2() {}
fn main() {}
-error: attribute must be of the form `#[unwind(allowed|aborts)]`
+error: malformed `unwind` attribute input
--> $DIR/malformed-unwind-1.rs:3:1
|
LL | #[unwind]
- | ^^^^^^^^^
+ | ^^^^^^^^^ help: must be of the form: `#[unwind(allowed|aborts)]`
-error: attribute must be of the form `#[unwind(allowed|aborts)]`
- --> $DIR/malformed-unwind-1.rs:7:1
+error: malformed `unwind` attribute input
+ --> $DIR/malformed-unwind-1.rs:6:1
|
LL | #[unwind = ""]
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ help: must be of the form: `#[unwind(allowed|aborts)]`
error: aborting due to 2 previous errors
#![feature(unwind_attributes)]
#[unwind(allowed, aborts)]
-//~^ ERROR malformed `#[unwind]` attribute
+//~^ ERROR malformed `unwind` attribute
extern "C" fn f1() {}
#[unwind(unsupported)]
-//~^ ERROR malformed `#[unwind]` attribute
+//~^ ERROR malformed `unwind` attribute
extern "C" fn f2() {}
fn main() {}
-error[E0633]: malformed `#[unwind]` attribute
+error[E0633]: malformed `unwind` attribute input
--> $DIR/malformed-unwind-2.rs:3:1
|
LL | #[unwind(allowed, aborts)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid argument
+help: the allowed arguments are `allowed` and `aborts`
+ |
+LL | #[unwind(allowed)]
+ |
+LL | #[unwind(aborts)]
+ |
-error[E0633]: malformed `#[unwind]` attribute
+error[E0633]: malformed `unwind` attribute input
--> $DIR/malformed-unwind-2.rs:7:1
|
LL | #[unwind(unsupported)]
- | ^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^ invalid argument
+help: the allowed arguments are `allowed` and `aborts`
+ |
+LL | #[unwind(allowed)]
+ |
+LL | #[unwind(aborts)]
+ |
error: aborting due to 2 previous errors
#![feature(marker_trait_attr)]
-#[marker(always)]
+#[marker(always)] //~ ERROR malformed `marker` attribute
trait Marker1 {}
-//~^^ ERROR attribute must be of the form
-#[marker("never")]
+#[marker("never")] //~ ERROR malformed `marker` attribute
trait Marker2 {}
-//~^^ ERROR attribute must be of the form
-#[marker(key = "value")]
+#[marker(key = "value")] //~ ERROR malformed `marker` attribute
trait Marker3 {}
-//~^^ ERROR attribute must be of the form `#[marker]`
fn main() {}
-error: attribute must be of the form `#[marker]`
+error: malformed `marker` attribute input
--> $DIR/marker-attribute-with-values.rs:3:1
|
LL | #[marker(always)]
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[marker]`
-error: attribute must be of the form `#[marker]`
- --> $DIR/marker-attribute-with-values.rs:7:1
+error: malformed `marker` attribute input
+ --> $DIR/marker-attribute-with-values.rs:6:1
|
LL | #[marker("never")]
- | ^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[marker]`
-error: attribute must be of the form `#[marker]`
- --> $DIR/marker-attribute-with-values.rs:11:1
+error: malformed `marker` attribute input
+ --> $DIR/marker-attribute-with-values.rs:9:1
|
LL | #[marker(key = "value")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[marker]`
error: aborting due to 3 previous errors
+++ /dev/null
-// Test that we don't show variables with from async fn desugaring
-
-// edition:2018
-#![feature(async_await)]
-
-async fn async_fn(&ref mut s: &[i32]) {}
-//~^ ERROR cannot borrow data in a `&` reference as mutable [E0596]
-
-fn main() {}
+++ /dev/null
-error[E0596]: cannot borrow data in a `&` reference as mutable
- --> $DIR/dont-print-desugared-async.rs:6:20
- |
-LL | async fn async_fn(&ref mut s: &[i32]) {}
- | -^^^^^^^^^
- | ||
- | |cannot borrow as mutable through `&` reference
- | help: consider changing this to be a mutable reference: `&mut ref mut s`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0596`.
+++ /dev/null
-// edition:2018
-
-#![feature(async_await, await_macro)]
-
-fn main() {
- let _ = async |x: u8| {};
- //~^ ERROR `async` non-`move` closures with arguments are not currently supported
-}
+++ /dev/null
-error[E0708]: `async` non-`move` closures with arguments are not currently supported
- --> $DIR/no-args-non-move-async-closure.rs:6:13
- |
-LL | let _ = async |x: u8| {};
- | ^^^^^^^^^^^^^
- |
- = help: consider using `let` statements to manually capture variables by reference before entering an `async move` closure
-
-error: aborting due to previous error
-
// regression test for issue 11256
-#![crate_type] //~ ERROR attribute must be of the form
+#![crate_type] //~ ERROR malformed `crate_type` attribute
fn main() {
return
-error: attribute must be of the form `#[crate_type = "bin|lib|..."]`
+error: malformed `crate_type` attribute input
--> $DIR/no_crate_type.rs:2:1
|
LL | #![crate_type]
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ help: must be of the form: `#[crate_type = "bin|lib|..."]`
error: aborting due to previous error
}
#[rustc_on_unimplemented]
-//~^ ERROR attribute must be of the form
+//~^ ERROR malformed `rustc_on_unimplemented` attribute
trait BadAnnotation1
{}
-error: attribute must be of the form `#[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")]` or `#[rustc_on_unimplemented = "message"]`
+error: malformed `rustc_on_unimplemented` attribute input
--> $DIR/bad-annotation.rs:17:1
|
LL | #[rustc_on_unimplemented]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: the following are the possible correct uses
+ |
+LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")]
+ |
+LL | #[rustc_on_unimplemented = "message"]
+ |
error[E0230]: there is no parameter `C` on trait `BadAnnotation2`
--> $DIR/bad-annotation.rs:22:1
--- /dev/null
+fn main() {
+ let message = "world";
+ println!("Hello, {}", message/); //~ ERROR expected expression
+}
--- /dev/null
+error: expected expression, found end of macro arguments
+ --> $DIR/bad-macro-argument.rs:3:35
+ |
+LL | println!("Hello, {}", message/);
+ | ^ expected expression
+
+error: aborting due to previous error
+
--- /dev/null
+fn foo(x:i32, self: i32) -> i32 { self } //~ ERROR unexpected `self` parameter in function
+
+fn main() {}
--- /dev/null
+error: unexpected `self` parameter in function
+ --> $DIR/self-in-function-arg.rs:1:15
+ |
+LL | fn foo(x:i32, self: i32) -> i32 { self }
+ | ^^^^ not valid as function parameter
+ |
+ = note: `self` is only valid as the first parameter of an associated function
+
+error: aborting due to previous error
+
-thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:1083:5
+thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:1085:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
error: internal compiler error: unexpected panic
match s {
MAGIC_TEST => (),
[0x00, 0x00, 0x00, 0x00] => (),
- [4, 5, 6, 7] => (), //~ ERROR unreachable pattern
+ [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not
_ => (),
}
match s {
[0x00, 0x00, 0x00, 0x00] => (),
MAGIC_TEST => (),
- [4, 5, 6, 7] => (), //~ ERROR unreachable pattern
+ [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not
_ => (),
}
match s {
error: unreachable pattern
- --> $DIR/slice-pattern-const-2.rs:9:9
+ --> $DIR/slice-pattern-const-2.rs:28:9
|
-LL | [4, 5, 6, 7] => (),
- | ^^^^^^^^^^^^
+LL | FOO => (),
+ | ^^^
|
note: lint level defined here
--> $DIR/slice-pattern-const-2.rs:1:9
LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^
-error: unreachable pattern
- --> $DIR/slice-pattern-const-2.rs:15:9
- |
-LL | [4, 5, 6, 7] => (),
- | ^^^^^^^^^^^^
-
-error: unreachable pattern
- --> $DIR/slice-pattern-const-2.rs:28:9
- |
-LL | FOO => (),
- | ^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to previous error
fn main() {
let _ = #[no_output] "Hello, world!";
- //~^ ERROR expected expression, found `<eof>`
+ //~^ ERROR expected expression, found end of macro arguments
let _ = #[duplicate] "Hello, world!";
//~^ ERROR macro expansion ignores token `,` and any following
-error: expected expression, found `<eof>`
+error: expected expression, found end of macro arguments
--> $DIR/attr-invalid-exprs.rs:11:13
|
LL | let _ = #[no_output] "Hello, world!";
extern crate proc_macro;
use proc_macro::*;
-#[proc_macro_derive]
-//~^ ERROR: attribute must be of the form
+#[proc_macro_derive] //~ ERROR malformed `proc_macro_derive` attribute
pub fn foo1(input: TokenStream) -> TokenStream { input }
-#[proc_macro_derive = ""]
-//~^ ERROR: attribute must be of the form
+#[proc_macro_derive = ""] //~ ERROR malformed `proc_macro_derive` attribute
pub fn foo2(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(d3, a, b)]
-//~^ ERROR: attribute must have either one or two arguments
+//~^ ERROR attribute must have either one or two arguments
pub fn foo3(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive(d4, attributes(a), b)]
-//~^ ERROR: attribute must have either one or two arguments
+//~^ ERROR attribute must have either one or two arguments
pub fn foo4(input: TokenStream) -> TokenStream { input }
#[proc_macro_derive("a")]
error: attribute must have either one or two arguments
- --> $DIR/attribute.rs:17:1
+ --> $DIR/attribute.rs:15:1
|
LL | #[proc_macro_derive(d3, a, b)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: attribute must have either one or two arguments
- --> $DIR/attribute.rs:21:1
+ --> $DIR/attribute.rs:19:1
|
LL | #[proc_macro_derive(d4, attributes(a), b)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: not a meta item
- --> $DIR/attribute.rs:25:21
+ --> $DIR/attribute.rs:23:21
|
LL | #[proc_macro_derive("a")]
| ^^^
error: must only be one word
- --> $DIR/attribute.rs:29:21
+ --> $DIR/attribute.rs:27:21
|
LL | #[proc_macro_derive(d6 = "")]
| ^^^^^^^
error: must only be one word
- --> $DIR/attribute.rs:33:21
+ --> $DIR/attribute.rs:31:21
|
LL | #[proc_macro_derive(m::d7)]
| ^^^^^
error: must only be one word
- --> $DIR/attribute.rs:37:21
+ --> $DIR/attribute.rs:35:21
|
LL | #[proc_macro_derive(d8(a))]
| ^^^^^
error: `self` cannot be a name of derive macro
- --> $DIR/attribute.rs:41:21
+ --> $DIR/attribute.rs:39:21
|
LL | #[proc_macro_derive(self)]
| ^^^^
error: cannot override a built-in derive macro
- --> $DIR/attribute.rs:45:21
+ --> $DIR/attribute.rs:43:21
|
LL | #[proc_macro_derive(PartialEq)]
| ^^^^^^^^^
error: second argument must be `attributes`
- --> $DIR/attribute.rs:49:26
+ --> $DIR/attribute.rs:47:26
|
LL | #[proc_macro_derive(d11, a)]
| ^
error: attribute must be of form: `attributes(foo, bar)`
- --> $DIR/attribute.rs:49:26
+ --> $DIR/attribute.rs:47:26
|
LL | #[proc_macro_derive(d11, a)]
| ^
error: attribute must be of form: `attributes(foo, bar)`
- --> $DIR/attribute.rs:54:26
+ --> $DIR/attribute.rs:52:26
|
LL | #[proc_macro_derive(d12, attributes)]
| ^^^^^^^^^^
error: not a meta item
- --> $DIR/attribute.rs:58:37
+ --> $DIR/attribute.rs:56:37
|
LL | #[proc_macro_derive(d13, attributes("a"))]
| ^^^
error: must only be one word
- --> $DIR/attribute.rs:62:37
+ --> $DIR/attribute.rs:60:37
|
LL | #[proc_macro_derive(d14, attributes(a = ""))]
| ^^^^^^
error: must only be one word
- --> $DIR/attribute.rs:66:37
+ --> $DIR/attribute.rs:64:37
|
LL | #[proc_macro_derive(d15, attributes(m::a))]
| ^^^^
error: must only be one word
- --> $DIR/attribute.rs:70:37
+ --> $DIR/attribute.rs:68:37
|
LL | #[proc_macro_derive(d16, attributes(a(b)))]
| ^^^^
error: `self` cannot be a name of derive helper attribute
- --> $DIR/attribute.rs:74:37
+ --> $DIR/attribute.rs:72:37
|
LL | #[proc_macro_derive(d17, attributes(self))]
| ^^^^
-error: attribute must be of the form `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+error: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:9:1
|
LL | #[proc_macro_derive]
- | ^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
-error: attribute must be of the form `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
- --> $DIR/attribute.rs:13:1
+error: malformed `proc_macro_derive` attribute input
+ --> $DIR/attribute.rs:12:1
|
LL | #[proc_macro_derive = ""]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
error: aborting due to 18 previous errors
use proc_macro::TokenStream;
-#[proc_macro = "test"] //~ ERROR attribute must be of the form
+#[proc_macro = "test"] //~ ERROR malformed `proc_macro` attribute
pub fn a(a: TokenStream) -> TokenStream { a }
-#[proc_macro()] //~ ERROR attribute must be of the form
+#[proc_macro()] //~ ERROR malformed `proc_macro` attribute
pub fn c(a: TokenStream) -> TokenStream { a }
-#[proc_macro(x)] //~ ERROR attribute must be of the form
+#[proc_macro(x)] //~ ERROR malformed `proc_macro` attribute
pub fn d(a: TokenStream) -> TokenStream { a }
-#[proc_macro_attribute = "test"] //~ ERROR attribute must be of the form
+#[proc_macro_attribute = "test"] //~ ERROR malformed `proc_macro_attribute` attribute
pub fn e(_: TokenStream, a: TokenStream) -> TokenStream { a }
-#[proc_macro_attribute()] //~ ERROR attribute must be of the form
+#[proc_macro_attribute()] //~ ERROR malformed `proc_macro_attribute` attribute
pub fn g(_: TokenStream, a: TokenStream) -> TokenStream { a }
-#[proc_macro_attribute(x)] //~ ERROR attribute must be of the form
+#[proc_macro_attribute(x)] //~ ERROR malformed `proc_macro_attribute` attribute
pub fn h(_: TokenStream, a: TokenStream) -> TokenStream { a }
-error: attribute must be of the form `#[proc_macro]`
+error: malformed `proc_macro` attribute input
--> $DIR/invalid-attributes.rs:10:1
|
LL | #[proc_macro = "test"]
- | ^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]`
-error: attribute must be of the form `#[proc_macro]`
+error: malformed `proc_macro` attribute input
--> $DIR/invalid-attributes.rs:13:1
|
LL | #[proc_macro()]
- | ^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]`
-error: attribute must be of the form `#[proc_macro]`
+error: malformed `proc_macro` attribute input
--> $DIR/invalid-attributes.rs:16:1
|
LL | #[proc_macro(x)]
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]`
-error: attribute must be of the form `#[proc_macro_attribute]`
+error: malformed `proc_macro_attribute` attribute input
--> $DIR/invalid-attributes.rs:19:1
|
LL | #[proc_macro_attribute = "test"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]`
-error: attribute must be of the form `#[proc_macro_attribute]`
+error: malformed `proc_macro_attribute` attribute input
--> $DIR/invalid-attributes.rs:22:1
|
LL | #[proc_macro_attribute()]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]`
-error: attribute must be of the form `#[proc_macro_attribute]`
+error: malformed `proc_macro_attribute` attribute input
--> $DIR/invalid-attributes.rs:25:1
|
LL | #[proc_macro_attribute(x)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]`
error: aborting due to 6 previous errors
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0284`.
-#[repr]
-//~^ ERROR attribute must be of the form
+#[repr] //~ ERROR malformed `repr` attribute
struct _A {}
-#[repr = "B"]
-//~^ ERROR attribute must be of the form
+#[repr = "B"] //~ ERROR malformed `repr` attribute
struct _B {}
-#[repr = "C"]
-//~^ ERROR attribute must be of the form
+#[repr = "C"] //~ ERROR malformed `repr` attribute
struct _C {}
#[repr(C)]
-error: attribute must be of the form `#[repr(C, packed, ...)]`
+error: malformed `repr` attribute input
--> $DIR/repr.rs:1:1
|
LL | #[repr]
- | ^^^^^^^
+ | ^^^^^^^ help: must be of the form: `#[repr(C, packed, ...)]`
-error: attribute must be of the form `#[repr(C, packed, ...)]`
- --> $DIR/repr.rs:5:1
+error: malformed `repr` attribute input
+ --> $DIR/repr.rs:4:1
|
LL | #[repr = "B"]
- | ^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^ help: must be of the form: `#[repr(C, packed, ...)]`
-error: attribute must be of the form `#[repr(C, packed, ...)]`
- --> $DIR/repr.rs:9:1
+error: malformed `repr` attribute input
+ --> $DIR/repr.rs:7:1
|
LL | #[repr = "C"]
- | ^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^ help: must be of the form: `#[repr(C, packed, ...)]`
error: aborting due to 3 previous errors
#![feature(non_exhaustive)]
#[non_exhaustive(anything)]
-//~^ ERROR attribute must be of the form
+//~^ ERROR malformed `non_exhaustive` attribute
struct Foo;
#[non_exhaustive]
-error: attribute must be of the form `#[non_exhaustive]`
+error: malformed `non_exhaustive` attribute input
--> $DIR/invalid-attribute.rs:3:1
|
LL | #[non_exhaustive(anything)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[non_exhaustive]`
error[E0701]: attribute can only be applied to a struct or enum
--> $DIR/invalid-attribute.rs:7:1
--- /dev/null
+// rust-lang/rust#60654: Do not ICE on an attempt to use GATs that is
+// missing the feature gate.
+
+struct Foo;
+
+impl Iterator for Foo {
+ type Item<'b> = &'b Foo; //~ ERROR generic associated types are unstable [E0658]
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0658]: generic associated types are unstable
+ --> $DIR/gat-dont-ice-on-absent-feature.rs:7:5
+ |
+LL | type Item<'b> = &'b Foo;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/44265
+ = help: add #![feature(generic_associated_types)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
#![stable(feature = "rust1", since = "1.0.0")]
mod bogus_attribute_types_2 {
- #[unstable] //~ ERROR attribute must be of the form
+ #[unstable] //~ ERROR malformed `unstable` attribute
fn f1() { }
- #[unstable = "b"] //~ ERROR attribute must be of the form
+ #[unstable = "b"] //~ ERROR malformed `unstable` attribute
fn f2() { }
- #[stable] //~ ERROR attribute must be of the form
+ #[stable] //~ ERROR malformed `stable` attribute
fn f3() { }
- #[stable = "a"] //~ ERROR attribute must be of the form
+ #[stable = "a"] //~ ERROR malformed `stable` attribute
fn f4() { }
#[stable(feature = "a", since = "b")]
- #[rustc_deprecated] //~ ERROR attribute must be of the form
+ #[rustc_deprecated] //~ ERROR malformed `rustc_deprecated` attribute
fn f5() { }
#[stable(feature = "a", since = "b")]
- #[rustc_deprecated = "a"] //~ ERROR attribute must be of the form
+ #[rustc_deprecated = "a"] //~ ERROR malformed `rustc_deprecated` attribute
fn f6() { }
}
-error: attribute must be of the form `#[unstable(feature = "name", reason = "...", issue = "N")]`
+error: malformed `unstable` attribute input
--> $DIR/stability-attribute-sanity-4.rs:8:5
|
LL | #[unstable]
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^ help: must be of the form: `#[unstable(feature = "name", reason = "...", issue = "N")]`
-error: attribute must be of the form `#[unstable(feature = "name", reason = "...", issue = "N")]`
+error: malformed `unstable` attribute input
--> $DIR/stability-attribute-sanity-4.rs:11:5
|
LL | #[unstable = "b"]
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[unstable(feature = "name", reason = "...", issue = "N")]`
-error: attribute must be of the form `#[stable(feature = "name", since = "version")]`
+error: malformed `stable` attribute input
--> $DIR/stability-attribute-sanity-4.rs:14:5
|
LL | #[stable]
- | ^^^^^^^^^
+ | ^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]`
-error: attribute must be of the form `#[stable(feature = "name", since = "version")]`
+error: malformed `stable` attribute input
--> $DIR/stability-attribute-sanity-4.rs:17:5
|
LL | #[stable = "a"]
- | ^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]`
-error: attribute must be of the form `#[rustc_deprecated(since = "version", reason = "...")]`
+error: malformed `rustc_deprecated` attribute input
--> $DIR/stability-attribute-sanity-4.rs:21:5
|
LL | #[rustc_deprecated]
- | ^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_deprecated(since = "version", reason = "...")]`
-error: attribute must be of the form `#[rustc_deprecated(since = "version", reason = "...")]`
+error: malformed `rustc_deprecated` attribute input
--> $DIR/stability-attribute-sanity-4.rs:25:5
|
LL | #[rustc_deprecated = "a"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_deprecated(since = "version", reason = "...")]`
error: aborting due to 6 previous errors
| - move occurs because `a` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
LL | for i in &a {
LL | for j in a {
- | ^ value moved here, in previous iteration of loop
-help: consider borrowing this to avoid moving it into the for loop
- |
-LL | for j in &a {
- | ^^
+ | ^
+ | |
+ | value moved here, in previous iteration of loop
+ | help: consider borrowing to avoid moving into the for loop: `&a`
error: aborting due to 2 previous errors
--- /dev/null
+//run-rustfix
+
+pub struct LipogramCorpora {
+ selections: Vec<(char, Option<String>)>,
+}
+
+impl LipogramCorpora {
+ pub fn validate_all(&mut self) -> Result<(), char> {
+ for selection in &self.selections {
+ if selection.1.is_some() {
+ if selection.1.as_ref().unwrap().contains(selection.0) {
+ //~^ ERROR cannot move out of borrowed content
+ return Err(selection.0);
+ }
+ }
+ }
+ Ok(())
+ }
+}
+
+pub struct LipogramCorpora2 {
+ selections: Vec<(char, Result<String, String>)>,
+}
+
+impl LipogramCorpora2 {
+ pub fn validate_all(&mut self) -> Result<(), char> {
+ for selection in &self.selections {
+ if selection.1.is_ok() {
+ if selection.1.as_ref().unwrap().contains(selection.0) {
+ //~^ ERROR cannot move out of borrowed content
+ return Err(selection.0);
+ }
+ }
+ }
+ Ok(())
+ }
+}
+
+fn main() {}
--- /dev/null
+//run-rustfix
+
+pub struct LipogramCorpora {
+ selections: Vec<(char, Option<String>)>,
+}
+
+impl LipogramCorpora {
+ pub fn validate_all(&mut self) -> Result<(), char> {
+ for selection in &self.selections {
+ if selection.1.is_some() {
+ if selection.1.unwrap().contains(selection.0) {
+ //~^ ERROR cannot move out of borrowed content
+ return Err(selection.0);
+ }
+ }
+ }
+ Ok(())
+ }
+}
+
+pub struct LipogramCorpora2 {
+ selections: Vec<(char, Result<String, String>)>,
+}
+
+impl LipogramCorpora2 {
+ pub fn validate_all(&mut self) -> Result<(), char> {
+ for selection in &self.selections {
+ if selection.1.is_ok() {
+ if selection.1.unwrap().contains(selection.0) {
+ //~^ ERROR cannot move out of borrowed content
+ return Err(selection.0);
+ }
+ }
+ }
+ Ok(())
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0507]: cannot move out of borrowed content
+ --> $DIR/option-content-move.rs:11:20
+ |
+LL | if selection.1.unwrap().contains(selection.0) {
+ | ^^^^^^^^^^^
+ | |
+ | cannot move out of borrowed content
+ | help: consider borrowing the `Option`'s content: `selection.1.as_ref()`
+
+error[E0507]: cannot move out of borrowed content
+ --> $DIR/option-content-move.rs:29:20
+ |
+LL | if selection.1.unwrap().contains(selection.0) {
+ | ^^^^^^^^^^^
+ | |
+ | cannot move out of borrowed content
+ | help: consider borrowing the `Result`'s content: `selection.1.as_ref()`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
--- /dev/null
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+trait Foo {
+ fn baz();
+}
+
+impl Foo for [u8; 1 + 2] {
+ #[rustc_def_path] //~ ERROR def-path(<[u8; _] as Foo>::baz)
+ fn baz() { }
+}
+
+fn main() {
+}
--- /dev/null
+error: def-path(<[u8; _] as Foo>::baz)
+ --> $DIR/impl2.rs:9:5
+ |
+LL | #[rustc_def_path]
+ | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
#![feature(target_feature)]
#[target_feature = "+sse2"]
-//~^ ERROR: must be of the form
+//~^ ERROR malformed `target_feature` attribute
#[target_feature(enable = "foo")]
-//~^ ERROR: not valid for this target
+//~^ ERROR not valid for this target
+//~| NOTE `foo` is not valid for this target
#[target_feature(bar)]
-//~^ ERROR: only accepts sub-keys
+//~^ ERROR malformed `target_feature` attribute
#[target_feature(disable = "baz")]
-//~^ ERROR: only accepts sub-keys
+//~^ ERROR malformed `target_feature` attribute
unsafe fn foo() {}
#[target_feature(enable = "sse2")]
-//~^ ERROR: can only be applied to `unsafe` function
+//~^ ERROR #[target_feature(..)] can only be applied to `unsafe` functions
+//~| NOTE can only be applied to `unsafe` functions
fn bar() {}
+//~^ NOTE not an `unsafe` function
#[target_feature(enable = "sse2")]
-//~^ ERROR: should be applied to a function
+//~^ ERROR attribute should be applied to a function
mod another {}
+//~^ NOTE not a function
#[inline(always)]
//~^ ERROR: cannot use #[inline(always)]
-error: attribute must be of the form `#[target_feature(enable = "name")]`
+error: malformed `target_feature` attribute input
--> $DIR/target-feature-wrong.rs:16:1
|
LL | #[target_feature = "+sse2"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]`
error: the feature named `foo` is not valid for this target
--> $DIR/target-feature-wrong.rs:18:18
|
LL | #[target_feature(enable = "foo")]
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ `foo` is not valid for this target
-error: #[target_feature(..)] only accepts sub-keys of `enable` currently
- --> $DIR/target-feature-wrong.rs:20:18
+error: malformed `target_feature` attribute input
+ --> $DIR/target-feature-wrong.rs:21:18
|
LL | #[target_feature(bar)]
- | ^^^
+ | ^^^ help: must be of the form: `enable = ".."`
-error: #[target_feature(..)] only accepts sub-keys of `enable` currently
- --> $DIR/target-feature-wrong.rs:22:18
+error: malformed `target_feature` attribute input
+ --> $DIR/target-feature-wrong.rs:23:18
|
LL | #[target_feature(disable = "baz")]
- | ^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."`
-error: #[target_feature(..)] can only be applied to `unsafe` function
- --> $DIR/target-feature-wrong.rs:26:1
+error: #[target_feature(..)] can only be applied to `unsafe` functions
+ --> $DIR/target-feature-wrong.rs:27:1
|
LL | #[target_feature(enable = "sse2")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only be applied to `unsafe` functions
+...
+LL | fn bar() {}
+ | ----------- not an `unsafe` function
error: attribute should be applied to a function
- --> $DIR/target-feature-wrong.rs:30:1
+ --> $DIR/target-feature-wrong.rs:33:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| -------------- not a function
error: cannot use #[inline(always)] with #[target_feature]
- --> $DIR/target-feature-wrong.rs:34:1
+ --> $DIR/target-feature-wrong.rs:38:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
-Subproject commit c4fcfb725b4be00c72eb9cf30c7d8b095577c280
+Subproject commit 545f354259be4e9745ea00a524c0e4c51df01aa6
-Subproject commit a8eeb7cdb135da1cd582c6093c1739732727a4a2
+Subproject commit 46e64911ad43c519c61d22afef7f82625dd9c4a8
"objbase",
"profileapi",
"processenv",
+ "processthreadsapi",
"psapi",
"schannel",
"securitybaseapi",
"adler32", // BSD-3-Clause AND Zlib, cargo dep that isn't used
"fortanix-sgx-abi", // MPL-2.0+, libstd but only for `sgx` target
"constant_time_eq", // CC0-1.0, rustfmt
+ "utf8parse", // Apache-2.0 OR MIT, cargo via strip-ansi-escapes
+ "vte", // Apache-2.0 OR MIT, cargo via strip-ansi-escapes
+ "sized-chunks", // MPL-2.0+, cargo via im-rc
];
/// Which crates to check against the whitelist?
Crate("aho-corasick"),
Crate("arrayvec"),
Crate("atty"),
+ Crate("autocfg"),
Crate("backtrace"),
Crate("backtrace-sys"),
Crate("bitflags"),
}
let toml = dir.path().join("Cargo.toml");
- *bad = *bad || !check_license(&toml);
+ *bad = !check_license(&toml) || *bad;
}
assert!(saw_dir, "no vendored source");
}
"src/libstd/net/test.rs",
"src/libstd/sys_common/mod.rs",
"src/libstd/sys_common/net.rs",
+ "src/libstd/sys_common/backtrace.rs",
"src/libterm", // Not sure how to make this crate portable, but test crate needs it.
"src/libtest", // Probably should defer to unstable `std::sys` APIs.
"src/libstd/sync/mpsc", // some tests are only run on non-emscripten